Index: clang/lib/Sema/ParsedAttr.cpp =================================================================== --- clang/lib/Sema/ParsedAttr.cpp +++ clang/lib/Sema/ParsedAttr.cpp @@ -110,13 +110,26 @@ unsigned IsKnownToGCC : 1; unsigned IsSupportedByPragmaAttribute : 1; - bool (*DiagAppertainsToDecl)(Sema &S, const ParsedAttr &Attr, const Decl *); - bool (*DiagLangOpts)(Sema &S, const ParsedAttr &Attr); - bool (*ExistsInTarget)(const TargetInfo &Target); - unsigned (*SpellingIndexToSemanticSpelling)(const ParsedAttr &Attr); - void (*GetPragmaAttributeMatchRules)( - llvm::SmallVectorImpl> &Rules, - const LangOptions &LangOpts); + virtual ~ParsedAttrInfo() = default; + + virtual bool diagAppertainsToDecl(Sema &S, const ParsedAttr &Attr, + const Decl *) const { + return true; + } + virtual bool diagLangOpts(Sema &S, const ParsedAttr &Attr) const { + return true; + } + virtual bool existsInTarget(const TargetInfo &Target) const { + return true; + } + virtual unsigned + spellingIndexToSemanticSpelling(const ParsedAttr &Attr) const { + return UINT_MAX; + } + virtual void getPragmaAttributeMatchRules( + llvm::SmallVectorImpl> &Rules, + const LangOptions &LangOpts) const { + } }; namespace { @@ -125,8 +138,13 @@ } // namespace +static ParsedAttrInfo DefaultParsedAttrInfo; static const ParsedAttrInfo &getInfo(const ParsedAttr &A) { - return AttrInfoMap[A.getKind()]; + // If we have a ParsedAttrInfo for this ParsedAttr then return that, + // otherwise return a default ParsedAttrInfo. + if (A.getKind() < sizeof(AttrInfoMap)/sizeof(AttrInfoMap[0])) + return *AttrInfoMap[A.getKind()]; + return DefaultParsedAttrInfo; } unsigned ParsedAttr::getMinArgs() const { return getInfo(*this).NumArgs; } @@ -140,7 +158,7 @@ } bool ParsedAttr::diagnoseAppertainsTo(Sema &S, const Decl *D) const { - return getInfo(*this).DiagAppertainsToDecl(S, *this, D); + return getInfo(*this).diagAppertainsToDecl(S, *this, D); } bool ParsedAttr::appliesToDecl(const Decl *D, @@ -152,11 +170,11 @@ const LangOptions &LangOpts, SmallVectorImpl> &MatchRules) const { - return getInfo(*this).GetPragmaAttributeMatchRules(MatchRules, LangOpts); + return getInfo(*this).getPragmaAttributeMatchRules(MatchRules, LangOpts); } bool ParsedAttr::diagnoseLangOpts(Sema &S) const { - return getInfo(*this).DiagLangOpts(S, *this); + return getInfo(*this).diagLangOpts(S, *this); } bool ParsedAttr::isTargetSpecificAttr() const { @@ -168,7 +186,7 @@ bool ParsedAttr::isStmtAttr() const { return getInfo(*this).IsStmt; } bool ParsedAttr::existsInTarget(const TargetInfo &Target) const { - return getInfo(*this).ExistsInTarget(Target); + return getInfo(*this).existsInTarget(Target); } bool ParsedAttr::isKnownToGCC() const { return getInfo(*this).IsKnownToGCC; } @@ -178,7 +196,7 @@ } unsigned ParsedAttr::getSemanticSpelling() const { - return getInfo(*this).SpellingIndexToSemanticSpelling(*this); + return getInfo(*this).spellingIndexToSemanticSpelling(*this); } bool ParsedAttr::hasVariadicArg() const { Index: clang/utils/TableGen/ClangAttrEmitter.cpp =================================================================== --- clang/utils/TableGen/ClangAttrEmitter.cpp +++ clang/utils/TableGen/ClangAttrEmitter.cpp @@ -1801,7 +1801,7 @@ void emitMatchRuleList(raw_ostream &OS); - std::string generateStrictConformsTo(const Record &Attr, raw_ostream &OS); + void generateStrictConformsTo(const Record &Attr, raw_ostream &OS); void generateParsingHelpers(raw_ostream &OS); }; @@ -1962,21 +1962,17 @@ return Test; } -std::string +void PragmaClangAttributeSupport::generateStrictConformsTo(const Record &Attr, raw_ostream &OS) { - if (!isAttributedSupported(Attr)) - return "nullptr"; + if (!isAttributedSupported(Attr) || Attr.isValueUnset("Subjects")) + return; // Generate a function that constructs a set of matching rules that describe // to which declarations the attribute should apply to. - std::string FnName = "matchRulesFor" + Attr.getName().str(); - OS << "static void " << FnName << "(llvm::SmallVectorImpl> &MatchRules, const LangOptions &LangOpts) {\n"; - if (Attr.isValueUnset("Subjects")) { - OS << "}\n\n"; - return FnName; - } + << ", bool>> &MatchRules, const LangOptions &LangOpts) const {\n"; const Record *SubjectObj = Attr.getValueAsDef("Subjects"); std::vector Subjects = SubjectObj->getValueAsListOfDefs("Subjects"); for (const auto *Subject : Subjects) { @@ -1993,7 +1989,6 @@ } } OS << "}\n\n"; - return FnName; } void PragmaClangAttributeSupport::generateParsingHelpers(raw_ostream &OS) { @@ -3287,14 +3282,8 @@ // If there is a variadic argument, we will set the optional argument count // to its largest value. Since it's currently a 4-bit number, we set it to 15. - OS << ArgCount << ", " << (HasVariadic ? 15 : OptCount); -} - -static void GenerateDefaultAppertainsTo(raw_ostream &OS) { - OS << "static bool defaultAppertainsTo(Sema &, const ParsedAttr &,"; - OS << "const Decl *) {\n"; - OS << " return true;\n"; - OS << "}\n\n"; + OS << " NumArgs = " << ArgCount << ";\n"; + OS << " OptArgs = " << (HasVariadic ? 15 : OptCount) << ";\n"; } static std::string GetDiagnosticSpelling(const Record &R) { @@ -3408,11 +3397,12 @@ return FnName; } -static std::string GenerateAppertainsTo(const Record &Attr, raw_ostream &OS) { +static void GenerateAppertainsTo(const Record &Attr, raw_ostream &SS, + raw_ostream &OS) { // If the attribute does not contain a Subjects definition, then use the // default appertainsTo logic. if (Attr.isValueUnset("Subjects")) - return "defaultAppertainsTo"; + return; const Record *SubjectObj = Attr.getValueAsDef("Subjects"); std::vector Subjects = SubjectObj->getValueAsListOfDefs("Subjects"); @@ -3420,22 +3410,19 @@ // If the list of subjects is empty, it is assumed that the attribute // appertains to everything. if (Subjects.empty()) - return "defaultAppertainsTo"; + return; bool Warn = SubjectObj->getValueAsDef("Diag")->getValueAsBit("Warn"); // Otherwise, generate an appertainsTo check specific to this attribute which - // checks all of the given subjects against the Decl passed in. Return the - // name of that check to the caller. + // checks all of the given subjects against the Decl passed in. // // If D is null, that means the attribute was not applied to a declaration // at all (for instance because it was applied to a type), or that the caller // has determined that the check should fail (perhaps prior to the creation // of the declaration). - std::string FnName = "check" + Attr.getName().str() + "AppertainsTo"; - std::stringstream SS; - SS << "static bool " << FnName << "(Sema &S, const ParsedAttr &Attr, "; - SS << "const Decl *D) {\n"; + SS << "virtual bool diagAppertainsToDecl(Sema &S, "; + SS << "const ParsedAttr &Attr, const Decl *D) const {\n"; SS << " if (!D || ("; for (auto I = Subjects.begin(), E = Subjects.end(); I != E; ++I) { // If the subject has custom code associated with it, generate a function @@ -3463,9 +3450,6 @@ SS << " }\n"; SS << " return true;\n"; SS << "}\n\n"; - - OS << SS.str(); - return FnName; } static void @@ -3504,37 +3488,16 @@ OS << "}\n\n"; } -static void GenerateDefaultLangOptRequirements(raw_ostream &OS) { - OS << "static bool defaultDiagnoseLangOpts(Sema &, "; - OS << "const ParsedAttr &) {\n"; - OS << " return true;\n"; - OS << "}\n\n"; -} - -static std::string GenerateLangOptRequirements(const Record &R, - raw_ostream &OS) { +static void GenerateLangOptRequirements(const Record &R, + raw_ostream &OS) { // If the attribute has an empty or unset list of language requirements, - // return the default handler. + // use the default handler. std::vector LangOpts = R.getValueAsListOfDefs("LangOpts"); if (LangOpts.empty()) - return "defaultDiagnoseLangOpts"; - - // Generate a unique function name for the diagnostic test. The list of - // options should usually be short (one or two options), and the - // uniqueness isn't strictly necessary (it is just for codegen efficiency). - std::string FnName = "check"; - for (auto I = LangOpts.begin(), E = LangOpts.end(); I != E; ++I) - FnName += (*I)->getValueAsString("Name"); - FnName += "LangOpts"; - - // If this code has already been generated, simply return the previous - // instance of it. - static std::set CustomLangOptsSet; - auto I = CustomLangOptsSet.find(FnName); - if (I != CustomLangOptsSet.end()) - return *I; + return; - OS << "static bool " << FnName << "(Sema &S, const ParsedAttr &Attr) {\n"; + OS << "virtual bool diagLangOpts(Sema &S, const ParsedAttr &Attr) "; + OS << "const {\n"; OS << " auto &LangOpts = S.LangOpts;\n"; OS << " if (" << GenerateTestExpression(LangOpts) << ")\n"; OS << " return true;\n\n"; @@ -3542,24 +3505,15 @@ OS << "<< Attr;\n"; OS << " return false;\n"; OS << "}\n\n"; - - CustomLangOptsSet.insert(FnName); - return FnName; -} - -static void GenerateDefaultTargetRequirements(raw_ostream &OS) { - OS << "static bool defaultTargetRequirements(const TargetInfo &) {\n"; - OS << " return true;\n"; - OS << "}\n\n"; } -static std::string GenerateTargetRequirements(const Record &Attr, - const ParsedAttrMap &Dupes, - raw_ostream &OS) { - // If the attribute is not a target specific attribute, return the default +static void GenerateTargetRequirements(const Record &Attr, + const ParsedAttrMap &Dupes, + raw_ostream &OS) { + // If the attribute is not a target specific attribute, use the default // target handler. if (!Attr.isSubClassOf("TargetSpecificAttr")) - return "defaultTargetRequirements"; + return; // Get the list of architectures to be tested for. const Record *R = Attr.getValueAsDef("Target"); @@ -3587,55 +3541,37 @@ std::string Test; bool UsesT = GenerateTargetSpecificAttrChecks(R, Arches, Test, &FnName); - // If this code has already been generated, simply return the previous - // instance of it. - static std::set CustomTargetSet; - auto I = CustomTargetSet.find(FnName); - if (I != CustomTargetSet.end()) - return *I; - - OS << "static bool " << FnName << "(const TargetInfo &Target) {\n"; + OS << "virtual bool existsInTarget(const TargetInfo &Target) const {\n"; if (UsesT) OS << " const llvm::Triple &T = Target.getTriple(); (void)T;\n"; OS << " return " << Test << ";\n"; OS << "}\n\n"; - - CustomTargetSet.insert(FnName); - return FnName; } -static void GenerateDefaultSpellingIndexToSemanticSpelling(raw_ostream &OS) { - OS << "static unsigned defaultSpellingIndexToSemanticSpelling(" - << "const ParsedAttr &Attr) {\n"; - OS << " return UINT_MAX;\n"; - OS << "}\n\n"; -} - -static std::string GenerateSpellingIndexToSemanticSpelling(const Record &Attr, - raw_ostream &OS) { +static void GenerateSpellingIndexToSemanticSpelling(const Record &Attr, + raw_ostream &OS) { // If the attribute does not have a semantic form, we can bail out early. if (!Attr.getValueAsBit("ASTNode")) - return "defaultSpellingIndexToSemanticSpelling"; + return; std::vector Spellings = GetFlattenedSpellings(Attr); // If there are zero or one spellings, or all of the spellings share the same // name, we can also bail out early. if (Spellings.size() <= 1 || SpellingNamesAreCommon(Spellings)) - return "defaultSpellingIndexToSemanticSpelling"; + return; // Generate the enumeration we will use for the mapping. SemanticSpellingMap SemanticToSyntacticMap; std::string Enum = CreateSemanticSpellings(Spellings, SemanticToSyntacticMap); std::string Name = Attr.getName().str() + "AttrSpellingMap"; - OS << "static unsigned " << Name << "(const ParsedAttr &Attr) {\n"; + OS << "virtual unsigned spellingIndexToSemanticSpelling("; + OS << "const ParsedAttr &Attr) const {\n"; OS << Enum; OS << " unsigned Idx = Attr.getAttributeSpellingListIndex();\n"; WriteSemanticSpellingSwitch("Idx", SemanticToSyntacticMap, OS); OS << "}\n\n"; - - return Name; } static bool IsKnownToGCC(const Record &Attr) { @@ -3658,13 +3594,6 @@ ParsedAttrMap Dupes; ParsedAttrMap Attrs = getParsedAttrList(Records, &Dupes); - // Generate the default appertainsTo, target and language option diagnostic, - // and spelling list index mapping methods. - GenerateDefaultAppertainsTo(OS); - GenerateDefaultLangOptRequirements(OS); - GenerateDefaultTargetRequirements(OS); - GenerateDefaultSpellingIndexToSemanticSpelling(OS); - // Generate the appertainsTo diagnostic methods and write their names into // another mapping. At the same time, generate the AttrInfoMap object // contents. Due to the reliance on generated code, use separate streams so @@ -3680,33 +3609,39 @@ // We need to generate struct instances based off ParsedAttrInfo from // ParsedAttr.cpp. - SS << " { "; - emitArgInfo(*I->second, SS); - SS << ", " << I->second->getValueAsBit("HasCustomParsing"); - SS << ", " << I->second->isSubClassOf("TargetSpecificAttr"); - SS << ", " - << (I->second->isSubClassOf("TypeAttr") || - I->second->isSubClassOf("DeclOrTypeAttr")); - SS << ", " << I->second->isSubClassOf("StmtAttr"); - SS << ", " << IsKnownToGCC(*I->second); - SS << ", " << PragmaAttributeSupport.isAttributedSupported(*I->second); - SS << ", " << GenerateAppertainsTo(*I->second, OS); - SS << ", " << GenerateLangOptRequirements(*I->second, OS); - SS << ", " << GenerateTargetRequirements(*I->second, Dupes, OS); - SS << ", " << GenerateSpellingIndexToSemanticSpelling(*I->second, OS); - SS << ", " - << PragmaAttributeSupport.generateStrictConformsTo(*I->second, OS); - SS << " }"; - - if (I + 1 != E) - SS << ","; - - SS << " // AT_" << I->first << "\n"; + const Record &Attr = *I->second; + SS << "struct ParsedAttrInfo" << I->first << " : public ParsedAttrInfo {\n"; + SS << " ParsedAttrInfo" << I->first << "() {\n"; + emitArgInfo(Attr, SS); + SS << " HasCustomParsing = "; + SS << Attr.getValueAsBit("HasCustomParsing") << ";\n"; + SS << " IsTargetSpecific = "; + SS << Attr.isSubClassOf("TargetSpecificAttr") << ";\n"; + SS << " IsType = "; + SS << (Attr.isSubClassOf("TypeAttr") || + Attr.isSubClassOf("DeclOrTypeAttr")) << ";\n"; + SS << " IsStmt = "; + SS << Attr.isSubClassOf("StmtAttr") << ";\n"; + SS << " IsKnownToGCC = "; + SS << IsKnownToGCC(Attr) << ";\n"; + SS << " IsSupportedByPragmaAttribute = "; + SS << PragmaAttributeSupport.isAttributedSupported(*I->second) << ";\n"; + SS << " }\n"; + GenerateAppertainsTo(Attr, SS, OS); + GenerateLangOptRequirements(Attr, SS); + GenerateTargetRequirements(Attr, Dupes, SS); + GenerateSpellingIndexToSemanticSpelling(Attr, SS); + PragmaAttributeSupport.generateStrictConformsTo(*I->second, SS); + SS << "static ParsedAttrInfo" << I->first << " Instance;\n"; + SS << "};\n"; + SS << "ParsedAttrInfo" << I->first << " ParsedAttrInfo" << I->first << "::Instance;\n"; } - - OS << "static const ParsedAttrInfo AttrInfoMap[ParsedAttr::UnknownAttribute " - "+ 1] = {\n"; OS << SS.str(); + + OS << "static const ParsedAttrInfo *AttrInfoMap[] = {\n"; + for (auto I = Attrs.begin(), E = Attrs.end(); I != E; ++I) { + OS << "&ParsedAttrInfo" << I->first << "::Instance,\n"; + } OS << "};\n\n"; // Generate the attribute match rules.