diff --git a/clang/test/Preprocessor/has_attribute.c b/clang/test/Preprocessor/has_attribute.c --- a/clang/test/Preprocessor/has_attribute.c +++ b/clang/test/Preprocessor/has_attribute.c @@ -10,6 +10,11 @@ int __always_inline__(); #endif +// CHECK: warn_unused_result +#if __has_attribute(warn_unused_result) +int warn_unused_result(); +#endif + // CHECK: no_dummy_attribute #if !__has_attribute(dummy_attribute) int no_dummy_attribute(); diff --git a/clang/test/Preprocessor/has_attribute.cpp b/clang/test/Preprocessor/has_attribute.cpp --- a/clang/test/Preprocessor/has_attribute.cpp +++ b/clang/test/Preprocessor/has_attribute.cpp @@ -3,14 +3,14 @@ #define CXX11(x) x: __has_cpp_attribute(x) -// CHECK: clang::fallthrough: 201603L +// CHECK: clang::fallthrough: 1 CXX11(clang::fallthrough) // CHECK: selectany: 0 CXX11(selectany) // The attribute name can be bracketed with double underscores. -// CHECK: clang::__fallthrough__: 201603L +// CHECK: clang::__fallthrough__: 1 CXX11(clang::__fallthrough__) // The scope cannot be bracketed with double underscores unless it is @@ -18,12 +18,21 @@ // CHECK: __gsl__::suppress: 0 CXX11(__gsl__::suppress) -// CHECK: _Clang::fallthrough: 201603L +// CHECK: _Clang::fallthrough: 1 CXX11(_Clang::fallthrough) // CHECK: __nodiscard__: 201907L CXX11(__nodiscard__) +// CHECK: warn_unused_result: 0 +CXX11(warn_unused_result) + +// CHECK: gnu::warn_unused_result: 1 +CXX11(gnu::warn_unused_result) + +// CHECK: clang::warn_unused_result: 1 +CXX11(clang::warn_unused_result) + // CHECK: __gnu__::__const__: 1 CXX11(__gnu__::__const__) diff --git a/clang/test/Preprocessor/has_c_attribute.c b/clang/test/Preprocessor/has_c_attribute.c --- a/clang/test/Preprocessor/has_c_attribute.c +++ b/clang/test/Preprocessor/has_c_attribute.c @@ -9,6 +9,15 @@ // CHECK: __nodiscard__: 202003L C2x(__nodiscard__) +// CHECK: warn_unused_result: 0 +C2x(warn_unused_result) + +// CHECK: gnu::warn_unused_result: 1 +C2x(gnu::warn_unused_result) + +// CHECK: clang::warn_unused_result: 0 +C2x(clang::warn_unused_result) + // CHECK: selectany: 0 C2x(selectany); // Known attribute not supported in C mode @@ -27,10 +36,10 @@ // CHECK: maybe_unused: 202106L C2x(maybe_unused) -// CHECK: __gnu__::warn_unused_result: 202003L +// CHECK: __gnu__::warn_unused_result: 1 C2x(__gnu__::warn_unused_result) -// CHECK: gnu::__warn_unused_result__: 202003L +// CHECK: gnu::__warn_unused_result__: 1 C2x(gnu::__warn_unused_result__) // Test that macro expansion of the builtin argument works. diff --git a/clang/utils/TableGen/ClangAttrEmitter.cpp b/clang/utils/TableGen/ClangAttrEmitter.cpp --- a/clang/utils/TableGen/ClangAttrEmitter.cpp +++ b/clang/utils/TableGen/ClangAttrEmitter.cpp @@ -3388,9 +3388,10 @@ } static void GenerateHasAttrSpellingStringSwitch( - const std::vector &Attrs, raw_ostream &OS, - const std::string &Variety = "", const std::string &Scope = "") { - for (const auto *Attr : Attrs) { + const std::vector> &Attrs, + raw_ostream &OS, const std::string &Variety, + const std::string &Scope = "") { + for (const auto &[Attr, Spelling] : Attrs) { // C++11-style attributes have specific version information associated with // them. If the attribute has no scope, the version information must not // have the default value (1), as that's incorrect. Instead, the unscoped @@ -3409,24 +3410,20 @@ // a way that is impactful to the end user. int Version = 1; - std::vector Spellings = GetFlattenedSpellings(*Attr); - for (const auto &Spelling : Spellings) { - if (Spelling.variety() == Variety && - (Spelling.nameSpace().empty() || Scope == Spelling.nameSpace())) { - Version = static_cast( - Spelling.getSpellingRecord().getValueAsInt("Version")); - // Verify that explicitly specified CXX11 and C23 spellings (i.e. - // not inferred from Clang/GCC spellings) have a version that's - // different than the default (1). - bool RequiresValidVersion = - (Variety == "CXX11" || Variety == "C23") && - Spelling.getSpellingRecord().getValueAsString("Variety") == Variety; - if (RequiresValidVersion && Scope.empty() && Version == 1) - PrintError(Spelling.getSpellingRecord().getLoc(), - "Standard attributes must have " - "valid version information."); - break; - } + assert(Spelling.variety() == Variety); + if (Spelling.nameSpace().empty() || Scope == Spelling.nameSpace()) { + Version = static_cast( + Spelling.getSpellingRecord().getValueAsInt("Version")); + // Verify that explicitly specified CXX11 and C23 spellings (i.e. + // not inferred from Clang/GCC spellings) have a version that's + // different from the default (1). + bool RequiresValidVersion = + (Variety == "CXX11" || Variety == "C23") && + Spelling.getSpellingRecord().getValueAsString("Variety") == Variety; + if (RequiresValidVersion && Scope.empty() && Version == 1) + PrintError(Spelling.getSpellingRecord().getLoc(), + "Standard attributes must have " + "valid version information."); } std::string Test; @@ -3446,10 +3443,8 @@ 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()))) - OS << " .Case(\"" << S.name() << "\", " << TestStr << ")\n"; + if (Scope.empty() || Scope == Spelling.nameSpace()) + OS << " .Case(\"" << Spelling.name() << "\", " << TestStr << ")\n"; } OS << " .Default(0);\n"; } @@ -3481,8 +3476,11 @@ // Separate all of the attributes out into four group: generic, C++11, GNU, // and declspecs. Then generate a big switch statement for each of them. std::vector Attrs = Records.getAllDerivedDefinitions("Attr"); - std::vector Declspec, Microsoft, GNU, Pragma, HLSLSemantic; - std::map> CXX, C23; + std::vector> Declspec, Microsoft, + GNU, Pragma, HLSLSemantic; + std::map>> + CXX, C23; // Walk over the list of all attributes, and split them out based on the // spelling variety. @@ -3491,19 +3489,19 @@ for (const auto &SI : Spellings) { const std::string &Variety = SI.variety(); if (Variety == "GNU") - GNU.push_back(R); + GNU.emplace_back(R, SI); else if (Variety == "Declspec") - Declspec.push_back(R); + Declspec.emplace_back(R, SI); else if (Variety == "Microsoft") - Microsoft.push_back(R); + Microsoft.emplace_back(R, SI); else if (Variety == "CXX11") - CXX[SI.nameSpace()].push_back(R); + CXX[SI.nameSpace()].emplace_back(R, SI); else if (Variety == "C23") - C23[SI.nameSpace()].push_back(R); + C23[SI.nameSpace()].emplace_back(R, SI); else if (Variety == "Pragma") - Pragma.push_back(R); + Pragma.emplace_back(R, SI); else if (Variety == "HLSLSemantic") - HLSLSemantic.push_back(R); + HLSLSemantic.emplace_back(R, SI); } } @@ -3525,7 +3523,10 @@ OS << " return llvm::StringSwitch(Name)\n"; GenerateHasAttrSpellingStringSwitch(HLSLSemantic, OS, "HLSLSemantic"); auto fn = [&OS](const char *Spelling, - const std::map> &List) { + const std::map< + std::string, + std::vector>> + &List) { OS << "case AttributeCommonInfo::Syntax::AS_" << Spelling << ": {\n"; // C++11-style attributes are further split out based on the Scope. for (auto I = List.cbegin(), E = List.cend(); I != E; ++I) {