This revision was automatically updated to reflect the committed changes.
Closed by commit rG590dc8d02cd7: Use virtual functions in ParsedAttrInfo 
instead of function pointers (authored by john.brawn).

Changed prior to commit:
  https://reviews.llvm.org/D31337?vs=242363&id=246765#toc

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D31337/new/

https://reviews.llvm.org/D31337

Files:
  clang/lib/Sema/ParsedAttr.cpp
  clang/utils/TableGen/ClangAttrEmitter.cpp

Index: clang/utils/TableGen/ClangAttrEmitter.cpp
===================================================================
--- clang/utils/TableGen/ClangAttrEmitter.cpp
+++ clang/utils/TableGen/ClangAttrEmitter.cpp
@@ -1814,7 +1814,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);
 };
@@ -1975,21 +1975,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<std::pair<"
+  OS << "virtual void getPragmaAttributeMatchRules("
+     << "llvm::SmallVectorImpl<std::pair<"
      << AttributeSubjectMatchRule::EnumName
-     << ", bool>> &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<Record *> Subjects = SubjectObj->getValueAsListOfDefs("Subjects");
   for (const auto *Subject : Subjects) {
@@ -2006,7 +2002,6 @@
     }
   }
   OS << "}\n\n";
-  return FnName;
 }
 
 void PragmaClangAttributeSupport::generateParsingHelpers(raw_ostream &OS) {
@@ -3300,14 +3295,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) {
@@ -3388,16 +3377,14 @@
   return "is" + Subject.getName().str();
 }
 
-static std::string GenerateCustomAppertainsTo(const Record &Subject,
-                                              raw_ostream &OS) {
+static void GenerateCustomAppertainsTo(const Record &Subject, raw_ostream &OS) {
   std::string FnName = functionNameForCustomAppertainsTo(Subject);
 
-  // If this code has already been generated, simply return the previous
-  // instance of it.
+  // If this code has already been generated, we don't need to do anything.
   static std::set<std::string> CustomSubjectSet;
   auto I = CustomSubjectSet.find(FnName);
   if (I != CustomSubjectSet.end())
-    return *I;
+    return;
 
   // This only works with non-root Decls.
   Record *Base = Subject.getValueAsDef(BaseFieldName);
@@ -3406,7 +3393,7 @@
   if (Base->isSubClassOf("SubsetSubject")) {
     PrintFatalError(Subject.getLoc(),
                     "SubsetSubjects within SubsetSubjects is not supported");
-    return "";
+    return;
   }
 
   OS << "static bool " << FnName << "(const Decl *D) {\n";
@@ -3418,14 +3405,13 @@
   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<Record*> Subjects = SubjectObj->getValueAsListOfDefs("Subjects");
@@ -3433,52 +3419,46 @@
   // 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 << "  if (!D || (";
+  OS << "virtual bool diagAppertainsToDecl(Sema &S, ";
+  OS << "const ParsedAttr &Attr, const Decl *D) const {\n";
+  OS << "  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
-    // 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 the subject has custom code associated with it, use the generated
+    // 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)";
+      OS << "!" << functionNameForCustomAppertainsTo(**I) << "(D)";
     } else {
-      SS << "!isa<" << GetSubjectWithSuffix(*I) << ">(D)";
+      OS << "!isa<" << GetSubjectWithSuffix(*I) << ">(D)";
     }
 
     if (I + 1 != E)
-      SS << " && ";
+      OS << " && ";
   }
-  SS << ")) {\n";
-  SS << "    S.Diag(Attr.getLoc(), diag::";
-  SS << (Warn ? "warn_attribute_wrong_decl_type_str" :
+  OS << ")) {\n";
+  OS << "    S.Diag(Attr.getLoc(), diag::";
+  OS << (Warn ? "warn_attribute_wrong_decl_type_str" :
                "err_attribute_wrong_decl_type_str");
-  SS << ")\n";
-  SS << "      << Attr << ";
-  SS << CalculateDiagnostic(*SubjectObj) << ";\n";
-  SS << "    return false;\n";
-  SS << "  }\n";
-  SS << "  return true;\n";
-  SS << "}\n\n";
-
-  OS << SS.str();
-  return FnName;
+  OS << ")\n";
+  OS << "      << Attr << ";
+  OS << CalculateDiagnostic(*SubjectObj) << ";\n";
+  OS << "    return false;\n";
+  OS << "  }\n";
+  OS << "  return true;\n";
+  OS << "}\n\n";
 }
 
 static void
