john.brawn updated this revision to Diff 239292.
john.brawn added reviewers: erichkeane, aaron.ballman, rjmccall.
john.brawn set the repository for this revision to rG LLVM Github Monorepo.
john.brawn added a subscriber: llvm-commits.
john.brawn added a comment.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Resurrecting this old patch, with the intention of trying to get it committed 
this time. This is the first of four patches to make it possible for clang 
plugins to define attributes.


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
@@ -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,40 @@
 
     // 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 << "};\n";
+    SS << "ParsedAttrInfo" << I->first;
+    SS << " parsedAttrInfo" << I->first << "Instance;\n\n";
   }
+  OS << SS.str();
 
-  OS << "static const ParsedAttrInfo AttrInfoMap[ParsedAttr::UnknownAttribute "
+  OS << "static const ParsedAttrInfo *AttrInfoMap[ParsedAttr::UnknownAttribute "
         "+ 1] = {\n";
-  OS << SS.str();
+  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,24 @@
   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 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 +136,14 @@
 
 } // 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.
+  const ParsedAttrInfo *Info = AttrInfoMap[A.getKind()];
+  if (Info)
+    return *Info;
+  return DefaultParsedAttrInfo;
 }
 
 unsigned ParsedAttr::getMinArgs() const { return getInfo(*this).NumArgs; }
@@ -140,7 +157,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 +169,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 +185,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 +195,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