-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[clang] Fix compile-time regression from attribute arg checking change #101768
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
In 2acf77f code was added to use the 'full' name including syntax and scope. Instead of building up a large string for each name, add syntax and scope checks to the value expression in tablegen. There is already code to generate expressions for target specific attributes. This change refactors and adds to that code to include syntax and scope checks. The tablegen avoids generating the complicated expression unless there are two attributes using the same name, otherwise the case values will be as simple as before. Removes the currently unused attributeHasStrictIdentifierArgAtIndex function and the related tablegen.
@llvm/pr-subscribers-clang Author: Mike Rice (mikerice1969) ChangesIn 2acf77f code was added to use the 'full' name including syntax and scope. Instead of building up a large string for each name, add syntax and scope checks to the value expression in tablegen. There is already code to generate expressions for target specific attributes. This change refactors and adds to that code to include syntax and scope checks. The tablegen avoids generating the complicated expression unless there are two attributes using the same name, otherwise the case values will be as simple as before. Removes the currently unused attributeHasStrictIdentifierArgAtIndex function and the related tablegen. Patch is 36.86 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/101768.diff 5 Files Affected:
diff --git a/clang/include/clang/Basic/AttributeCommonInfo.h b/clang/include/clang/Basic/AttributeCommonInfo.h
index cdf9dcaff7508..5f024b4b5fd78 100644
--- a/clang/include/clang/Basic/AttributeCommonInfo.h
+++ b/clang/include/clang/Basic/AttributeCommonInfo.h
@@ -191,12 +191,6 @@ class AttributeCommonInfo {
/// __gnu__::__attr__ will be normalized to gnu::attr).
std::string getNormalizedFullName() const;
- /// Generate a normalized full name, with syntax, scope and name.
- static std::string
- normalizeFullNameWithSyntax(const IdentifierInfo *Name,
- const IdentifierInfo *Scope,
- AttributeCommonInfo::Syntax SyntaxUsed);
-
bool isDeclspecAttribute() const { return SyntaxUsed == AS_Declspec; }
bool isMicrosoftAttribute() const { return SyntaxUsed == AS_Microsoft; }
diff --git a/clang/lib/Basic/Attributes.cpp b/clang/lib/Basic/Attributes.cpp
index a39eb85f7e8fa..867d241a2cf84 100644
--- a/clang/lib/Basic/Attributes.cpp
+++ b/clang/lib/Basic/Attributes.cpp
@@ -153,40 +153,6 @@ std::string AttributeCommonInfo::getNormalizedFullName() const {
normalizeName(getAttrName(), getScopeName(), getSyntax()));
}
-static StringRef getSyntaxName(AttributeCommonInfo::Syntax SyntaxUsed) {
- switch (SyntaxUsed) {
- case AttributeCommonInfo::AS_GNU:
- return "GNU";
- case AttributeCommonInfo::AS_CXX11:
- return "CXX11";
- case AttributeCommonInfo::AS_C23:
- return "C23";
- case AttributeCommonInfo::AS_Declspec:
- return "Declspec";
- case AttributeCommonInfo::AS_Microsoft:
- return "Microsoft";
- case AttributeCommonInfo::AS_Keyword:
- return "Keyword";
- case AttributeCommonInfo::AS_Pragma:
- return "Pragma";
- case AttributeCommonInfo::AS_ContextSensitiveKeyword:
- return "ContextSensitiveKeyword";
- case AttributeCommonInfo::AS_HLSLAnnotation:
- return "HLSLAnnotation";
- case AttributeCommonInfo::AS_Implicit:
- return "Implicit";
- }
- llvm_unreachable("Invalid attribute syntax");
-}
-
-std::string AttributeCommonInfo::normalizeFullNameWithSyntax(
- const IdentifierInfo *Name, const IdentifierInfo *ScopeName,
- Syntax SyntaxUsed) {
- return (Twine(getSyntaxName(SyntaxUsed)) +
- "::" + normalizeName(Name, ScopeName, SyntaxUsed))
- .str();
-}
-
unsigned AttributeCommonInfo::calculateAttributeSpellingListIndex() const {
// Both variables will be used in tablegen generated
// attribute spell list index matching code.
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 4a2d9a650e20c..8fdbfb70e732c 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -314,27 +314,24 @@ void Parser::ParseGNUAttributes(ParsedAttributes &Attrs,
}
/// Determine whether the given attribute has an identifier argument.
-static bool attributeHasIdentifierArg(const IdentifierInfo &II,
+static bool attributeHasIdentifierArg(const llvm::Triple &T,
+ const IdentifierInfo &II,
ParsedAttr::Syntax Syntax,
IdentifierInfo *ScopeName) {
- std::string FullName =
- AttributeCommonInfo::normalizeFullNameWithSyntax(&II, ScopeName, Syntax);
#define CLANG_ATTR_IDENTIFIER_ARG_LIST
- return llvm::StringSwitch<bool>(FullName)
+ return llvm::StringSwitch<bool>(normalizeAttrName(II.getName()))
#include "clang/Parse/AttrParserStringSwitches.inc"
.Default(false);
#undef CLANG_ATTR_IDENTIFIER_ARG_LIST
}
-/// Determine whether the given attribute has an identifier argument.
+/// Determine whether the given attribute has string arguments.
static ParsedAttributeArgumentsProperties
attributeStringLiteralListArg(const llvm::Triple &T, const IdentifierInfo &II,
ParsedAttr::Syntax Syntax,
IdentifierInfo *ScopeName) {
- std::string FullName =
- AttributeCommonInfo::normalizeFullNameWithSyntax(&II, ScopeName, Syntax);
#define CLANG_ATTR_STRING_LITERAL_ARG_LIST
- return llvm::StringSwitch<uint32_t>(FullName)
+ return llvm::StringSwitch<uint32_t>(normalizeAttrName(II.getName()))
#include "clang/Parse/AttrParserStringSwitches.inc"
.Default(0);
#undef CLANG_ATTR_STRING_LITERAL_ARG_LIST
@@ -344,10 +341,8 @@ attributeStringLiteralListArg(const llvm::Triple &T, const IdentifierInfo &II,
static bool attributeHasVariadicIdentifierArg(const IdentifierInfo &II,
ParsedAttr::Syntax Syntax,
IdentifierInfo *ScopeName) {
- std::string FullName =
- AttributeCommonInfo::normalizeFullNameWithSyntax(&II, ScopeName, Syntax);
#define CLANG_ATTR_VARIADIC_IDENTIFIER_ARG_LIST
- return llvm::StringSwitch<bool>(FullName)
+ return llvm::StringSwitch<bool>(normalizeAttrName(II.getName()))
#include "clang/Parse/AttrParserStringSwitches.inc"
.Default(false);
#undef CLANG_ATTR_VARIADIC_IDENTIFIER_ARG_LIST
@@ -357,10 +352,8 @@ static bool attributeHasVariadicIdentifierArg(const IdentifierInfo &II,
static bool attributeTreatsKeywordThisAsIdentifier(const IdentifierInfo &II,
ParsedAttr::Syntax Syntax,
IdentifierInfo *ScopeName) {
- std::string FullName =
- AttributeCommonInfo::normalizeFullNameWithSyntax(&II, ScopeName, Syntax);
#define CLANG_ATTR_THIS_ISA_IDENTIFIER_ARG_LIST
- return llvm::StringSwitch<bool>(FullName)
+ return llvm::StringSwitch<bool>(normalizeAttrName(II.getName()))
#include "clang/Parse/AttrParserStringSwitches.inc"
.Default(false);
#undef CLANG_ATTR_THIS_ISA_IDENTIFIER_ARG_LIST
@@ -370,10 +363,8 @@ static bool attributeTreatsKeywordThisAsIdentifier(const IdentifierInfo &II,
static bool attributeAcceptsExprPack(const IdentifierInfo &II,
ParsedAttr::Syntax Syntax,
IdentifierInfo *ScopeName) {
- std::string FullName =
- AttributeCommonInfo::normalizeFullNameWithSyntax(&II, ScopeName, Syntax);
#define CLANG_ATTR_ACCEPTS_EXPR_PACK
- return llvm::StringSwitch<bool>(FullName)
+ return llvm::StringSwitch<bool>(normalizeAttrName(II.getName()))
#include "clang/Parse/AttrParserStringSwitches.inc"
.Default(false);
#undef CLANG_ATTR_ACCEPTS_EXPR_PACK
@@ -383,42 +374,22 @@ static bool attributeAcceptsExprPack(const IdentifierInfo &II,
static bool attributeIsTypeArgAttr(const IdentifierInfo &II,
ParsedAttr::Syntax Syntax,
IdentifierInfo *ScopeName) {
- std::string FullName =
- AttributeCommonInfo::normalizeFullNameWithSyntax(&II, ScopeName, Syntax);
#define CLANG_ATTR_TYPE_ARG_LIST
- return llvm::StringSwitch<bool>(FullName)
+ return llvm::StringSwitch<bool>(normalizeAttrName(II.getName()))
#include "clang/Parse/AttrParserStringSwitches.inc"
.Default(false);
#undef CLANG_ATTR_TYPE_ARG_LIST
}
-/// Determine whether the given attribute takes identifier arguments.
+/// Determine whether the given attribute takes a strict identifier argument.
static bool attributeHasStrictIdentifierArgs(const IdentifierInfo &II,
ParsedAttr::Syntax Syntax,
IdentifierInfo *ScopeName) {
- std::string FullName =
- AttributeCommonInfo::normalizeFullNameWithSyntax(&II, ScopeName, Syntax);
-#define CLANG_ATTR_STRICT_IDENTIFIER_ARG_AT_INDEX_LIST
- return (llvm::StringSwitch<uint64_t>(FullName)
-#include "clang/Parse/AttrParserStringSwitches.inc"
- .Default(0)) != 0;
-#undef CLANG_ATTR_STRICT_IDENTIFIER_ARG_AT_INDEX_LIST
-}
-
-/// Determine whether the given attribute takes an identifier argument at a
-/// specific index
-static bool attributeHasStrictIdentifierArgAtIndex(const IdentifierInfo &II,
- ParsedAttr::Syntax Syntax,
- IdentifierInfo *ScopeName,
- size_t argIndex) {
- std::string FullName =
- AttributeCommonInfo::normalizeFullNameWithSyntax(&II, ScopeName, Syntax);
-#define CLANG_ATTR_STRICT_IDENTIFIER_ARG_AT_INDEX_LIST
- return (llvm::StringSwitch<uint64_t>(FullName)
+#define CLANG_ATTR_STRICT_IDENTIFIER_ARG_LIST
+ return llvm::StringSwitch<bool>(normalizeAttrName(II.getName()))
#include "clang/Parse/AttrParserStringSwitches.inc"
- .Default(0)) &
- (1ull << argIndex);
-#undef CLANG_ATTR_STRICT_IDENTIFIER_ARG_AT_INDEX_LIST
+ .Default(false);
+#undef CLANG_ATTR_STRICT_IDENTIFIER_ARG_LIST
}
/// Determine whether the given attribute requires parsing its arguments
@@ -426,10 +397,8 @@ static bool attributeHasStrictIdentifierArgAtIndex(const IdentifierInfo &II,
static bool attributeParsedArgsUnevaluated(const IdentifierInfo &II,
ParsedAttr::Syntax Syntax,
IdentifierInfo *ScopeName) {
- std::string FullName =
- AttributeCommonInfo::normalizeFullNameWithSyntax(&II, ScopeName, Syntax);
#define CLANG_ATTR_ARG_CONTEXT_LIST
- return llvm::StringSwitch<bool>(FullName)
+ return llvm::StringSwitch<bool>(normalizeAttrName(II.getName()))
#include "clang/Parse/AttrParserStringSwitches.inc"
.Default(false);
#undef CLANG_ATTR_ARG_CONTEXT_LIST
@@ -575,7 +544,8 @@ unsigned Parser::ParseAttributeArgsCommon(
// If this attribute wants an 'identifier' argument, make it so.
bool IsIdentifierArg =
AttributeHasVariadicIdentifierArg ||
- attributeHasIdentifierArg(*AttrName, Form.getSyntax(), ScopeName);
+ attributeHasIdentifierArg(getTargetInfo().getTriple(), *AttrName,
+ Form.getSyntax(), ScopeName);
ParsedAttr::Kind AttrKind =
ParsedAttr::getParsedKind(AttrName, ScopeName, Form.getSyntax());
@@ -619,13 +589,6 @@ unsigned Parser::ParseAttributeArgsCommon(
if (ChangeKWThisToIdent && Tok.is(tok::kw_this))
Tok.setKind(tok::identifier);
- if (Tok.is(tok::identifier) &&
- attributeHasStrictIdentifierArgAtIndex(
- *AttrName, Form.getSyntax(), ScopeName, ArgExprs.size())) {
- ArgExprs.push_back(ParseIdentifierLoc());
- continue;
- }
-
ExprResult ArgExpr;
if (Tok.is(tok::identifier)) {
ArgExprs.push_back(ParseIdentifierLoc());
diff --git a/clang/test/TableGen/attrs-parser-string-switches.td b/clang/test/TableGen/attrs-parser-string-switches.td
index c15ab104e0ccd..3219916869004 100644
--- a/clang/test/TableGen/attrs-parser-string-switches.td
+++ b/clang/test/TableGen/attrs-parser-string-switches.td
@@ -22,19 +22,15 @@ def TestUnEvalTwo : InheritableAttr {
}
// CHECK: #if defined(CLANG_ATTR_ARG_CONTEXT_LIST)
-// CHECK-NOT: .Case("Pragma::test_uneval", true)
-// CHECK: .Case("GNU::test_uneval", true)
-// CHECK-NOT: .Case("Pragma::test_uneval", true)
-// CHECK: .Case("CXX11::clang::test_uneval", true)
-// CHECK-NOT: .Case("Pragma::test_uneval", true)
-// CHECK: .Case("C23::clang::test_uneval", true)
-// CHECK-NOT: .Case("Pragma::test_uneval", true)
+// CHECK: .Case("test_uneval", (Syntax==AttributeCommonInfo::AS_GNU && !ScopeName) ? 1 :
+// CHECK-SAME: (Syntax==AttributeCommonInfo::AS_CXX11 && ScopeName && ScopeName->getName()=="clang") ? 1 :
+// CHECK-SAME: (Syntax==AttributeCommonInfo::AS_C23 && ScopeName && ScopeName->getName()=="clang") ? 1 : 0)
// CHECK: #endif // CLANG_ATTR_ARG_CONTEXT_LIST
// Test attributeHasIdentifierArg: Same spelling, one with and one without
// an IdentifierArg.
def TestIdentOne : Attr {
- let Spellings = [Clang<"test_ident">];
+ let Spellings = [GNU<"test_ident">];
let Args = [EnumArgument<"Option", "OptionType", /*is_string=*/false,
["optA", "optB"], ["OPTA", "OPTB"]>];
let Subjects = SubjectList<[Function]>;
@@ -48,28 +44,35 @@ def TestIdentTwo : StmtAttr {
let Documentation = [Undocumented];
}
+// Checks that the simple value is produced if only one attribute with a
+// spelling.
+def TestOnlyIdent : Attr {
+ let Spellings = [GNU<"test_only_ident">];
+ let Args = [EnumArgument<"Option", "OptionType", /*is_string=*/false,
+ ["optA", "optB"], ["OPTA", "OPTB"]>];
+ let Subjects = SubjectList<[Function]>;
+ let Documentation = [Undocumented];
+}
+
// CHECK: #if defined(CLANG_ATTR_IDENTIFIER_ARG_LIST)
-// CHECK-NOT: .Case("Pragma::test_ident", true)
-// CHECK: .Case("GNU::test_ident", true)
-// CHECK-NOT: .Case("Pragma::test_ident", true)
-// CHECK: .Case("CXX11::clang::test_ident", true)
-// CHECK-NOT: .Case("Pragma::test_ident", true)
-// CHECK: .Case("C23::clang::test_ident", true)
-// CHECK-NOT: .Case("Pragma::test_ident", true)
+// CHECK: .Case("test_ident", (Syntax==AttributeCommonInfo::AS_GNU && !ScopeName)
+// CHECK: .Case("test_only_ident", true)
+// CHECK: .Case("test_targspec",
+// CHECK-SAME: (T.getArch() == llvm::Triple::arm)) ? 1 : 0
// CHECK: #endif // CLANG_ATTR_IDENTIFIER_ARG_LIST
// Test attributeStringLiteralListArg : Same spelling, some with a
// StringArgument, some without, some in different locations.
def TestStringOne : DeclOrTypeAttr {
let Spellings = [Clang<"test_string">];
- let Args = [StringArgument<"strarg">];
+ let Args = [UnsignedArgument<"unsarg">];
let Subjects = SubjectList<[Function, TypedefName, ParmVar]>;
let Documentation = [AcquireHandleDocs];
}
def TestStringTwo : InheritableAttr {
let Spellings = [Pragma<"", "test_string">];
- let Args = [UnsignedArgument<"unsarg">];
+ let Args = [StringArgument<"strarg">];
let Subjects = SubjectList<[Function], ErrorDiag>;
let Documentation = [Undocumented];
}
@@ -83,39 +86,31 @@ def TestStringThree : Attr {
}
// CHECK: #if defined(CLANG_ATTR_STRING_LITERAL_ARG_LIST)
-// CHECK-NOT: .Case("Pragma::test_string"
-// CHECK: .Case("GNU::test_string", 1)
-// CHECK: .Case("CXX11::clang::test_string", 1)
-// CHECK: .Case("C23::clang::test_string", 1)
-// CHECK-NOT: .Case("Pragma::test_string"
-// CHECK: .Case("Declspec::test_string", 2)
-// CHECK-NOT: .Case("Pragma::test_string"
+// CHECK: .Case("test_string", (Syntax==AttributeCommonInfo::AS_Declspec && !ScopeName) ? 2 :
+// CHECK-SAME: (Syntax==AttributeCommonInfo::AS_Pragma && !ScopeName) ? 1 : 0)
+// CHECK: .Case("test_targspec",
+// CHECK-SAME: (T.getArch() == llvm::Triple::arm)) ? 4294967294 :
+// CHECK-SAME: (T.getArch() == llvm::Triple::ppc)) ? 1 :
// CHECK: #endif // CLANG_ATTR_STRING_LITERAL_ARG_LIST
// Test attributeHasVariadicIdentifierArg : One with VariadicIdentifierArgument
// and one without.
def TestVariadicIdentOne : InheritableAttr {
let Spellings = [Clang<"test_var_ident">];
- let Args = [VariadicIdentifierArgument<"iargs">];
+ let Args = [UnsignedArgument<"Hint">];
let Subjects = SubjectList<[Function], ErrorDiag>;
let Documentation = [Undocumented];
}
def TestVariadicIdentTwo : InheritableAttr {
let Spellings = [Pragma<"", "test_var_ident">];
- let Args = [UnsignedArgument<"Hint">];
+ let Args = [VariadicIdentifierArgument<"iargs">];
let Subjects = SubjectList<[Function], ErrorDiag>;
let Documentation = [Undocumented];
}
// CHECK: #if defined(CLANG_ATTR_VARIADIC_IDENTIFIER_ARG_LIST)
-// CHECK-NOT: .Case("Pragma::"test_var_ident", true)
-// CHECK: .Case("GNU::test_var_ident", true)
-// CHECK-NOT: .Case("Pragma::test_var_ident", true)
-// CHECK: .Case("CXX11::clang::test_var_ident", true)
-// CHECK-NOT: .Case("Pragma::test_var_ident", true)
-// CHECK: .Case("C23::clang::test_var_ident", true)
-// CHECK-NOT: .Case("Pragma::test_var_ident", true)
+// CHECK: .Case("test_var_ident", (Syntax==AttributeCommonInfo::AS_Pragma && !ScopeName))
// CHECK: #endif // CLANG_ATTR_VARIADIC_IDENTIFIER_ARG_LIST
// Test attributeTreatsKeywordThisAsIdentifier : Same spelling, one with and
@@ -135,13 +130,9 @@ def TestVarOrIdxTwo : InheritableAttr {
}
// CHECK: #if defined(CLANG_ATTR_THIS_ISA_IDENTIFIER_ARG_LIST)
-// CHECK-NOT: .Case("Pragma::test_var_idx", true)
-// CHECK: .Case("GNU::test_var_idx", true)
-// CHECK-NOT: .Case("Pragma::test_var_idx", true)
-// CHECK: .Case("CXX11::clang::test_var_idx", true)
-// CHECK-NOT: .Case("Pragma::test_var_idx", true)
-// CHECK: .Case("C23::clang::test_var_idx", true)
-// CHECK-NOT: .Case("Pragma::test_var_idx", true)
+// CHECK: .Case("test_var_idx", (Syntax==AttributeCommonInfo::AS_GNU && !ScopeName) ? 1 :
+// CHECK-SAME: (Syntax==AttributeCommonInfo::AS_CXX11 && ScopeName && ScopeName->getName()=="clang") ? 1 :
+// CHECK-SAME: (Syntax==AttributeCommonInfo::AS_C23 && ScopeName && ScopeName->getName()=="clang") ? 1 : 0)
// CHECK: #endif // CLANG_ATTR_THIS_ISA_IDENTIFIER_ARG_LIST
// Test attributeAcceptsExprPack : One with, one without.
@@ -161,13 +152,9 @@ def TestExprPackTwo : InheritableAttr {
}
// CHECK: #if defined(CLANG_ATTR_ACCEPTS_EXPR_PACK)
-// CHECK-NOT: .Case("Pragma::test_expr_pack", true)
-// CHECK: .Case("GNU::test_expr_pack", true)
-// CHECK-NOT: .Case("Pragma::test_expr_pack", true)
-// CHECK: .Case("CXX11::clang::test_expr_pack", true)
-// CHECK-NOT: .Case("Pragma::test_expr_pack", true)
-// CHECK: .Case("C23::clang::test_expr_pack", true)
-// CHECK-NOT: .Case("Pragma::test_expr_pack", true)
+// CHECK: .Case("test_expr_pack", (Syntax==AttributeCommonInfo::AS_GNU && !ScopeName) ? 1 :
+// CHECK-SAME: (Syntax==AttributeCommonInfo::AS_CXX11 && ScopeName && ScopeName->getName()=="clang") ? 1 :
+// CHECK-SAME: (Syntax==AttributeCommonInfo::AS_C23 && ScopeName && ScopeName->getName()=="clang") ? 1 : 0)
// CHECK: #endif // CLANG_ATTR_ACCEPTS_EXPR_PACK
@@ -188,17 +175,12 @@ def TestTypeTwo : InheritableAttr {
}
// CHECK: #if defined(CLANG_ATTR_TYPE_ARG_LIST)
-// CHECK-NOT: .Case("Pragma::test_type", true)
-// CHECK: .Case("GNU::test_type", true)
-// CHECK-NOT: .Case("Pragma::test_type", true)
-// CHECK: .Case("CXX11::clang::test_type", true)
-// CHECK-NOT: .Case("Pragma::test_type", true)
-// CHECK: .Case("C23::clang::test_type", true)
-// CHECK-NOT: .Case("Pragma::test_type", true)
+// CHECK: .Case("test_type", (Syntax==AttributeCommonInfo::AS_GNU && !ScopeName) ? 1 :
+// CHECK-SAME: (Syntax==AttributeCommonInfo::AS_CXX11 && ScopeName && ScopeName->getName()=="clang") ? 1 :
+// CHECK-SAME: (Syntax==AttributeCommonInfo::AS_C23 && ScopeName && ScopeName->getName()=="clang") ? 1 : 0)
// CHECK: #endif // CLANG_ATTR_TYPE_ARG_LIST
-// Test attributeHasStrictIdentifierArgs and
-// attributeHasStrictIdentifierArgAtIndex, one used StrictEnumParameters, the
+// Test attributeHasStrictIdentifierArgs, one used StrictEnumParameters, the
// other does not.
def TestStrictEnumOne : InheritableAttr {
let Spellings = [Clang<"strict_enum">];
@@ -221,12 +203,32 @@ def TestStrictEnumTwo : InheritableAttr {
let Documentation = [Undocumented];
}
-// CHECK: #if defined(CLANG_ATTR_STRICT_IDENTIFIER_ARG_AT_INDEX_LIST)
-// CHECK-NOT: .Case("Pragma::strict_enum", 5ull)
-// CHECK: .Case("GNU::strict_enum", 5ull)
-// CHECK-NOT: .Case("Pragma::strict_enum", 5ull)
-// CHECK: .Case("CXX11::clang::strict_enum", 5ull)
-// CHECK-NOT: .Case("Pragma::strict_enum", 5ull)
-// CHECK: .Case("C23::clang::strict_enum", 5ull)
-// CHECK-NOT: .Case("Pragma::strict_enum", 5ull)
-// CHECK: #endif // CLANG_ATTR_STRICT_IDENTIFIER_ARG_AT_INDEX_LIST
+// CHECK: #if defined(CLANG_ATTR_STRICT_IDENTIFIER_ARG_LIST)
+// CHECK: .Case("strict_enum", (Syntax==AttributeCommonInfo::AS_GNU && !ScopeName) ? 1 :
+// CHECK-SAME: (Syntax==AttributeCommonInfo::AS_CXX11 && ScopeName && ScopeName->getName()=="clang") ? 1 :
+// CHECK-SAME: (Syntax==AttributeCommonInfo::AS_C23 && ScopeName && ScopeName->getName()=="clang") ? 1 : 0)
+// CHECK: #endif // CLANG_ATTR_STRICT_IDENTIFIER_ARG_LIST
+
+// Test that TargetSpecific attributes work as expected.
+
+def TargSpecX86 : InheritableAttr, TargetSpecificAttr<TargetArch<["x86"]>> {
+ let Spellings = [GCC<"test_targspec">];
+ let Subjects = SubjectList<[Function]>;
+ let Args = [UnsignedArgument<"ua">, DefaultIntArgument<"o", 0>];
+ let ParseKind = "TargSpec";
+ let Documentation = [Undocumented];
+}
+def TargSpecPPC : InheritableAttr, TargetSpecificAttr<TargetArch<["ppc"]>> {
+ let Spellings = [GCC<"test_targspec">];
+ let Subjects = SubjectList<[Function]>;
+ let Args = [Str...
[truncated]
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The code changes LGTM but I wonder if we should put a branch up on https://llvm-compile-time-tracker.com/ to verify the compile-time improvements before landing to verify they in fact resolve the issue.
Original regression for comparison: https://llvm-compile-time-tracker.com/compare.php?from=39b6900852e7a1187bd742ba5c1387ca1be58e2c&to=2acf77f987331c05520c5bfd849326909ffce983&stat=instructions:u Looks about the same! |
Thanks @nikic! |
In 2acf77f code was added to use the 'full' name including syntax and scope.
Instead of building up a large string for each name, add syntax and scope checks to the value expression in tablegen.
There is already code to generate expressions for target specific attributes. This change refactors and adds to that code to include syntax and scope checks.
The tablegen avoids generating the complicated expression unless there are two attributes using the same name, otherwise the case values will be as simple as before.
Removes the currently unused attributeHasStrictIdentifierArgAtIndex function and the related tablegen.