[clang] extend external_source_symbol attribute with USR clause

Allow the user to specify a concrete USR in the external_source_symbol attribute.
That will let Clang's indexer to use Swift USRs for Swift declarations that are
represented with C++ declarations.

This new clause is used by Swift when generating a C++ header representation
of a Swift module:
https://github.com/apple/swift/pull/63002

Differential Revision: https://reviews.llvm.org/D141324
This commit is contained in:
Alex Lorenz
2023-02-23 14:14:14 -08:00
parent 5a4f193afa
commit c8b37e48f6
17 changed files with 205 additions and 52 deletions

View File

@@ -127,6 +127,11 @@ Attribute Changes in Clang
- ``__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
-----------------------------------

View File

@@ -287,23 +287,22 @@ class VariadicEnumArgument<string name, string type, list<string> values,
}
// This handles one spelling of an attribute.
class Spelling<string name, string variety> {
class Spelling<string name, string variety, int version = 1> {
string Name = name;
string Variety = variety;
int Version = version;
}
class GNU<string name> : Spelling<name, "GNU">;
class Declspec<string name> : Spelling<name, "Declspec">;
class Microsoft<string name> : Spelling<name, "Microsoft">;
class CXX11<string namespace, string name, int version = 1>
: Spelling<name, "CXX11"> {
: Spelling<name, "CXX11", version> {
string Namespace = namespace;
int Version = version;
}
class C2x<string namespace, string name, int version = 1>
: Spelling<name, "C2x"> {
: Spelling<name, "C2x", version> {
string Namespace = namespace;
int Version = version;
}
class Keyword<string name> : Spelling<name, "Keyword">;
@@ -321,7 +320,8 @@ class GCC<string name, bit allowInC = 1> : Spelling<name, "GCC"> {
// The Clang spelling implies GNU<name>, CXX11<"clang", name>, and optionally,
// C2x<"clang", name>. This spelling should be used for any Clang-specific
// attributes.
class Clang<string name, bit allowInC = 1> : Spelling<name, "Clang"> {
class Clang<string name, bit allowInC = 1, int version = 1>
: Spelling<name, "Clang", version> {
bit AllowInC = allowInC;
}
@@ -958,10 +958,12 @@ static llvm::StringRef canonicalizePlatformName(llvm::StringRef Platform) {
}
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];

View File

@@ -1750,6 +1750,19 @@ defined_in=\ *string-literal*
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.

View File

@@ -55,7 +55,7 @@ def err_expected_colon_after_setter_name : Error<
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">;

View File

@@ -1104,7 +1104,7 @@ def err_availability_query_repeated_star : Error<
// 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">;

View File

@@ -157,7 +157,7 @@ class Parser : public CodeCompletionHandler {
/// 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;

View File

@@ -1141,6 +1141,15 @@ bool clang::index::generateUSRForDecl(const Decl *D,
// 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<ExternalSourceSymbolAttr>()) {
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();

View File

@@ -1340,6 +1340,7 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability,
/// keyword-arg:
/// 'language' '=' <string>
/// 'defined_in' '=' <string>
/// 'USR' '=' <string>
/// 'generated_declaration'
void Parser::ParseExternalSourceSymbolAttribute(
IdentifierInfo &ExternalSourceSymbol, SourceLocation Loc,
@@ -1355,6 +1356,7 @@ void Parser::ParseExternalSourceSymbolAttribute(
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 @@ void Parser::ParseExternalSourceSymbolAttribute(
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 @@ void Parser::ParseExternalSourceSymbolAttribute(
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 @@ void Parser::ParseExternalSourceSymbolAttribute(
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 @@ void Parser::ParseExternalSourceSymbolAttribute(
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 @@ void Parser::ParseExternalSourceSymbolAttribute(
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);
}

View File

@@ -523,7 +523,8 @@ void Parser::Initialize() {
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;

View File

@@ -2834,7 +2834,7 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
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 @@ static void handleExternalSourceSymbolAttr(Sema &S, Decl *D,
if (const auto *SE = dyn_cast_or_null<StringLiteral>(AL.getArgAsExpr(1)))
DefinedIn = SE->getString();
bool IsGeneratedDeclaration = AL.getArgAsIdent(2) != nullptr;
StringRef USR;
if (const auto *SE = dyn_cast_or_null<StringLiteral>(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 <class T>

View File

@@ -175,7 +175,7 @@ __attribute__((external_source_symbol(language="Swift", defined_in="module", gen
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 @@ __attribute__((external_source_symbol(generated_declaration, defined_in="module"
// 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 *)'

View File

@@ -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 T>
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<int> c2 = TemplateClass<int>();
// 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 |
}

View File

@@ -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 @@ void test3(I3 *i3) {
[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
}

View File

@@ -14,10 +14,14 @@ enum E {
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 @@ void f8(void)
__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 @@ void f13(void)
__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 @@ void f25(void)
__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

View File

@@ -0,0 +1,16 @@
// RUN: %clang_cc1 -fsyntax-only -fblocks -verify -fdouble-square-bracket-attributes %s
template<class T>
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<class T>
void Class<T>::testExternalSourceSymbol() {
}

View File

@@ -4,7 +4,9 @@ void threeClauses(void) __attribute__((external_source_symbol(language="Swift",
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 @@ void namedDeclsOnly(void) {
[[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);

View File

@@ -51,14 +51,18 @@ namespace {
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 @@ public:
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 @@ GetFlattenedSpellings(const Record &Attr) {
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 @@ static void GenerateHasAttrSpellingStringSwitch(
// 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<Record *> Spellings = Attr->getValueAsListOfDefs("Spellings");
for (const auto &Spelling : Spellings) {
if (Spelling->getValueAsString("Variety") == Variety) {
Version = static_cast<int>(Spelling->getValueAsInt("Version"));
if (Scope.empty() && Version == 1)
PrintError(Spelling->getLoc(), "Standard attributes must have "
"valid version information.");
break;
}
std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(*Attr);
for (const auto &Spelling : Spellings) {
if (Spelling.variety() == Variety &&
(Spelling.nameSpace().empty() || Scope == Spelling.nameSpace())) {
Version = static_cast<int>(
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 @@ static void GenerateHasAttrSpellingStringSwitch(
else if (Variety == "C2x")
Test = "LangOpts.DoubleSquareBracketAttributes";
std::string TestStr =
!Test.empty() ? Test + " ? " + llvm::itostr(Version) + " : 0" : "1";
std::vector<FlattenedSpelling> 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())))