john.brawn updated this revision to Diff 239535.
john.brawn added a comment.
Update based on review comments. Also fix warnings due to missing virtual 
destructor that I hadn't noticed before.


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
@@ -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<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) {
@@ -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<Record*> 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<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;
+    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<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) {
@@ -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.
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 {
@@ -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<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 +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 {
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to