Skip to content

Commit 77d21e7

Browse files
authored
[APINotes] Upstream dependencies of Sema logic to apply API Notes to decls
This upstreams more of the Clang API Notes functionality that is currently implemented in the Apple fork: https://github.com/apple/llvm-project/tree/next/clang/lib/APINotes This is the largest chunk of the API Notes functionality in the upstreaming process. I will soon submit a follow-up patch to actually enable usage of this functionality by having a Clang driver flag that enables API Notes, along with tests.
1 parent 9791e54 commit 77d21e7

File tree

13 files changed

+348
-91
lines changed

13 files changed

+348
-91
lines changed

clang/include/clang/Basic/Attr.td

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,9 @@ class VariadicEnumArgument<string name, string type, list<string> values,
306306
bit IsExternalType = isExternalType;
307307
}
308308

309+
// Represents an attribute wrapped by another attribute.
310+
class WrappedAttr<string name, bit opt = 0> : Argument<name, opt>;
311+
309312
// This handles one spelling of an attribute.
310313
class Spelling<string name, string variety, int version = 1> {
311314
string Name = name;
@@ -2291,7 +2294,7 @@ def ObjCBridgeRelated : InheritableAttr {
22912294
def NSErrorDomain : InheritableAttr {
22922295
let Spellings = [GNU<"ns_error_domain">];
22932296
let Subjects = SubjectList<[Enum], ErrorDiag>;
2294-
let Args = [DeclArgument<Var, "ErrorDomain">];
2297+
let Args = [IdentifierArgument<"ErrorDomain">];
22952298
let Documentation = [NSErrorDomainDocs];
22962299
}
22972300

@@ -2648,6 +2651,22 @@ def SwiftError : InheritableAttr {
26482651
let Documentation = [SwiftErrorDocs];
26492652
}
26502653

2654+
def SwiftImportAsNonGeneric : InheritableAttr {
2655+
// This attribute has no spellings as it is only ever created implicitly
2656+
// from API notes.
2657+
let Spellings = [];
2658+
let SemaHandler = 0;
2659+
let Documentation = [InternalOnly];
2660+
}
2661+
2662+
def SwiftImportPropertyAsAccessors : InheritableAttr {
2663+
// This attribute has no spellings as it is only ever created implicitly
2664+
// from API notes.
2665+
let Spellings = [];
2666+
let SemaHandler = 0;
2667+
let Documentation = [InternalOnly];
2668+
}
2669+
26512670
def SwiftName : InheritableAttr {
26522671
let Spellings = [GNU<"swift_name">];
26532672
let Args = [StringArgument<"Name">];
@@ -2669,6 +2688,31 @@ def SwiftPrivate : InheritableAttr {
26692688
let SimpleHandler = 1;
26702689
}
26712690

2691+
def SwiftVersionedAddition : Attr {
2692+
// This attribute has no spellings as it is only ever created implicitly
2693+
// from API notes.
2694+
let Spellings = [];
2695+
let Args = [VersionArgument<"Version">, WrappedAttr<"AdditionalAttr">,
2696+
BoolArgument<"IsReplacedByActive">];
2697+
let SemaHandler = 0;
2698+
let Documentation = [InternalOnly];
2699+
}
2700+
2701+
def SwiftVersionedRemoval : Attr {
2702+
// This attribute has no spellings as it is only ever created implicitly
2703+
// from API notes.
2704+
let Spellings = [];
2705+
let Args = [VersionArgument<"Version">, UnsignedArgument<"RawKind">,
2706+
BoolArgument<"IsReplacedByActive">];
2707+
let SemaHandler = 0;
2708+
let Documentation = [InternalOnly];
2709+
let AdditionalMembers = [{
2710+
attr::Kind getAttrKindToRemove() const {
2711+
return static_cast<attr::Kind>(getRawKind());
2712+
}
2713+
}];
2714+
}
2715+
26722716
def NoDeref : TypeAttr {
26732717
let Spellings = [Clang<"noderef">];
26742718
let Documentation = [NoDerefDocs];

clang/include/clang/Basic/DiagnosticParseKinds.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1617,6 +1617,9 @@ def err_pragma_invalid_keyword : Error<
16171617
def err_pragma_pipeline_invalid_keyword : Error<
16181618
"invalid argument; expected 'disable'">;
16191619

1620+
// API notes.
1621+
def err_type_unparsed : Error<"unparsed tokens following type">;
1622+
16201623
// Pragma unroll support.
16211624
def warn_pragma_unroll_cuda_value_in_parens : Warning<
16221625
"argument to '#pragma unroll' should not be in parentheses in CUDA C/C++">,

clang/include/clang/Lex/Lexer.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,11 +198,11 @@ class Lexer : public PreprocessorLexer {
198198
/// from. Currently this is only used by _Pragma handling.
199199
SourceLocation getFileLoc() const { return FileLoc; }
200200

201-
private:
202201
/// Lex - Return the next token in the file. If this is the end of file, it
203202
/// return the tok::eof token. This implicitly involves the preprocessor.
204203
bool Lex(Token &Result);
205204

205+
private:
206206
/// Called when the preprocessor is in 'dependency scanning lexing mode'.
207207
bool LexDependencyDirectiveToken(Token &Result);
208208

clang/include/clang/Parse/Parser.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3656,6 +3656,18 @@ class Parser : public CodeCompletionHandler {
36563656
ParseConceptDefinition(const ParsedTemplateInfo &TemplateInfo,
36573657
SourceLocation &DeclEnd);
36583658

3659+
/// Parse the given string as a type.
3660+
///
3661+
/// This is a dangerous utility function currently employed only by API notes.
3662+
/// It is not a general entry-point for safely parsing types from strings.
3663+
///
3664+
/// \param TypeStr The string to be parsed as a type.
3665+
/// \param Context The name of the context in which this string is being
3666+
/// parsed, which will be used in diagnostics.
3667+
/// \param IncludeLoc The location at which this parse was triggered.
3668+
TypeResult ParseTypeFromString(StringRef TypeStr, StringRef Context,
3669+
SourceLocation IncludeLoc);
3670+
36593671
//===--------------------------------------------------------------------===//
36603672
// Modules
36613673
DeclGroupPtrTy ParseModuleDecl(Sema::ModuleImportState &ImportState);

clang/include/clang/Sema/Sema.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -955,6 +955,10 @@ class Sema final {
955955
OpaqueParser = P;
956956
}
957957

958+
/// Callback to the parser to parse a type expressed as a string.
959+
std::function<TypeResult(StringRef, StringRef, SourceLocation)>
960+
ParseTypeFromStringCallback;
961+
958962
class DelayedDiagnostics;
959963

960964
class DelayedDiagnosticsState {
@@ -3017,6 +3021,9 @@ class Sema final {
30173021
ParmVarDecl *BuildParmVarDeclForTypedef(DeclContext *DC,
30183022
SourceLocation Loc,
30193023
QualType T);
3024+
QualType AdjustParameterTypeForObjCAutoRefCount(QualType T,
3025+
SourceLocation NameLoc,
3026+
TypeSourceInfo *TSInfo);
30203027
ParmVarDecl *CheckParameter(DeclContext *DC, SourceLocation StartLoc,
30213028
SourceLocation NameLoc, IdentifierInfo *Name,
30223029
QualType T, TypeSourceInfo *TSInfo,
@@ -4816,6 +4823,29 @@ class Sema final {
48164823
/// Valid types should not have multiple attributes with different CCs.
48174824
const AttributedType *getCallingConvAttributedType(QualType T) const;
48184825

4826+
/// Check whether a nullability type specifier can be added to the given
4827+
/// type through some means not written in source (e.g. API notes).
4828+
///
4829+
/// \param Type The type to which the nullability specifier will be
4830+
/// added. On success, this type will be updated appropriately.
4831+
///
4832+
/// \param Nullability The nullability specifier to add.
4833+
///
4834+
/// \param DiagLoc The location to use for diagnostics.
4835+
///
4836+
/// \param AllowArrayTypes Whether to accept nullability specifiers on an
4837+
/// array type (e.g., because it will decay to a pointer).
4838+
///
4839+
/// \param OverrideExisting Whether to override an existing, locally-specified
4840+
/// nullability specifier rather than complaining about the conflict.
4841+
///
4842+
/// \returns true if nullability cannot be applied, false otherwise.
4843+
bool CheckImplicitNullabilityTypeSpecifier(QualType &Type,
4844+
NullabilityKind Nullability,
4845+
SourceLocation DiagLoc,
4846+
bool AllowArrayTypes,
4847+
bool OverrideExisting);
4848+
48194849
/// Process the attributes before creating an attributed statement. Returns
48204850
/// the semantic attributes that have been processed.
48214851
void ProcessStmtAttributes(Stmt *Stmt, const ParsedAttributes &InAttrs,

clang/lib/Parse/ParseDecl.cpp

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8051,6 +8051,71 @@ bool Parser::TryAltiVecTokenOutOfLine(DeclSpec &DS, SourceLocation Loc,
80518051
return false;
80528052
}
80538053

8054+
TypeResult Parser::ParseTypeFromString(StringRef TypeStr, StringRef Context,
8055+
SourceLocation IncludeLoc) {
8056+
// Consume (unexpanded) tokens up to the end-of-directive.
8057+
SmallVector<Token, 4> Tokens;
8058+
{
8059+
// Create a new buffer from which we will parse the type.
8060+
auto &SourceMgr = PP.getSourceManager();
8061+
FileID FID = SourceMgr.createFileID(
8062+
llvm::MemoryBuffer::getMemBufferCopy(TypeStr, Context), SrcMgr::C_User,
8063+
0, 0, IncludeLoc);
8064+
8065+
// Form a new lexer that references the buffer.
8066+
Lexer L(FID, SourceMgr.getBufferOrFake(FID), PP);
8067+
L.setParsingPreprocessorDirective(true);
8068+
8069+
// Lex the tokens from that buffer.
8070+
Token Tok;
8071+
do {
8072+
L.Lex(Tok);
8073+
Tokens.push_back(Tok);
8074+
} while (Tok.isNot(tok::eod));
8075+
}
8076+
8077+
// Replace the "eod" token with an "eof" token identifying the end of
8078+
// the provided string.
8079+
Token &EndToken = Tokens.back();
8080+
EndToken.startToken();
8081+
EndToken.setKind(tok::eof);
8082+
EndToken.setLocation(Tok.getLocation());
8083+
EndToken.setEofData(TypeStr.data());
8084+
8085+
// Add the current token back.
8086+
Tokens.push_back(Tok);
8087+
8088+
// Enter the tokens into the token stream.
8089+
PP.EnterTokenStream(Tokens, /*DisableMacroExpansion=*/false,
8090+
/*IsReinject=*/false);
8091+
8092+
// Consume the current token so that we'll start parsing the tokens we
8093+
// added to the stream.
8094+
ConsumeAnyToken();
8095+
8096+
// Enter a new scope.
8097+
ParseScope LocalScope(this, 0);
8098+
8099+
// Parse the type.
8100+
TypeResult Result = ParseTypeName(nullptr);
8101+
8102+
// Check if we parsed the whole thing.
8103+
if (Result.isUsable() &&
8104+
(Tok.isNot(tok::eof) || Tok.getEofData() != TypeStr.data())) {
8105+
Diag(Tok.getLocation(), diag::err_type_unparsed);
8106+
}
8107+
8108+
// There could be leftover tokens (e.g. because of an error).
8109+
// Skip through until we reach the 'end of directive' token.
8110+
while (Tok.isNot(tok::eof))
8111+
ConsumeAnyToken();
8112+
8113+
// Consume the end token.
8114+
if (Tok.is(tok::eof) && Tok.getEofData() == TypeStr.data())
8115+
ConsumeAnyToken();
8116+
return Result;
8117+
}
8118+
80548119
void Parser::DiagnoseBitIntUse(const Token &Tok) {
80558120
// If the token is for _ExtInt, diagnose it as being deprecated. Otherwise,
80568121
// the token is about _BitInt and gets (potentially) diagnosed as use of an

clang/lib/Parse/Parser.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,11 @@ Parser::Parser(Preprocessor &pp, Sema &actions, bool skipFunctionBodies)
7070
PP.addCommentHandler(CommentSemaHandler.get());
7171

7272
PP.setCodeCompletionHandler(*this);
73+
74+
Actions.ParseTypeFromStringCallback =
75+
[this](StringRef TypeStr, StringRef Context, SourceLocation IncludeLoc) {
76+
return this->ParseTypeFromString(TypeStr, Context, IncludeLoc);
77+
};
7378
}
7479

7580
DiagnosticBuilder Parser::Diag(SourceLocation Loc, unsigned DiagID) {

clang/lib/Sema/SemaDecl.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15205,6 +15205,37 @@ void Sema::DiagnoseSizeOfParametersAndReturnValue(
1520515205
}
1520615206
}
1520715207

15208+
QualType Sema::AdjustParameterTypeForObjCAutoRefCount(QualType T,
15209+
SourceLocation NameLoc,
15210+
TypeSourceInfo *TSInfo) {
15211+
// In ARC, infer a lifetime qualifier for appropriate parameter types.
15212+
if (!getLangOpts().ObjCAutoRefCount ||
15213+
T.getObjCLifetime() != Qualifiers::OCL_None || !T->isObjCLifetimeType())
15214+
return T;
15215+
15216+
Qualifiers::ObjCLifetime Lifetime;
15217+
15218+
// Special cases for arrays:
15219+
// - if it's const, use __unsafe_unretained
15220+
// - otherwise, it's an error
15221+
if (T->isArrayType()) {
15222+
if (!T.isConstQualified()) {
15223+
if (DelayedDiagnostics.shouldDelayDiagnostics())
15224+
DelayedDiagnostics.add(sema::DelayedDiagnostic::makeForbiddenType(
15225+
NameLoc, diag::err_arc_array_param_no_ownership, T, false));
15226+
else
15227+
Diag(NameLoc, diag::err_arc_array_param_no_ownership)
15228+
<< TSInfo->getTypeLoc().getSourceRange();
15229+
}
15230+
Lifetime = Qualifiers::OCL_ExplicitNone;
15231+
} else {
15232+
Lifetime = T->getObjCARCImplicitLifetime();
15233+
}
15234+
T = Context.getLifetimeQualifiedType(T, Lifetime);
15235+
15236+
return T;
15237+
}
15238+
1520815239
ParmVarDecl *Sema::CheckParameter(DeclContext *DC, SourceLocation StartLoc,
1520915240
SourceLocation NameLoc, IdentifierInfo *Name,
1521015241
QualType T, TypeSourceInfo *TSInfo,

clang/lib/Sema/SemaDeclAttr.cpp

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6236,29 +6236,35 @@ static void handleObjCRequiresSuperAttr(Sema &S, Decl *D,
62366236
D->addAttr(::new (S.Context) ObjCRequiresSuperAttr(S.Context, Attrs));
62376237
}
62386238

6239-
static void handleNSErrorDomain(Sema &S, Decl *D, const ParsedAttr &AL) {
6240-
auto *E = AL.getArgAsExpr(0);
6241-
auto Loc = E ? E->getBeginLoc() : AL.getLoc();
6242-
6243-
auto *DRE = dyn_cast<DeclRefExpr>(AL.getArgAsExpr(0));
6244-
if (!DRE) {
6245-
S.Diag(Loc, diag::err_nserrordomain_invalid_decl) << 0;
6239+
static void handleNSErrorDomain(Sema &S, Decl *D, const ParsedAttr &Attr) {
6240+
if (!isa<TagDecl>(D)) {
6241+
S.Diag(D->getBeginLoc(), diag::err_nserrordomain_invalid_decl) << 0;
62466242
return;
62476243
}
62486244

6249-
auto *VD = dyn_cast<VarDecl>(DRE->getDecl());
6250-
if (!VD) {
6251-
S.Diag(Loc, diag::err_nserrordomain_invalid_decl) << 1 << DRE->getDecl();
6245+
IdentifierLoc *IdentLoc =
6246+
Attr.isArgIdent(0) ? Attr.getArgAsIdent(0) : nullptr;
6247+
if (!IdentLoc || !IdentLoc->Ident) {
6248+
// Try to locate the argument directly.
6249+
SourceLocation Loc = Attr.getLoc();
6250+
if (Attr.isArgExpr(0) && Attr.getArgAsExpr(0))
6251+
Loc = Attr.getArgAsExpr(0)->getBeginLoc();
6252+
6253+
S.Diag(Loc, diag::err_nserrordomain_invalid_decl) << 0;
62526254
return;
62536255
}
62546256

6255-
if (!isNSStringType(VD->getType(), S.Context) &&
6256-
!isCFStringType(VD->getType(), S.Context)) {
6257-
S.Diag(Loc, diag::err_nserrordomain_wrong_type) << VD;
6257+
// Verify that the identifier is a valid decl in the C decl namespace.
6258+
LookupResult Result(S, DeclarationName(IdentLoc->Ident), SourceLocation(),
6259+
Sema::LookupNameKind::LookupOrdinaryName);
6260+
if (!S.LookupName(Result, S.TUScope) || !Result.getAsSingle<VarDecl>()) {
6261+
S.Diag(IdentLoc->Loc, diag::err_nserrordomain_invalid_decl)
6262+
<< 1 << IdentLoc->Ident;
62586263
return;
62596264
}
62606265

6261-
D->addAttr(::new (S.Context) NSErrorDomainAttr(S.Context, AL, VD));
6266+
D->addAttr(::new (S.Context)
6267+
NSErrorDomainAttr(S.Context, Attr, IdentLoc->Ident));
62626268
}
62636269

62646270
static void handleObjCBridgeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {

0 commit comments

Comments
 (0)