@@ -3517,37 +3497,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<Record *> 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<std::string> CustomLangOptsSet;
-  auto I = CustomLangOptsSet.find(FnName);
-  if (I != CustomLangOptsSet.end())
-    return *I;
-
-  OS << "static bool " << FnName << "(Sema &S, const ParsedAttr &Attr) {\n";
+    return;
+
+  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";
@@ -3555,24 +3514,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");
@@ -3600,55 +3550,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<std::string> 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<FlattenedSpelling> 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) {
@@ -3671,19 +3603,19 @@
   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::string Buffer;
-  raw_string_ostream SS {Buffer};
+  // Generate all of the custom appertainsTo functions that the attributes
+  // will be using.
+  for (auto I : Attrs) {
+    const Record &Attr = *I.second;
+    if (Attr.isValueUnset("Subjects"))
+      continue;
+    const Record *SubjectObj = Attr.getValueAsDef("Subjects");
+    for (auto Subject : SubjectObj->getValueAsListOfDefs("Subjects"))
+      if (Subject->isSubClassOf("SubsetSubject"))
+        GenerateCustomAppertainsTo(*Subject, OS);
+  }
+
+  // Generate a ParsedAttrInfo struct for each of the attributes.
   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.
@@ -3693,33 +3625,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;
+    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") ||
+           Attr.isSubClassOf("DeclOrTypeAttr")) << ";\n";
+    OS << "    IsStmt = ";
+    OS << Attr.isSubClassOf("StmtAttr") << ";\n";
+    OS << "    IsKnownToGCC = ";
+    OS << IsKnownToGCC(Attr) << ";\n";
+    OS << "    IsSupportedByPragmaAttribute = ";
+    OS << PragmaAttributeSupport.isAttributedSupported(*I->second) << ";\n";
+    OS << "  }\n";
+    GenerateAppertainsTo(Attr, OS);
+    GenerateLangOptRequirements(Attr, OS);
+    GenerateTargetRequirements(Attr, Dupes, OS);
+    GenerateSpellingIndexToSemanticSpelling(Attr, OS);
+    PragmaAttributeSupport.generateStrictConformsTo(*I->second, OS);
+    OS << "static const ParsedAttrInfo" << I->first << " Instance;\n";
+    OS << "};\n";
+    OS << "const 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.
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<std::pair<attr::SubjectMatchRule, bool>> &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<std::pair<attr::SubjectMatchRule, bool>> &Rules,
+    const LangOptions &LangOpts) const {
+  }
 };
 
 namespace {
@@ -126,7 +139,13 @@
 } // namespace
 
 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() < llvm::array_lengthof(AttrInfoMap))
+    return *AttrInfoMap[A.getKind()];
+
+  static ParsedAttrInfo DefaultParsedAttrInfo;
+  return DefaultParsedAttrInfo;
 }
 
 unsigned ParsedAttr::getMinArgs() const { return getInfo(*this).NumArgs; }
@@ -140,7 +159,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 +171,11 @@
     const LangOptions &LangOpts,
     SmallVectorImpl<std::pair<attr::SubjectMatchRule, bool>> &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 +187,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 +197,7 @@
 }
 
 unsigned ParsedAttr::getSemanticSpelling() const {
-  return getInfo(*this).SpellingIndexToSemanticSpelling(*this);
+  return getInfo(*this).spellingIndexToSemanticSpelling(*this);
 }
 
 bool ParsedAttr::hasVariadicArg() const {
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to