[clang] [clang] Fix compile-time regression from attribute arg checking change (PR #101768)

via cfe-commits cfe-commits at lists.llvm.org
Fri Aug 2 15:58:08 PDT 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Mike Rice (mikerice1969)

<details>
<summary>Changes</summary>

In 2acf77f987331c05520c5bfd849326909ffce983 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:

- (modified) clang/include/clang/Basic/AttributeCommonInfo.h (-6) 
- (modified) clang/lib/Basic/Attributes.cpp (-34) 
- (modified) clang/lib/Parse/ParseDecl.cpp (+17-54) 
- (modified) clang/test/TableGen/attrs-parser-string-switches.td (+67-65) 
- (modified) clang/utils/TableGen/ClangAttrEmitter.cpp (+163-111) 


``````````diff
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]

``````````

</details>


https://github.com/llvm/llvm-project/pull/101768


More information about the cfe-commits mailing list