Index: clang/include/clang/Basic/Attr.td =================================================================== --- clang/include/clang/Basic/Attr.td +++ clang/include/clang/Basic/Attr.td @@ -257,7 +257,6 @@ class Spelling { string Name = name; string Variety = variety; - bit KnownToGCC; } class GNU : Spelling; @@ -277,11 +276,11 @@ string Namespace = namespace; } -// The GCC spelling implies GNU and CXX11<"gnu", name> and also sets -// KnownToGCC to 1. This spelling should be used for any GCC-compatible +// The GCC spelling implies GNU, CXX11<"gnu", name>, and optionally, +// C2x<"gnu", name>. This spelling should be used for any GCC-compatible // attributes. -class GCC : Spelling { - let KnownToGCC = 1; +class GCC : Spelling { + bit AllowInC = allowInC; } // The Clang spelling implies GNU, CXX11<"clang", name>, and optionally, @@ -605,7 +604,7 @@ // def AbiTag : Attr { - let Spellings = [GCC<"abi_tag">]; + let Spellings = [GCC<"abi_tag", /*AllowInC*/0>]; let Args = [VariadicStringArgument<"Tags">]; let Subjects = SubjectList<[Struct, Var, Function, Namespace], ErrorDiag>; let MeaningfulToClassTemplateDefinition = 1; @@ -2113,7 +2112,7 @@ } def InitPriority : InheritableAttr { - let Spellings = [GCC<"init_priority">]; + let Spellings = [GCC<"init_priority", /*AllowInC*/0>]; let Args = [UnsignedArgument<"Priority">]; let Subjects = SubjectList<[Var], ErrorDiag>; let Documentation = [Undocumented]; Index: clang/test/Sema/attr-c2x.c =================================================================== --- clang/test/Sema/attr-c2x.c +++ clang/test/Sema/attr-c2x.c @@ -27,3 +27,15 @@ [[nodiscard]] int without_underscores(void); [[__nodiscard__]] int underscores(void); + +// Match GCC's behavior for C attributes as well. +[[gnu::constructor]] void ctor_func(void); +[[gnu::destructor]] void dtor_func(void); +[[gnu::hot]] void hot_func(void); +[[__gnu__::hot]] void hot_func2(void); +[[gnu::__hot__]] void hot_func3(void); +[[__gnu__::__hot__]] void hot_func4(void); + +// Note how not all GCC attributes are supported in C. +[[gnu::abi_tag("")]] void abi_func(void); // expected-warning {{unknown attribute 'abi_tag' ignored}} +struct S s [[gnu::init_priority(1)]]; // expected-warning {{unknown attribute 'init_priority' ignored}} Index: clang/utils/TableGen/ClangAttrEmitter.cpp =================================================================== --- clang/utils/TableGen/ClangAttrEmitter.cpp +++ clang/utils/TableGen/ClangAttrEmitter.cpp @@ -48,7 +48,7 @@ class FlattenedSpelling { std::string V, N, NS; - bool K; + bool K = false; public: FlattenedSpelling(const std::string &Variety, const std::string &Name, @@ -61,8 +61,6 @@ "Given a GCC spelling, which means this hasn't been flattened!"); if (V == "CXX11" || V == "C2x" || V == "Pragma") NS = std::string(Spelling.getValueAsString("Namespace")); - bool Unset; - K = Spelling.getValueAsBitOrUnset("KnownToGCC", Unset); } const std::string &variety() const { return V; } @@ -82,9 +80,10 @@ StringRef Variety = Spelling->getValueAsString("Variety"); StringRef Name = Spelling->getValueAsString("Name"); if (Variety == "GCC") { - // Gin up two new spelling objects to add into the list. Ret.emplace_back("GNU", std::string(Name), "", true); Ret.emplace_back("CXX11", std::string(Name), "gnu", true); + if (Spelling->getValueAsBit("AllowInC")) + Ret.emplace_back("C2x", std::string(Name), "gnu", true); } else if (Variety == "Clang") { Ret.emplace_back("GNU", std::string(Name), "", false); Ret.emplace_back("CXX11", std::string(Name), "clang", false);