barannikov88 created this revision. Herald added subscribers: s.egerton, PkmX, simoncook, kristof.beyls, krytarowski, arichardson, dylanmckay. Herald added a reviewer: aaron.ballman. Herald added a project: All. barannikov88 requested review of this revision. Herald added subscribers: cfe-commits, wangpc. Herald added a project: clang.
1. The generated file contained a lot of duplicate switch cases, e.g.: switch (Syntax) { case AttributeCommonInfo::Syntax::AS_GNU: return llvm::StringSwitch<int>(Name) ... .Case("error", 1) .Case("warning", 1) .Case("error", 1) .Case("warning", 1) 2. Some attributes were listed in wrong places, e.g.: case AttributeCommonInfo::Syntax::AS_CXX11: { if (ScopeName == "") { return llvm::StringSwitch<int>(Name) ... .Case("warn_unused_result", LangOpts.CPlusPlus11 ? 201907 : 0) `warn_unused_result` is a non-standard attribute and should not be available as [[warn_unused_result]]. 3. Some attributes had the wrong version, e.g.: case AttributeCommonInfo::Syntax::AS_CXX11: { } else if (ScopeName == "gnu") { return llvm::StringSwitch<int>(Name) ... .Case("fallthrough", LangOpts.CPlusPlus11 ? 201603 : 0) [[gnu::fallthrough]] is a non-standard spelling and should not have the standard version. Instead, __has_cpp_attribute should return 1 for it. There is another issue with attributes that share spellings, e.g.: .Case("interrupt", true && (T.getArch() == llvm::Triple::arm || ...) ? 1 : 0) .Case("interrupt", true && (T.getArch() == llvm::Triple::avr) ? 1 : 0) ... .Case("interrupt", true && (T.getArch() == llvm::Triple::riscv32 || ...) ? 1 : 0) As can be seen, __has_attribute(interrupt) would only return true for ARM targets. This patch does not address this issue. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D159393 Files: clang/test/Preprocessor/has_attribute.cpp clang/test/Preprocessor/has_c_attribute.c clang/utils/TableGen/ClangAttrEmitter.cpp
Index: clang/utils/TableGen/ClangAttrEmitter.cpp =================================================================== --- clang/utils/TableGen/ClangAttrEmitter.cpp +++ clang/utils/TableGen/ClangAttrEmitter.cpp @@ -3388,9 +3388,10 @@ } static void GenerateHasAttrSpellingStringSwitch( - const std::vector<Record *> &Attrs, raw_ostream &OS, - const std::string &Variety = "", const std::string &Scope = "") { - for (const auto *Attr : Attrs) { + const std::vector<std::pair<const Record *, FlattenedSpelling>> &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<FlattenedSpelling> Spellings = GetFlattenedSpellings(*Attr); - for (const auto &Spelling : Spellings) { - if (Spelling.variety() == Variety && - (Spelling.nameSpace().empty() || Scope == Spelling.nameSpace())) { - Version = static_cast<int>( - 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<int>( + 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<Record *> Attrs = Records.getAllDerivedDefinitions("Attr"); - std::vector<Record *> Declspec, Microsoft, GNU, Pragma, HLSLSemantic; - std::map<std::string, std::vector<Record *>> CXX, C23; + std::vector<std::pair<const Record *, FlattenedSpelling>> Declspec, Microsoft, + GNU, Pragma, HLSLSemantic; + std::map<std::string, + std::vector<std::pair<const Record *, FlattenedSpelling>>> + 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<int>(Name)\n"; GenerateHasAttrSpellingStringSwitch(HLSLSemantic, OS, "HLSLSemantic"); auto fn = [&OS](const char *Spelling, - const std::map<std::string, std::vector<Record *>> &List) { + const std::map< + std::string, + std::vector<std::pair<const Record *, FlattenedSpelling>>> + &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) { Index: clang/test/Preprocessor/has_c_attribute.c =================================================================== --- clang/test/Preprocessor/has_c_attribute.c +++ 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. Index: clang/test/Preprocessor/has_attribute.cpp =================================================================== --- clang/test/Preprocessor/has_attribute.cpp +++ 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__)
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits