mirror of
https://github.com/intel/llvm.git
synced 2026-01-15 12:25:46 +08:00
[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:
@@ -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
|
||||
-----------------------------------
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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">;
|
||||
|
||||
@@ -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">;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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 *)'
|
||||
|
||||
35
clang/test/Index/Core/external-source-symbol-attr-cxx.cpp
Normal file
35
clang/test/Index/Core/external-source-symbol-attr-cxx.cpp
Normal 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 |
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
16
clang/test/Sema/attr-external-source-symbol-cxx.cpp
Normal file
16
clang/test/Sema/attr-external-source-symbol-cxx.cpp
Normal 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() {
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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())))
|
||||
|
||||
Reference in New Issue
Block a user