Index: lib/Sema/AttributeList.cpp =================================================================== --- lib/Sema/AttributeList.cpp +++ lib/Sema/AttributeList.cpp @@ -161,11 +161,20 @@ unsigned IsStmt : 1; unsigned IsKnownToGCC : 1; - bool (*DiagAppertainsToDecl)(Sema &S, const AttributeList &Attr, - const Decl *); - bool (*DiagLangOpts)(Sema &S, const AttributeList &Attr); - bool (*ExistsInTarget)(const TargetInfo &Target); - unsigned (*SpellingIndexToSemanticSpelling)(const AttributeList &Attr); + virtual bool diagAppertainsToDecl(Sema &S, const AttributeList &Attr, + const Decl *) const { + return true; + } + virtual bool diagLangOpts(Sema &S, const AttributeList &Attr) const { + return true; + } + virtual bool existsInTarget(const TargetInfo &Target) const { + return true; + } + virtual unsigned + spellingIndexToSemanticSpelling(const AttributeList &Attr) const { + return UINT_MAX; + } }; namespace { @@ -173,7 +182,7 @@ } static const ParsedAttrInfo &getInfo(const AttributeList &A) { - return AttrInfoMap[A.getKind()]; + return *AttrInfoMap[A.getKind()]; } unsigned AttributeList::getMinArgs() const { @@ -189,11 +198,11 @@ } bool AttributeList::diagnoseAppertainsTo(Sema &S, const Decl *D) const { - return getInfo(*this).DiagAppertainsToDecl(S, *this, D); + return getInfo(*this).diagAppertainsToDecl(S, *this, D); } bool AttributeList::diagnoseLangOpts(Sema &S) const { - return getInfo(*this).DiagLangOpts(S, *this); + return getInfo(*this).diagLangOpts(S, *this); } bool AttributeList::isTargetSpecificAttr() const { @@ -209,7 +218,7 @@ } bool AttributeList::existsInTarget(const TargetInfo &Target) const { - return getInfo(*this).ExistsInTarget(Target); + return getInfo(*this).existsInTarget(Target); } bool AttributeList::isKnownToGCC() const { @@ -217,7 +226,7 @@ } unsigned AttributeList::getSemanticSpelling() const { - return getInfo(*this).SpellingIndexToSemanticSpelling(*this); + return getInfo(*this).spellingIndexToSemanticSpelling(*this); } bool AttributeList::hasVariadicArg() const { Index: utils/TableGen/ClangAttrEmitter.cpp =================================================================== --- utils/TableGen/ClangAttrEmitter.cpp +++ utils/TableGen/ClangAttrEmitter.cpp @@ -2543,7 +2543,7 @@ return createArgument(R, AttrName)->isVariadic(); } -static void emitArgInfo(const Record &R, std::stringstream &OS) { +static void emitArgInfo(const Record &R, raw_ostream &OS) { // This function will count the number of arguments specified for the // attribute and emit the number of required arguments followed by the // number of optional arguments. @@ -2562,14 +2562,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 AttributeList &,"; - OS << "const Decl *) {\n"; - OS << " return true;\n"; - OS << "}\n\n"; + OS << " NumArgs = " << ArgCount << ";\n"; + OS << " OptArgs = " << (HasVariadic ? 15 : OptCount) << ";\n"; } static std::string CalculateDiagnostic(const Record &S) { @@ -2704,43 +2698,11 @@ return B + "Decl"; } -static std::string GenerateCustomAppertainsTo(const Record &Subject, - raw_ostream &OS) { - std::string FnName = "is" + Subject.getName().str(); - - // If this code has already been generated, simply return the previous - // instance of it. - static std::set CustomSubjectSet; - auto I = CustomSubjectSet.find(FnName); - if (I != CustomSubjectSet.end()) - return *I; - - Record *Base = Subject.getValueAsDef("Base"); - - // Not currently support custom subjects within custom subjects. - if (Base->isSubClassOf("SubsetSubject")) { - PrintFatalError(Subject.getLoc(), - "SubsetSubjects within SubsetSubjects is not supported"); - return ""; - } - - OS << "static bool " << FnName << "(const Decl *D) {\n"; - OS << " if (const auto *S = dyn_cast<"; - OS << GetSubjectWithSuffix(Base); - OS << ">(D))\n"; - OS << " return " << Subject.getValueAsString("CheckCode") << ";\n"; - OS << " return false;\n"; - OS << "}\n\n"; - - CustomSubjectSet.insert(FnName); - return FnName; -} - -static std::string GenerateAppertainsTo(const Record &Attr, raw_ostream &OS) { +static void GenerateAppertainsTo(const Record &Attr, 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"); @@ -2748,114 +2710,80 @@ // 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"); + OS << " virtual bool diagAppertainsToDecl(Sema &S, "; + OS << "const AttributeList &Attr, const Decl *D) const {\n"; // 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. - std::string FnName = "check" + Attr.getName().str() + "AppertainsTo"; - std::stringstream SS; - SS << "static bool " << FnName << "(Sema &S, const AttributeList &Attr, "; - SS << "const Decl *D) {\n"; - SS << " if ("; + // checks all of the given subjects against the Decl passed in. for (auto I = Subjects.begin(), E = Subjects.end(); I != E; ++I) { - // If the subject has custom code associated with it, generate a function - // for it. The function cannot be inlined into this check (yet) because it - // requires the subject to be of a specific type, and were that information - // inlined here, it would not support an attribute with multiple custom - // subjects. - if ((*I)->isSubClassOf("SubsetSubject")) { - SS << "!" << GenerateCustomAppertainsTo(**I, OS) << "(D)"; + const Record *Subject = *I; + if (Subject->isSubClassOf("SubsetSubject")) { + Record *Base = Subject->getValueAsDef("Base"); + // Not currently support custom subjects within custom subjects. + if (Base->isSubClassOf("SubsetSubject")) { + PrintFatalError( + Subject->getLoc(), + "SubsetSubjects within SubsetSubjects is not supported"); + return; + } + std::string SubjectType = GetSubjectWithSuffix(Base); + OS << " if (const auto *S = dyn_cast<" << SubjectType << ">(D))\n"; + OS << " if (" << Subject->getValueAsString("CheckCode") << ")\n"; + OS << " return true;\n"; } else { - SS << "!isa<" << GetSubjectWithSuffix(*I) << ">(D)"; + std::string SubjectType = GetSubjectWithSuffix(Subject); + OS << " if (isa<" << SubjectType << ">(D)) return true;\n"; } - - if (I + 1 != E) - SS << " && "; } - SS << ") {\n"; - SS << " S.Diag(Attr.getLoc(), diag::"; - SS << (Warn ? "warn_attribute_wrong_decl_type" : - "err_attribute_wrong_decl_type"); - SS << ")\n"; - SS << " << Attr.getName() << "; - SS << CalculateDiagnostic(*SubjectObj) << ";\n"; - SS << " return false;\n"; - SS << " }\n"; - SS << " return true;\n"; - SS << "}\n\n"; - - OS << SS.str(); - return FnName; -} - -static void GenerateDefaultLangOptRequirements(raw_ostream &OS) { - OS << "static bool defaultDiagnoseLangOpts(Sema &, "; - OS << "const AttributeList &) {\n"; - OS << " return true;\n"; - OS << "}\n\n"; + bool Warn = SubjectObj->getValueAsDef("Diag")->getValueAsBit("Warn"); + OS << " S.Diag(Attr.getLoc(), diag::"; + OS << (Warn ? "warn_attribute_wrong_decl_type" : + "err_attribute_wrong_decl_type"); + OS << ")\n"; + OS << " << Attr.getName() << "; + OS << CalculateDiagnostic(*SubjectObj) << ";\n"; + OS << " return false;\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"; + return; - // Generate the test condition, as well as 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", Test; + // Generate the test condition. + std::string Test; for (auto I = LangOpts.begin(), E = LangOpts.end(); I != E; ++I) { std::string Part = (*I)->getValueAsString("Name"); if ((*I)->getValueAsBit("Negated")) { - FnName += "Not"; Test += "!"; } Test += "S.LangOpts." + Part; if (I + 1 != E) Test += " || "; - FnName += Part; } - 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; - - OS << "static bool " << FnName << "(Sema &S, const AttributeList &Attr) {\n"; - OS << " if (" << Test << ")\n"; - OS << " return true;\n\n"; - OS << " S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) "; + OS << " virtual bool diagLangOpts(Sema &S, const AttributeList &Attr) "; + OS << "const {\n"; + OS << " if (" << Test << ")\n"; + OS << " return true;\n\n"; + OS << " S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) "; OS << "<< Attr.getName();\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"; + OS << " return false;\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"); @@ -2863,7 +2791,7 @@ if (Arches.empty()) { PrintError(Attr.getLoc(), "Empty list of target architectures for a " "target-specific attr"); - return "defaultTargetRequirements"; + return; } // If there are other attributes which share the same parsed attribute kind, @@ -2887,54 +2815,36 @@ std::string Test; 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 << " const llvm::Triple &T = Target.getTriple();\n"; - OS << " return " << Test << ";\n"; - OS << "}\n\n"; - - CustomTargetSet.insert(FnName); - return FnName; -} - -static void GenerateDefaultSpellingIndexToSemanticSpelling(raw_ostream &OS) { - OS << "static unsigned defaultSpellingIndexToSemanticSpelling(" - << "const AttributeList &Attr) {\n"; - OS << " return UINT_MAX;\n"; - OS << "}\n\n"; + OS << " virtual bool existsInTarget(const TargetInfo &Target) const {\n"; + OS << " const llvm::Triple &T = Target.getTriple();\n"; + OS << " return " << Test << ";\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 AttributeList &Attr) {\n"; + OS << " virtual unsigned spellingIndexToSemanticSpelling("; + OS << "const AttributeList &Attr) const {\n"; OS << Enum; - OS << " unsigned Idx = Attr.getAttributeSpellingListIndex();\n"; + OS << " unsigned Idx = Attr.getAttributeSpellingListIndex();\n"; WriteSemanticSpellingSwitch("Idx", SemanticToSyntacticMap, OS); - OS << "}\n\n"; - - return Name; + OS << " }\n\n"; } static bool IsKnownToGCC(const Record &Attr) { @@ -2954,18 +2864,10 @@ 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 // that code will not be interleaved. - std::stringstream SS; for (auto I = Attrs.begin(), E = Attrs.end(); I != E; ++I) { // TODO: If the attribute's kind appears in the list of duplicates, that is // because it is a target-specific attribute that appears multiple times. @@ -2975,27 +2877,34 @@ // We need to generate struct instances based off ParsedAttrInfo from // AttributeList.cpp. - SS << " { "; - emitArgInfo(*I->second, SS); - SS << ", " << I->second->getValueAsBit("HasCustomParsing"); - SS << ", " << I->second->isSubClassOf("TargetSpecificAttr"); - SS << ", " << I->second->isSubClassOf("TypeAttr"); - SS << ", " << I->second->isSubClassOf("StmtAttr"); - SS << ", " << IsKnownToGCC(*I->second); - SS << ", " << GenerateAppertainsTo(*I->second, OS); - SS << ", " << GenerateLangOptRequirements(*I->second, OS); - SS << ", " << GenerateTargetRequirements(*I->second, Dupes, OS); - SS << ", " << GenerateSpellingIndexToSemanticSpelling(*I->second, OS); - SS << " }"; - - if (I + 1 != E) - SS << ","; - - SS << " // AT_" << I->first << "\n"; + const Record &Attr = *I->second; + OS << "struct ParsedAttrInfo" << I->first << " : public ParsedAttrInfo {\n"; + OS << " ParsedAttrInfo" << I->first << "() {\n"; + emitArgInfo(Attr, OS); + OS << " HasCustomParsing = "; + OS << Attr.getValueAsBit("HasCustomParsing") << ";\n"; + OS << " IsTargetSpecific = "; + OS << Attr.isSubClassOf("TargetSpecificAttr") << ";\n"; + OS << " IsType = "; + OS << Attr.isSubClassOf("TypeAttr") << ";\n"; + OS << " IsStmt = "; + OS << Attr.isSubClassOf("StmtAttr") << ";\n"; + OS << " IsKnownToGCC = "; + OS << IsKnownToGCC(Attr) << ";\n"; + OS << " }\n"; + GenerateAppertainsTo(Attr, OS); + GenerateLangOptRequirements(Attr, OS); + GenerateTargetRequirements(Attr, Dupes, OS); + GenerateSpellingIndexToSemanticSpelling(Attr, OS); + OS << "};\n"; + OS << "ParsedAttrInfo" << I->first; + OS << " parsedAttrInfo" << I->first << "Instance;\n\n"; } - OS << "static const ParsedAttrInfo AttrInfoMap[AttributeList::UnknownAttribute + 1] = {\n"; - OS << SS.str(); + OS << "static const ParsedAttrInfo *AttrInfoMap[AttributeList::UnknownAttribute + 1] = {\n"; + for (auto I = Attrs.begin(), E = Attrs.end(); I != E; ++I) { + OS << "&parsedAttrInfo" << I->first << "Instance,\n"; + } OS << "};\n\n"; }