Index: clang/include/clang/Basic/Attr.td =================================================================== --- clang/include/clang/Basic/Attr.td +++ clang/include/clang/Basic/Attr.td @@ -267,8 +267,10 @@ string Namespace = namespace; int Version = version; } -class C2x : Spelling { +class C2x + : Spelling { string Namespace = namespace; + int Version = version; } class Keyword : Spelling; @@ -1221,7 +1223,8 @@ def Deprecated : InheritableAttr { let Spellings = [GCC<"deprecated">, Declspec<"deprecated">, - CXX11<"","deprecated", 201309>, C2x<"", "deprecated">]; + CXX11<"","deprecated", 201309>, + C2x<"", "deprecated", 201904>]; let Args = [StringArgument<"Message", 1>, // An optional string argument that enables us to provide a // Fix-It. @@ -1278,7 +1281,8 @@ } def FallThrough : StmtAttr { - let Spellings = [CXX11<"", "fallthrough", 201603>, C2x<"", "fallthrough">, + let Spellings = [CXX11<"", "fallthrough", 201603>, + C2x<"", "fallthrough", 201904>, CXX11<"clang", "fallthrough">, GCC<"fallthrough">]; // let Subjects = [NullStmt]; let Documentation = [FallthroughDocs]; @@ -2442,7 +2446,7 @@ def Unused : InheritableAttr { let Spellings = [CXX11<"", "maybe_unused", 201603>, GCC<"unused">, - C2x<"", "maybe_unused">]; + C2x<"", "maybe_unused", 201904>]; let Subjects = SubjectList<[Var, ObjCIvar, Type, Enum, EnumConstant, Label, Field, ObjCMethod, FunctionLike]>; let Documentation = [WarnMaybeUnusedDocs]; @@ -2528,7 +2532,8 @@ } def WarnUnusedResult : InheritableAttr { - let Spellings = [CXX11<"", "nodiscard", 201907>, C2x<"", "nodiscard">, + let Spellings = [CXX11<"", "nodiscard", 201907>, + C2x<"", "nodiscard", 201904>, CXX11<"clang", "warn_unused_result">, GCC<"warn_unused_result">]; let Subjects = SubjectList<[ObjCMethod, Enum, Record, FunctionLike]>; Index: clang/test/Preprocessor/has_c_attribute.c =================================================================== --- clang/test/Preprocessor/has_c_attribute.c +++ clang/test/Preprocessor/has_c_attribute.c @@ -1,22 +1,44 @@ -// RUN: %clang_cc1 -fdouble-square-bracket-attributes -std=c11 -E %s -o - | FileCheck %s -// RUN: %clang_cc1 -std=c2x -E %s -o - | FileCheck %s - -// CHECK: has_fallthrough -#if __has_c_attribute(fallthrough) - int has_fallthrough(); -#endif - -// CHECK: does_not_have_selectany -#if !__has_c_attribute(selectany) - int does_not_have_selectany(); -#endif - -// CHECK: has_nodiscard_underscore -#if __has_c_attribute(__nodiscard__) - int has_nodiscard_underscore(); -#endif - -// CHECK: has_clang_annotate -#if __has_c_attribute(clang::annotate) - int has_clang_annotate(); -#endif +// RUN: %clang_cc1 -fdouble-square-bracket-attributes -std=c11 -E -P %s -o - | FileCheck %s +// RUN: %clang_cc1 -std=c2x -E -P %s -o - | FileCheck %s + +#define C2x(x) x: __has_c_attribute(x) + +// CHECK: fallthrough: 201904L +C2x(fallthrough) + +// CHECK: __nodiscard__: 201904L +C2x(__nodiscard__) + +// CHECK: selectany: 0 +C2x(selectany); // Known attribute not supported in C mode + +// CHECK: frobble: 0 +C2x(frobble) // Unknown attribute + +// CHECK: frobble::frobble: 0 +C2x(frobble::frobble) // Unknown vendor namespace + +// CHECK: clang::annotate: 1 +C2x(clang::annotate) + +// CHECK: deprecated: 201904L +C2x(deprecated) + +// CHECK: maybe_unused: 201904L +C2x(maybe_unused) + +// CHECK: __gnu__::warn_unused_result: 201904L +C2x(__gnu__::warn_unused_result) + +// CHECK: gnu::__warn_unused_result__: 201904L +C2x(gnu::__warn_unused_result__) + +// We do somewhat support the __clang__ vendor namespace, but it is a +// predefined macro and thus we encourage users to use _Clang instead. +// Because of this, we do not support __has_c_attribute for that +// vendor namespace. +// +// Note, we can't use C2x here because it will expand __clang__ to 1 +// too early. +// CHECK: 1::fallthrough: 0 +__clang__::fallthrough: __has_c_attribute(__clang__::fallthrough) Index: clang/utils/TableGen/ClangAttrEmitter.cpp =================================================================== --- clang/utils/TableGen/ClangAttrEmitter.cpp +++ clang/utils/TableGen/ClangAttrEmitter.cpp @@ -3064,18 +3064,22 @@ // attribute version information should be taken from the SD-6 standing // document, which can be found at: // https://isocpp.org/std/standing-documents/sd-6-sg10-feature-test-recommendations + // + // 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. int Version = 1; - if (Variety == "CXX11") { - std::vector Spellings = Attr->getValueAsListOfDefs("Spellings"); - for (const auto &Spelling : Spellings) { - if (Spelling->getValueAsString("Variety") == "CXX11") { - Version = static_cast(Spelling->getValueAsInt("Version")); - if (Scope.empty() && Version == 1) - PrintError(Spelling->getLoc(), "C++ standard attributes must " - "have valid version information."); - break; - } + if (Variety == "CXX11" || Variety == "C2x") { + std::vector Spellings = Attr->getValueAsListOfDefs("Spellings"); + for (const auto &Spelling : Spellings) { + if (Spelling->getValueAsString("Variety") == Variety) { + Version = static_cast(Spelling->getValueAsInt("Version")); + if (Scope.empty() && Version == 1) + PrintError(Spelling->getLoc(), "Standard attributes must have " + "valid version information."); + break; + } } }