diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -127,6 +127,11 @@ - ``__declspec`` attributes can now be used together with the using keyword. Before the attributes on ``__declspec`` was ignored, while now it will be forwarded to the point where the alias is used. +- Introduced a new ``USR`` (unified symbol resolution) clause inside of the +existing ``__attribute__((external_source_symbol))`` attribute. Clang's indexer +uses the optional USR value when indexing Clang's AST. This value is expected +to be generated by an external compiler when generating C++ bindings during +the compilation of the foreign language sources (e.g. Swift). Improvements to Clang's diagnostics ----------------------------------- diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -287,23 +287,22 @@ } // This handles one spelling of an attribute. -class Spelling { +class Spelling { string Name = name; string Variety = variety; + int Version = version; } class GNU : Spelling; class Declspec : Spelling; class Microsoft : Spelling; class CXX11 - : Spelling { + : Spelling { string Namespace = namespace; - int Version = version; } class C2x - : Spelling { + : Spelling { string Namespace = namespace; - int Version = version; } class Keyword : Spelling; @@ -321,7 +320,8 @@ // The Clang spelling implies GNU, CXX11<"clang", name>, and optionally, // C2x<"clang", name>. This spelling should be used for any Clang-specific // attributes. -class Clang : Spelling { +class Clang + : Spelling { bit AllowInC = allowInC; } @@ -958,10 +958,12 @@ } def ExternalSourceSymbol : InheritableAttr { - let Spellings = [Clang<"external_source_symbol">]; + let Spellings = [Clang<"external_source_symbol", /*allowInC=*/1, + /*version=*/20230206>]; let Args = [StringArgument<"language", 1>, StringArgument<"definedIn", 1>, - BoolArgument<"generatedDeclaration", 1>]; + BoolArgument<"generatedDeclaration", 1>, + StringArgument<"USR", 1>]; let HasCustomParsing = 1; let Subjects = SubjectList<[Named]>; let Documentation = [ExternalSourceSymbolDocs]; diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -1750,6 +1750,19 @@ source containers are modules, so ``defined_in`` should specify the Swift module name. +USR=\ *string-literal* + String that specifies a unified symbol resolution (USR) value for this + declaration. USR string uniquely identifies this particular declaration, and + is typically used when constructing an index of a codebase. + The USR value in this attribute is expected to be generated by an external + compiler that compiled the native declaration using its original source + language. The exact format of the USR string and its other attributes + are determined by the specification of this declaration's source language. + When not specified, Clang's indexer will use the Clang USR for this symbol. + User can query to see if Clang supports the use of the ``USR`` clause in + the ``external_source_symbol`` attribute with + ``__has_attribute(external_source_symbol) >= 20230206``. + generated_declaration This declaration was automatically generated by some tool. diff --git a/clang/include/clang/Basic/DiagnosticCommonKinds.td b/clang/include/clang/Basic/DiagnosticCommonKinds.td --- a/clang/include/clang/Basic/DiagnosticCommonKinds.td +++ b/clang/include/clang/Basic/DiagnosticCommonKinds.td @@ -55,7 +55,7 @@ def err_expected_string_literal : Error<"expected string literal " "%select{in %1|for diagnostic message in static_assert|" "for optional message in 'availability' attribute|" - "for %select{language|source container}1 name in " + "for %select{language name|source container name|USR}1 in " "'external_source_symbol' attribute}0">; def err_invalid_string_udl : Error< "string literal with user-defined suffix cannot be used here">; diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -1104,7 +1104,7 @@ // External source symbol attribute def err_external_source_symbol_expected_keyword : Error< - "expected 'language', 'defined_in', or 'generated_declaration'">; + "expected 'language', 'defined_in', 'generated_declaration', or 'USR'">; def err_external_source_symbol_duplicate_clause : Error< "duplicate %0 clause in an 'external_source_symbol' attribute">; diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -157,7 +157,7 @@ /// Identifiers used by the 'external_source_symbol' attribute. IdentifierInfo *Ident_language, *Ident_defined_in, - *Ident_generated_declaration; + *Ident_generated_declaration, *Ident_USR; /// C++11 contextual keywords. mutable IdentifierInfo *Ident_final; diff --git a/clang/lib/Index/USRGeneration.cpp b/clang/lib/Index/USRGeneration.cpp --- a/clang/lib/Index/USRGeneration.cpp +++ b/clang/lib/Index/USRGeneration.cpp @@ -1141,6 +1141,15 @@ // C++'s operator new function, can have invalid locations but it is fine to // create USRs that can identify them. + // Check if the declaration has explicit external USR specified. + auto *CD = D->getCanonicalDecl(); + if (auto *ExternalSymAttr = CD->getAttr()) { + if (!ExternalSymAttr->getUSR().empty()) { + llvm::raw_svector_ostream Out(Buf); + Out << ExternalSymAttr->getUSR(); + return false; + } + } USRGenerator UG(&D->getASTContext(), Buf); UG.Visit(D); return UG.ignoreResults(); diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -1340,6 +1340,7 @@ /// keyword-arg: /// 'language' '=' /// 'defined_in' '=' +/// 'USR' '=' /// 'generated_declaration' void Parser::ParseExternalSourceSymbolAttribute( IdentifierInfo &ExternalSourceSymbol, SourceLocation Loc, @@ -1355,6 +1356,7 @@ Ident_language = PP.getIdentifierInfo("language"); Ident_defined_in = PP.getIdentifierInfo("defined_in"); Ident_generated_declaration = PP.getIdentifierInfo("generated_declaration"); + Ident_USR = PP.getIdentifierInfo("USR"); } ExprResult Language; @@ -1362,6 +1364,8 @@ ExprResult DefinedInExpr; bool HasDefinedIn = false; IdentifierLoc *GeneratedDeclaration = nullptr; + ExprResult USR; + bool HasUSR = false; // Parse the language/defined_in/generated_declaration keywords do { @@ -1383,7 +1387,8 @@ continue; } - if (Keyword != Ident_language && Keyword != Ident_defined_in) { + if (Keyword != Ident_language && Keyword != Ident_defined_in && + Keyword != Ident_USR) { Diag(Tok, diag::err_external_source_symbol_expected_keyword); SkipUntil(tok::r_paren, StopAtSemi); return; @@ -1396,16 +1401,22 @@ return; } - bool HadLanguage = HasLanguage, HadDefinedIn = HasDefinedIn; + bool HadLanguage = HasLanguage, HadDefinedIn = HasDefinedIn, + HadUSR = HasUSR; if (Keyword == Ident_language) HasLanguage = true; + else if (Keyword == Ident_USR) + HasUSR = true; else HasDefinedIn = true; if (Tok.isNot(tok::string_literal)) { Diag(Tok, diag::err_expected_string_literal) << /*Source='external_source_symbol attribute'*/ 3 - << /*language | source container*/ (Keyword != Ident_language); + << /*language | source container | USR*/ ( + Keyword == Ident_language + ? 0 + : (Keyword == Ident_defined_in ? 1 : 2)); SkipUntil(tok::comma, tok::r_paren, StopAtSemi | StopBeforeMatch); continue; } @@ -1417,6 +1428,14 @@ continue; } Language = ParseStringLiteralExpression(); + } else if (Keyword == Ident_USR) { + if (HadUSR) { + Diag(KeywordLoc, diag::err_external_source_symbol_duplicate_clause) + << Keyword; + ParseStringLiteralExpression(); + continue; + } + USR = ParseStringLiteralExpression(); } else { assert(Keyword == Ident_defined_in && "Invalid clause keyword!"); if (HadDefinedIn) { @@ -1435,8 +1454,8 @@ if (EndLoc) *EndLoc = T.getCloseLocation(); - ArgsUnion Args[] = {Language.get(), DefinedInExpr.get(), - GeneratedDeclaration}; + ArgsUnion Args[] = {Language.get(), DefinedInExpr.get(), GeneratedDeclaration, + USR.get()}; Attrs.addNew(&ExternalSourceSymbol, SourceRange(Loc, T.getCloseLocation()), ScopeName, ScopeLoc, Args, std::size(Args), Syntax); } diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -523,7 +523,8 @@ Ident_strict = nullptr; Ident_replacement = nullptr; - Ident_language = Ident_defined_in = Ident_generated_declaration = nullptr; + Ident_language = Ident_defined_in = Ident_generated_declaration = Ident_USR = + nullptr; Ident__except = nullptr; diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -2834,7 +2834,7 @@ static void handleExternalSourceSymbolAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - if (!AL.checkAtLeastNumArgs(S, 1) || !AL.checkAtMostNumArgs(S, 3)) + if (!AL.checkAtLeastNumArgs(S, 1) || !AL.checkAtMostNumArgs(S, 4)) return; StringRef Language; @@ -2844,9 +2844,12 @@ if (const auto *SE = dyn_cast_or_null(AL.getArgAsExpr(1))) DefinedIn = SE->getString(); bool IsGeneratedDeclaration = AL.getArgAsIdent(2) != nullptr; + StringRef USR; + if (const auto *SE = dyn_cast_or_null(AL.getArgAsExpr(3))) + USR = SE->getString(); D->addAttr(::new (S.Context) ExternalSourceSymbolAttr( - S.Context, AL, Language, DefinedIn, IsGeneratedDeclaration)); + S.Context, AL, Language, DefinedIn, IsGeneratedDeclaration, USR)); } template diff --git a/clang/test/AST/ast-dump-attr.cpp b/clang/test/AST/ast-dump-attr.cpp --- a/clang/test/AST/ast-dump-attr.cpp +++ b/clang/test/AST/ast-dump-attr.cpp @@ -175,7 +175,7 @@ void TestExternalSourceSymbolAttr2() __attribute__((external_source_symbol(defined_in="module", language="Swift"))); // CHECK: FunctionDecl{{.*}} TestExternalSourceSymbolAttr2 -// CHECK-NEXT: ExternalSourceSymbolAttr{{.*}} "Swift" "module"{{$}} +// CHECK-NEXT: ExternalSourceSymbolAttr{{.*}} "Swift" "module" ""{{$}} void TestExternalSourceSymbolAttr3() __attribute__((external_source_symbol(generated_declaration, language="Objective-C++", defined_in="module"))); @@ -192,6 +192,11 @@ // CHECK: FunctionDecl{{.*}} TestExternalSourceSymbolAttr5 // CHECK-NEXT: ExternalSourceSymbolAttr{{.*}} "Swift" "module" GeneratedDeclaration +void TestExternalSourceSymbolAttr6() +__attribute__((external_source_symbol(generated_declaration, defined_in="module", language="Swift", USR="testUSR"))); +// CHECK: FunctionDecl{{.*}} TestExternalSourceSymbolAttr6 +// CHECK-NEXT: ExternalSourceSymbolAttr{{.*}} "Swift" "module" GeneratedDeclaration "testUSR" + namespace TestNoEscape { void noescapeFunc(int *p0, __attribute__((noescape)) int *p1) {} // CHECK: `-FunctionDecl{{.*}} noescapeFunc 'void (int *, __attribute__((noescape)) int *)' diff --git a/clang/test/Index/Core/external-source-symbol-attr-cxx.cpp b/clang/test/Index/Core/external-source-symbol-attr-cxx.cpp new file mode 100644 --- /dev/null +++ b/clang/test/Index/Core/external-source-symbol-attr-cxx.cpp @@ -0,0 +1,35 @@ +// RUN: c-index-test core -print-source-symbols -- %s -target x86_64-apple-macosx10.7 | FileCheck %s + +#define GEN_DECL_USR(mod_name, usr) __attribute__((external_source_symbol(language="Swift", defined_in=mod_name, USR=usr, generated_declaration))) + +class GEN_DECL_USR("Module", "s:Class") Class { +public: + void method() GEN_DECL_USR("Module", "s:Class_method"); + void method2() GEN_DECL_USR("Module", ""); + + static void staticMethod() GEN_DECL_USR("Module", "s:Class_staticMethod"); +}; + +template +class GEN_DECL_USR("Module", "s:TemplateClass") TemplateClass { +public: + void method() GEN_DECL_USR("Module", "s:TemplateClass_method"); +}; + +void test() { + Class c = Class(); + // CHECK: [[@LINE-1]]:3 | class/Swift | Class | s:Class | + // CHECK: [[@LINE-2]]:13 | class/Swift | Class | s:Class | + c.method(); + // CHECK: [[@LINE-1]]:5 | instance-method/Swift | method | s:Class_method | + c.method2(); + // CHECK: [[@LINE-1]]:5 | instance-method/Swift | method2 | c:@M@Module@S@Class@F@method2# | + Class::staticMethod(); + // CHECK: [[@LINE-1]]:10 | static-method/Swift | staticMethod | s:Class_staticMethod | + // CHECK: [[@LINE-2]]:3 | class/Swift | Class | s:Class | + TemplateClass c2 = TemplateClass(); + // CHECK: [[@LINE-1]]:3 | class(Gen)/Swift | TemplateClass | s:TemplateClass | + // CHECK: [[@LINE-2]]:27 | class(Gen)/Swift | TemplateClass | s:TemplateClass | + c2.method(); + // CHECK: [[@LINE-1]]:6 | instance-method/Swift | method | s:TemplateClass_method | +} diff --git a/clang/test/Index/Core/external-source-symbol-attr.m b/clang/test/Index/Core/external-source-symbol-attr.m --- a/clang/test/Index/Core/external-source-symbol-attr.m +++ b/clang/test/Index/Core/external-source-symbol-attr.m @@ -4,6 +4,8 @@ #define GEN_DECL(mod_name) __attribute__((external_source_symbol(language="Swift", defined_in=mod_name, generated_declaration))) #define PUSH_GEN_DECL(mod_name) push(GEN_DECL(mod_name), apply_to=any(enum, objc_interface, objc_category, objc_protocol)) +#define GEN_DECL_USR(mod_name, usr) __attribute__((external_source_symbol(language="Swift", defined_in=mod_name, USR=usr, generated_declaration))) + // Forward declarations should not affect module namespacing below @class I1; @class I2; @@ -110,3 +112,10 @@ [i3 meth_other_mod]; // CHECK: [[@LINE-1]]:7 | instance-method/Swift | meth_other_mod | c:@CM@other_mod_for_cat@modname@objc(cs)I3(im)meth_other_mod | } + +void function() GEN_DECL_USR("SwiftMod", "s:8SwiftMod8functionyyF"); + +void test4() { + function(); + // CHECK: [[@LINE-1]]:3 | function/Swift | function | s:8SwiftMod8functionyyF +} diff --git a/clang/test/Parser/attr-external-source-symbol.m b/clang/test/Parser/attr-external-source-symbol.m --- a/clang/test/Parser/attr-external-source-symbol.m +++ b/clang/test/Parser/attr-external-source-symbol.m @@ -14,10 +14,14 @@ CaseB __attribute__((external_source_symbol(generated_declaration, language="Swift"))) } __attribute__((external_source_symbol(language = "Swift"))); +void functionCustomUSR(void) __attribute__((external_source_symbol(language="Swift", defined_in="module", generated_declaration, USR="s:6module17functionCustomUSRyyF"))); + +void functionCustomUSR2(void) __attribute__((external_source_symbol(language="Swift", defined_in="module", USR="s:6module18functionCustomUSR2yyF", generated_declaration))); + void f2(void) -__attribute__((external_source_symbol())); // expected-error {{expected 'language', 'defined_in', or 'generated_declaration'}} +__attribute__((external_source_symbol())); // expected-error {{expected 'language', 'defined_in', 'generated_declaration', or 'USR'}} void f3(void) -__attribute__((external_source_symbol(invalid))); // expected-error {{expected 'language', 'defined_in', or 'generated_declaration'}} +__attribute__((external_source_symbol(invalid))); // expected-error {{expected 'language', 'defined_in', 'generated_declaration', or 'USR'}} void f4(void) __attribute__((external_source_symbol(language))); // expected-error {{expected '=' after language}} void f5(void) @@ -31,6 +35,8 @@ __attribute__((external_source_symbol(language="Swift", language="Swift"))); // expected-error {{duplicate 'language' clause in an 'external_source_symbol' attribute}} void f9(void) __attribute__((external_source_symbol(defined_in="module", language="Swift", defined_in="foo"))); // expected-error {{duplicate 'defined_in' clause in an 'external_source_symbol' attribute}} +__attribute__((external_source_symbol(defined_in="module", language="Swift", USR="foo", USR="bar"))); // expected-error {{duplicate 'USR' clause in an 'external_source_symbol' attribute}} +void f9_1(void); void f10(void) __attribute__((external_source_symbol(generated_declaration, language="Swift", defined_in="foo", generated_declaration, generated_declaration, language="Swift"))); // expected-error {{duplicate 'generated_declaration' clause in an 'external_source_symbol' attribute}} @@ -45,16 +51,16 @@ __attribute__((external_source_symbol(language=Swift))); // expected-error {{expected string literal for language name in 'external_source_symbol' attribute}} void f14(void) -__attribute__((external_source_symbol(=))); // expected-error {{expected 'language', 'defined_in', or 'generated_declaration'}} +__attribute__((external_source_symbol(=))); // expected-error {{expected 'language', 'defined_in', 'generated_declaration', or 'USR'}} void f15(void) -__attribute__((external_source_symbol(="Swift"))); // expected-error {{expected 'language', 'defined_in', or 'generated_declaration'}} +__attribute__((external_source_symbol(="Swift"))); // expected-error {{expected 'language', 'defined_in', 'generated_declaration', or 'USR'}} void f16(void) -__attribute__((external_source_symbol("Swift", "module", generated_declaration))); // expected-error {{expected 'language', 'defined_in', or 'generated_declaration'}} +__attribute__((external_source_symbol("Swift", "module", generated_declaration))); // expected-error {{expected 'language', 'defined_in', 'generated_declaration', or 'USR'}} void f17(void) -__attribute__((external_source_symbol(language="Swift", "generated_declaration"))); // expected-error {{expected 'language', 'defined_in', or 'generated_declaration'}} +__attribute__((external_source_symbol(language="Swift", "generated_declaration"))); // expected-error {{expected 'language', 'defined_in', 'generated_declaration', or 'USR'}} void f18(void) __attribute__((external_source_symbol(language= =))); // expected-error {{expected string literal for language name in 'external_source_symbol' attribute}} @@ -81,4 +87,14 @@ __attribute__((external_source_symbol(defined_in=123, defined_in="module"))); // expected-error {{expected string literal for source container name in 'external_source_symbol'}} expected-error {{duplicate 'defined_in' clause in an 'external_source_symbol' attribute}} void f26(void) -__attribute__((external_source_symbol(language=Swift, language="Swift", error))); // expected-error {{expected string literal for language name in 'external_source_symbol'}} expected-error {{duplicate 'language' clause in an 'external_source_symbol' attribute}} expected-error {{expected 'language', 'defined_in', or 'generated_declaration'}} +__attribute__((external_source_symbol(language=Swift, language="Swift", error))); // expected-error {{expected string literal for language name in 'external_source_symbol'}} expected-error {{duplicate 'language' clause in an 'external_source_symbol' attribute}} expected-error {{expected 'language', 'defined_in', 'generated_declaration', or 'USR'}} + +void f27(void) +__attribute__((external_source_symbol(USR=f27))); // expected-error {{expected string literal for USR in 'external_source_symbol' attribute}} + +void f28(void) +__attribute__((external_source_symbol(USR=""))); + +#if __has_attribute(external_source_symbol) != 20230206 +# error "invalid __has_attribute version" +#endif diff --git a/clang/test/Sema/attr-external-source-symbol-cxx.cpp b/clang/test/Sema/attr-external-source-symbol-cxx.cpp new file mode 100644 --- /dev/null +++ b/clang/test/Sema/attr-external-source-symbol-cxx.cpp @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 -fsyntax-only -fblocks -verify -fdouble-square-bracket-attributes %s + +template +class Class { +public: + [[clang::external_source_symbol(language="Swift", defined_in="module", USR="test", generated_declaration)]] + void testExternalSourceSymbol(); + + // expected-error@+1 {{expected string literal for USR in 'external_source_symbol' attribute}} + [[clang::external_source_symbol(language="Swift", defined_in="module", USR=T, generated_declaration)]] + void testExternalSourceSymbol2(); +}; + +template +void Class::testExternalSourceSymbol() { +} diff --git a/clang/test/Sema/attr-external-source-symbol.c b/clang/test/Sema/attr-external-source-symbol.c --- a/clang/test/Sema/attr-external-source-symbol.c +++ b/clang/test/Sema/attr-external-source-symbol.c @@ -4,7 +4,9 @@ void twoClauses(void) __attribute__((external_source_symbol(language="Swift", defined_in="module"))); -void fourClauses(void) __attribute__((external_source_symbol(language="Swift", defined_in="module", generated_declaration, generated_declaration))); // expected-error {{duplicate 'generated_declaration' clause in an 'external_source_symbol' attribute}} +void fourClauses(void) __attribute__((external_source_symbol(language="Swift", defined_in="module", generated_declaration, USR="test"))); + +void fiveClauses(void) __attribute__((external_source_symbol(language="Swift", defined_in="module", generated_declaration, generated_declaration, USR="test"))); // expected-error {{duplicate 'generated_declaration' clause in an 'external_source_symbol' attribute}} void oneClause(void) __attribute__((external_source_symbol(generated_declaration))); @@ -22,8 +24,8 @@ [[clang::external_source_symbol(language="Swift", defined_in="module")]] void twoClauses2(void); -[[clang::external_source_symbol(language="Swift", defined_in="module", generated_declaration, generated_declaration)]] // expected-error {{duplicate 'generated_declaration' clause in an 'external_source_symbol' attribute}} -void fourClauses2(void); +[[clang::external_source_symbol(language="Swift", defined_in="module", USR="test", generated_declaration, generated_declaration)]] // expected-error {{duplicate 'generated_declaration' clause in an 'external_source_symbol' attribute}} +void fiveClauses2(void); [[clang::external_source_symbol(generated_declaration)]] void oneClause2(void); diff --git a/clang/utils/TableGen/ClangAttrEmitter.cpp b/clang/utils/TableGen/ClangAttrEmitter.cpp --- a/clang/utils/TableGen/ClangAttrEmitter.cpp +++ b/clang/utils/TableGen/ClangAttrEmitter.cpp @@ -51,14 +51,18 @@ class FlattenedSpelling { std::string V, N, NS; bool K = false; + const Record &OriginalSpelling; public: FlattenedSpelling(const std::string &Variety, const std::string &Name, - const std::string &Namespace, bool KnownToGCC) : - V(Variety), N(Name), NS(Namespace), K(KnownToGCC) {} + const std::string &Namespace, bool KnownToGCC, + const Record &OriginalSpelling) + : V(Variety), N(Name), NS(Namespace), K(KnownToGCC), + OriginalSpelling(OriginalSpelling) {} explicit FlattenedSpelling(const Record &Spelling) : V(std::string(Spelling.getValueAsString("Variety"))), - N(std::string(Spelling.getValueAsString("Name"))) { + N(std::string(Spelling.getValueAsString("Name"))), + OriginalSpelling(Spelling) { assert(V != "GCC" && V != "Clang" && "Given a GCC spelling, which means this hasn't been flattened!"); if (V == "CXX11" || V == "C2x" || V == "Pragma") @@ -69,6 +73,7 @@ const std::string &name() const { return N; } const std::string &nameSpace() const { return NS; } bool knownToGCC() const { return K; } + const Record &getSpellingRecord() const { return OriginalSpelling; } }; } // end anonymous namespace @@ -82,15 +87,15 @@ StringRef Variety = Spelling->getValueAsString("Variety"); StringRef Name = Spelling->getValueAsString("Name"); if (Variety == "GCC") { - Ret.emplace_back("GNU", std::string(Name), "", true); - Ret.emplace_back("CXX11", std::string(Name), "gnu", true); + Ret.emplace_back("GNU", std::string(Name), "", true, *Spelling); + Ret.emplace_back("CXX11", std::string(Name), "gnu", true, *Spelling); if (Spelling->getValueAsBit("AllowInC")) - Ret.emplace_back("C2x", std::string(Name), "gnu", true); + Ret.emplace_back("C2x", std::string(Name), "gnu", true, *Spelling); } else if (Variety == "Clang") { - Ret.emplace_back("GNU", std::string(Name), "", false); - Ret.emplace_back("CXX11", std::string(Name), "clang", false); + Ret.emplace_back("GNU", std::string(Name), "", false, *Spelling); + Ret.emplace_back("CXX11", std::string(Name), "clang", false, *Spelling); if (Spelling->getValueAsBit("AllowInC")) - Ret.emplace_back("C2x", std::string(Name), "clang", false); + Ret.emplace_back("C2x", std::string(Name), "clang", false, *Spelling); } else Ret.push_back(FlattenedSpelling(*Spelling)); } @@ -3309,18 +3314,31 @@ // C2x-style attributes have the same kind of version information // associated with them. The unscoped attribute version information should // be taken from the specification of the attribute in the C Standard. + // + // Clang-specific attributes have the same kind of version information + // associated with them. This version is typically the default value (1). + // These version values are clang-specific and should typically be + // incremented once the attribute changes its syntax and/or semantics in a + // a way that is impactful to the end user. int Version = 1; - if (Variety == "CXX11" || Variety == "C2x") { - std::vector Spellings = Attr->getValueAsListOfDefs("Spellings"); - for (const auto &Spelling : Spellings) { - if (Spelling->getValueAsString("Variety") == Variety) { - Version = static_cast(Spelling->getValueAsInt("Version")); - if (Scope.empty() && Version == 1) - PrintError(Spelling->getLoc(), "Standard attributes must have " - "valid version information."); - break; - } + std::vector Spellings = GetFlattenedSpellings(*Attr); + for (const auto &Spelling : Spellings) { + if (Spelling.variety() == Variety && + (Spelling.nameSpace().empty() || Scope == Spelling.nameSpace())) { + Version = static_cast( + Spelling.getSpellingRecord().getValueAsInt("Version")); + // Verify that explicitly specified CXX11 and C2x spellings (i.e. + // not inferred from Clang/GCC spellings) have a version that's + // different than the default (1). + bool RequiresValidVersion = + (Variety == "CXX11" || Variety == "C2x") && + Spelling.getSpellingRecord().getValueAsString("Variety") == Variety; + if (RequiresValidVersion && Scope.empty() && Version == 1) + PrintError(Spelling.getSpellingRecord().getLoc(), + "Standard attributes must have " + "valid version information."); + break; } } @@ -3342,9 +3360,9 @@ else if (Variety == "C2x") Test = "LangOpts.DoubleSquareBracketAttributes"; - std::string TestStr = - !Test.empty() ? Test + " ? " + llvm::itostr(Version) + " : 0" : "1"; - std::vector Spellings = GetFlattenedSpellings(*Attr); + std::string TestStr = !Test.empty() + ? Test + " ? " + llvm::itostr(Version) + " : 0" + : llvm::itostr(Version); for (const auto &S : Spellings) if (Variety.empty() || (Variety == S.variety() && (Scope.empty() || Scope == S.nameSpace())))