[clang] c8b37e4 - [clang] extend external_source_symbol attribute with USR clause
Alex Lorenz via cfe-commits
cfe-commits at lists.llvm.org
Thu Feb 23 14:59:38 PST 2023
Author: Alex Lorenz
Date: 2023-02-23T14:59:26-08:00
New Revision: c8b37e48f6f00bb2aa3882ca3cc26082f85ca999
URL: https://github.com/llvm/llvm-project/commit/c8b37e48f6f00bb2aa3882ca3cc26082f85ca999
DIFF: https://github.com/llvm/llvm-project/commit/c8b37e48f6f00bb2aa3882ca3cc26082f85ca999.diff
LOG: [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
Added:
clang/test/Index/Core/external-source-symbol-attr-cxx.cpp
clang/test/Sema/attr-external-source-symbol-cxx.cpp
Modified:
clang/docs/ReleaseNotes.rst
clang/include/clang/Basic/Attr.td
clang/include/clang/Basic/AttrDocs.td
clang/include/clang/Basic/DiagnosticCommonKinds.td
clang/include/clang/Basic/DiagnosticParseKinds.td
clang/include/clang/Parse/Parser.h
clang/lib/Index/USRGeneration.cpp
clang/lib/Parse/ParseDecl.cpp
clang/lib/Parse/Parser.cpp
clang/lib/Sema/SemaDeclAttr.cpp
clang/test/AST/ast-dump-attr.cpp
clang/test/Index/Core/external-source-symbol-attr.m
clang/test/Parser/attr-external-source-symbol.m
clang/test/Sema/attr-external-source-symbol.c
clang/utils/TableGen/ClangAttrEmitter.cpp
Removed:
################################################################################
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 2a636ebb00f79..c7204d8615a90 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -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
-----------------------------------
diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index fc2c7f7e37f45..8858bb6bec850 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -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];
diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td
index eebbf6863dd43..cbf28688a7408 100644
--- a/clang/include/clang/Basic/AttrDocs.td
+++ b/clang/include/clang/Basic/AttrDocs.td
@@ -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.
diff --git a/clang/include/clang/Basic/DiagnosticCommonKinds.td b/clang/include/clang/Basic/DiagnosticCommonKinds.td
index c59adcc72a68b..9b8103c97e39c 100644
--- a/clang/include/clang/Basic/DiagnosticCommonKinds.td
+++ b/clang/include/clang/Basic/DiagnosticCommonKinds.td
@@ -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">;
diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td
index 31519f3c04795..e3849c6658d16 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -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">;
diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h
index 6f9581b9ea1fc..96963fb6aa807 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -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;
diff --git a/clang/lib/Index/USRGeneration.cpp b/clang/lib/Index/USRGeneration.cpp
index 77b05b6bae056..06a3717f9ffaf 100644
--- a/clang/lib/Index/USRGeneration.cpp
+++ b/clang/lib/Index/USRGeneration.cpp
@@ -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();
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 6465d859b1dab..d654cdff847be 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -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);
}
diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp
index 829a187e842b9..e6b1d3fdf70bf 100644
--- a/clang/lib/Parse/Parser.cpp
+++ b/clang/lib/Parse/Parser.cpp
@@ -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;
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index 1a0bfb3d91bcc..5a6e07c81041b 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -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>
diff --git a/clang/test/AST/ast-dump-attr.cpp b/clang/test/AST/ast-dump-attr.cpp
index 25cfa6820b372..15ef878f31573 100644
--- a/clang/test/AST/ast-dump-attr.cpp
+++ b/clang/test/AST/ast-dump-attr.cpp
@@ -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 *)'
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
index 0000000000000..8ccf3c7d69496
--- /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 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 at Module@S at Class@F at 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 |
+}
diff --git a/clang/test/Index/Core/external-source-symbol-attr.m b/clang/test/Index/Core/external-source-symbol-attr.m
index d2cef35ffab23..1f907912737b0 100644
--- 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 @@ void test3(I3 *i3) {
[i3 meth_other_mod];
// CHECK: [[@LINE-1]]:7 | instance-method/Swift | meth_other_mod | c:@CM at other_mod_for_cat@modname at 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
index 752c748be84a7..b94cb3a628145 100644
--- a/clang/test/Parser/attr-external-source-symbol.m
+++ b/clang/test/Parser/attr-external-source-symbol.m
@@ -14,10 +14,14 @@ CaseA __attribute__((external_source_symbol(generated_declaration))),
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
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
index 0000000000000..af5da4909b399
--- /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 T>
+class Class {
+public:
+ [[clang::external_source_symbol(language="Swift", defined_in="module", USR="test", generated_declaration)]]
+ void testExternalSourceSymbol();
+
+ // expected-error at +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() {
+}
diff --git a/clang/test/Sema/attr-external-source-symbol.c b/clang/test/Sema/attr-external-source-symbol.c
index f6d0e0649f035..7301b83ebfdeb 100644
--- a/clang/test/Sema/attr-external-source-symbol.c
+++ b/clang/test/Sema/attr-external-source-symbol.c
@@ -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);
diff --git a/clang/utils/TableGen/ClangAttrEmitter.cpp b/clang/utils/TableGen/ClangAttrEmitter.cpp
index de608c780f981..063b104984725 100644
--- a/clang/utils/TableGen/ClangAttrEmitter.cpp
+++ b/clang/utils/TableGen/ClangAttrEmitter.cpp
@@ -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 @@ class FlattenedSpelling {
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
+ //
diff erent 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())))
More information about the cfe-commits
mailing list