john.brawn updated this revision to Diff 246763.
john.brawn added a comment.
Herald added a subscriber: krytarowski.

This has been rewritten so that the registry is only used for attributes added 
by plugins, and everything else continues as before. This also removes the 
strange dependency I'd previously introduced, where Attributes.cpp (in 
libclangBasic.so) declared and used the registry but ParsedAttr.cpp (in 
libclangSema.so) populated it - now the registry is declared and used solely 
within ParsedAttr.cpp.


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

https://reviews.llvm.org/D31338

Files:
  clang/include/clang/Basic/AttributeCommonInfo.h
  clang/include/clang/Sema/ParsedAttr.h
  clang/lib/Basic/Attributes.cpp
  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
@@ -3625,9 +3625,11 @@
 
     // We need to generate struct instances based off ParsedAttrInfo from
     // ParsedAttr.cpp.
+    const std::string &AttrName = I->first;
     const Record &Attr = *I->second;
     OS << "struct ParsedAttrInfo" << I->first << " : public ParsedAttrInfo {\n";
     OS << "  ParsedAttrInfo" << I->first << "() {\n";
+    OS << "    AttrKind = ParsedAttr::AT_" << AttrName << ";\n";
     emitArgInfo(Attr, OS);
     OS << "    HasCustomParsing = ";
     OS << Attr.getValueAsBit("HasCustomParsing") << ";\n";
@@ -3642,6 +3644,20 @@
     OS << IsKnownToGCC(Attr) << ";\n";
     OS << "    IsSupportedByPragmaAttribute = ";
     OS << PragmaAttributeSupport.isAttributedSupported(*I->second) << ";\n";
+    for (const auto &S : GetFlattenedSpellings(Attr)) {
+      const std::string &RawSpelling = S.name();
+      std::string Spelling;
+      if (S.variety() == "CXX11" || S.variety() == "C2x") {
+        Spelling += S.nameSpace();
+        Spelling += "::";
+      }
+      if (S.variety() == "GNU")
+        Spelling += NormalizeGNUAttrSpelling(RawSpelling);
+      else
+        Spelling += RawSpelling;
+      OS << "    Spellings.push_back({AttributeCommonInfo::AS_" << S.variety();
+      OS << ",\"" << Spelling << "\"});\n";
+    }
     OS << "  }\n";
     GenerateAppertainsTo(Attr, OS);
     GenerateLangOptRequirements(Attr, OS);
Index: clang/lib/Sema/ParsedAttr.cpp
===================================================================
--- clang/lib/Sema/ParsedAttr.cpp
+++ clang/lib/Sema/ParsedAttr.cpp
@@ -25,6 +25,8 @@
 
 using namespace clang;
 
+LLVM_INSTANTIATE_REGISTRY(ParsedAttrInfoRegistry)
+
 IdentifierLoc *IdentifierLoc::create(ASTContext &Ctx, SourceLocation Loc,
                                      IdentifierInfo *Ident) {
   IdentifierLoc *Result = new (Ctx) IdentifierLoc;
@@ -100,66 +102,58 @@
   pool.Attrs.clear();
 }
 
-struct ParsedAttrInfo {
-  unsigned NumArgs : 4;
-  unsigned OptArgs : 4;
-  unsigned HasCustomParsing : 1;
-  unsigned IsTargetSpecific : 1;
-  unsigned IsType : 1;
-  unsigned IsStmt : 1;
-  unsigned IsKnownToGCC : 1;
-  unsigned IsSupportedByPragmaAttribute : 1;
-
-  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 {
 
 #include "clang/Sema/AttrParsedAttrImpl.inc"
 
 } // namespace
 
-static const ParsedAttrInfo &getInfo(const ParsedAttr &A) {
-  // 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()];
-
+const ParsedAttrInfo &ParsedAttrInfo::get(const AttributeCommonInfo &A) {
+  // If we have a ParsedAttrInfo for this ParsedAttr then return that.
+  if (A.getParsedKind() < llvm::array_lengthof(AttrInfoMap))
+    return *AttrInfoMap[A.getParsedKind()];
+
+  // If this is an ignored attribute then return an appropriate ParsedAttrInfo.
+  static ParsedAttrInfo IgnoredParsedAttrInfo(
+      AttributeCommonInfo::IgnoredAttribute);
+  if (A.getParsedKind() == AttributeCommonInfo::IgnoredAttribute)
+    return IgnoredParsedAttrInfo;
+
+  // Otherwise this may be an attribute defined by a plugin. First instantiate
+  // all plugin attributes if we haven't already done so.
+  static std::list<std::unique_ptr<ParsedAttrInfo>> PluginAttrInstances;
+  if (PluginAttrInstances.empty())
+    for (auto It : ParsedAttrInfoRegistry::entries())
+      PluginAttrInstances.emplace_back(It.instantiate());
+
+  // Search for a ParsedAttrInfo whose name and syntax match.
+  std::string FullName = A.getFullName();
+  AttributeCommonInfo::Syntax SyntaxUsed = A.getSyntax();
+  if (SyntaxUsed == AttributeCommonInfo::AS_ContextSensitiveKeyword)
+    SyntaxUsed = AttributeCommonInfo::AS_Keyword;
+
+  for (auto &Ptr : PluginAttrInstances)
+    for (auto &S : Ptr->Spellings)
+      if (S.Syntax == SyntaxUsed && FullName == S.FullName)
+        return *Ptr;
+
+  // If we failed to find a match then return a default ParsedAttrInfo.
   static ParsedAttrInfo DefaultParsedAttrInfo;
   return DefaultParsedAttrInfo;
 }
 
-unsigned ParsedAttr::getMinArgs() const { return getInfo(*this).NumArgs; }
+unsigned ParsedAttr::getMinArgs() const { return getInfo().NumArgs; }
 
 unsigned ParsedAttr::getMaxArgs() const {
-  return getMinArgs() + getInfo(*this).OptArgs;
+  return getMinArgs() + getInfo().OptArgs;
 }
 
 bool ParsedAttr::hasCustomParsing() const {
-  return getInfo(*this).HasCustomParsing;
+  return getInfo().HasCustomParsing;
 }
 
 bool ParsedAttr::diagnoseAppertainsTo(Sema &S, const Decl *D) const {
-  return getInfo(*this).diagAppertainsToDecl(S, *this, D);
+  return getInfo().diagAppertainsToDecl(S, *this, D);
 }
 
 bool ParsedAttr::appliesToDecl(const Decl *D,
@@ -171,33 +165,33 @@
     const LangOptions &LangOpts,
     SmallVectorImpl<std::pair<attr::SubjectMatchRule, bool>> &MatchRules)
     const {
-  return getInfo(*this).getPragmaAttributeMatchRules(MatchRules, LangOpts);
+  return getInfo().getPragmaAttributeMatchRules(MatchRules, LangOpts);
 }
 
 bool ParsedAttr::diagnoseLangOpts(Sema &S) const {
-  return getInfo(*this).diagLangOpts(S, *this);
+  return getInfo().diagLangOpts(S, *this);
 }
 
 bool ParsedAttr::isTargetSpecificAttr() const {
-  return getInfo(*this).IsTargetSpecific;
+  return getInfo().IsTargetSpecific;
 }
 
-bool ParsedAttr::isTypeAttr() const { return getInfo(*this).IsType; }
+bool ParsedAttr::isTypeAttr() const { return getInfo().IsType; }
 
-bool ParsedAttr::isStmtAttr() const { return getInfo(*this).IsStmt; }
+bool ParsedAttr::isStmtAttr() const { return getInfo().IsStmt; }
 
 bool ParsedAttr::existsInTarget(const TargetInfo &Target) const {
-  return getInfo(*this).existsInTarget(Target);
+  return getInfo().existsInTarget(Target);
 }
 
-bool ParsedAttr::isKnownToGCC() const { return getInfo(*this).IsKnownToGCC; }
+bool ParsedAttr::isKnownToGCC() const { return getInfo().IsKnownToGCC; }
 
 bool ParsedAttr::isSupportedByPragmaAttribute() const {
-  return getInfo(*this).IsSupportedByPragmaAttribute;
+  return getInfo().IsSupportedByPragmaAttribute;
 }
 
 unsigned ParsedAttr::getSemanticSpelling() const {
-  return getInfo(*this).spellingIndexToSemanticSpelling(*this);
+  return getInfo().spellingIndexToSemanticSpelling(*this);
 }
 
 bool ParsedAttr::hasVariadicArg() const {
@@ -205,5 +199,5 @@
   // claim that as being variadic. If we someday get an attribute that
   // legitimately bumps up against that maximum, we can use another bit to track
   // whether it's truly variadic or not.
-  return getInfo(*this).OptArgs == 15;
+  return getInfo().OptArgs == 15;
 }
Index: clang/lib/Basic/Attributes.cpp
===================================================================
--- clang/lib/Basic/Attributes.cpp
+++ clang/lib/Basic/Attributes.cpp
@@ -36,10 +36,14 @@
 }
 
 static StringRef
-normalizeAttrScopeName(StringRef ScopeName,
+normalizeAttrScopeName(const IdentifierInfo *Scope,
                        AttributeCommonInfo::Syntax SyntaxUsed) {
+  if (!Scope)
+    return "";
+
   // Normalize the "__gnu__" scope name to be "gnu" and the "_Clang" scope name
   // to be "clang".
+  StringRef ScopeName = Scope->getName();
   if (SyntaxUsed == AttributeCommonInfo::AS_CXX11 ||
       SyntaxUsed == AttributeCommonInfo::AS_C2x) {
     if (ScopeName == "__gnu__")
@@ -50,7 +54,7 @@
   return ScopeName;
 }
 
-static StringRef normalizeAttrName(StringRef AttrName,
+static StringRef normalizeAttrName(const IdentifierInfo *Name,
                                    StringRef NormalizedScopeName,
                                    AttributeCommonInfo::Syntax SyntaxUsed) {
   // Normalize the attribute name, __foo__ becomes foo. This is only allowable
@@ -61,6 +65,7 @@
         SyntaxUsed == AttributeCommonInfo::AS_C2x) &&
        (NormalizedScopeName.empty() || NormalizedScopeName == "gnu" ||
         NormalizedScopeName == "clang"));
+  StringRef AttrName = Name->getName();
   if (ShouldNormalize && AttrName.size() >= 4 && AttrName.startswith("__") &&
       AttrName.endswith("__"))
     AttrName = AttrName.slice(2, AttrName.size() - 2);
@@ -74,35 +79,41 @@
 
 #include "clang/Sema/AttrParsedAttrKinds.inc"
 
-AttributeCommonInfo::Kind
-AttributeCommonInfo::getParsedKind(const IdentifierInfo *Name,
-                                   const IdentifierInfo *ScopeName,
-                                   Syntax SyntaxUsed) {
-  StringRef AttrName = Name->getName();
-
-  SmallString<64> FullName;
-  if (ScopeName)
-    FullName += normalizeAttrScopeName(ScopeName->getName(), SyntaxUsed);
-
-  AttrName = normalizeAttrName(AttrName, FullName, SyntaxUsed);
+static SmallString<64> normalizeName(const IdentifierInfo *Name,
+                                     const IdentifierInfo *Scope,
+                                     AttributeCommonInfo::Syntax SyntaxUsed) {
+  StringRef ScopeName = normalizeAttrScopeName(Scope, SyntaxUsed);
+  StringRef AttrName = normalizeAttrName(Name, ScopeName, SyntaxUsed);
 
   // Ensure that in the case of C++11 attributes, we look for '::foo' if it is
   // unscoped.
-  if (ScopeName || SyntaxUsed == AS_CXX11 || SyntaxUsed == AS_C2x)
+  SmallString<64> FullName = ScopeName;
+  if (Scope || SyntaxUsed == AttributeCommonInfo::AS_CXX11 ||
+      SyntaxUsed == AttributeCommonInfo::AS_C2x)
     FullName += "::";
   FullName += AttrName;
 
-  return ::getAttrKind(FullName, SyntaxUsed);
+  return FullName;
+}
+
+AttributeCommonInfo::Kind
+AttributeCommonInfo::getParsedKind(const IdentifierInfo *Name,
+                                   const IdentifierInfo *ScopeName,
+                                   Syntax SyntaxUsed) {
+  return ::getAttrKind(normalizeName(Name, ScopeName, SyntaxUsed), SyntaxUsed);
+}
+
+std::string AttributeCommonInfo::getFullName() const {
+  return static_cast<std::string>(
+      normalizeName(getAttrName(), getScopeName(), getSyntax()));
 }
 
 unsigned AttributeCommonInfo::calculateAttributeSpellingListIndex() const {
   // Both variables will be used in tablegen generated
   // attribute spell list index matching code.
   auto Syntax = static_cast<AttributeCommonInfo::Syntax>(getSyntax());
-  StringRef Scope =
-      getScopeName() ? normalizeAttrScopeName(getScopeName()->getName(), Syntax)
-                     : "";
-  StringRef Name = normalizeAttrName(getAttrName()->getName(), Scope, Syntax);
+  StringRef Scope = normalizeAttrScopeName(getScopeName(), Syntax);
+  StringRef Name = normalizeAttrName(getAttrName(), Scope, Syntax);
 
 #include "clang/Sema/AttrSpellingListIndex.inc"
 }
Index: clang/include/clang/Sema/ParsedAttr.h
===================================================================
--- clang/include/clang/Sema/ParsedAttr.h
+++ clang/include/clang/Sema/ParsedAttr.h
@@ -24,6 +24,7 @@
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/TinyPtrVector.h"
 #include "llvm/Support/Allocator.h"
+#include "llvm/Support/Registry.h"
 #include "llvm/Support/VersionTuple.h"
 #include <cassert>
 #include <cstddef>
@@ -37,6 +38,72 @@
 class Expr;
 class IdentifierInfo;
 class LangOptions;
+class ParsedAttr;
+class Sema;
+
+struct ParsedAttrInfo {
+  /// Corresponds to the Kind enum.
+  unsigned AttrKind : 16;
+  /// The number of required arguments of this attribute.
+  unsigned NumArgs : 4;
+  /// The number of optional arguments of this attributes.
+  unsigned OptArgs : 4;
+  /// True if the parsing does not match the semantic content.
+  unsigned HasCustomParsing : 1;
+  /// True if this attribute is only available for certain targets.
+  unsigned IsTargetSpecific : 1;
+  /// True if this attribute applies to types.
+  unsigned IsType : 1;
+  /// True if this attribute applies to statements.
+  unsigned IsStmt : 1;
+  /// True if this attribute has any spellings that are known to gcc.
+  unsigned IsKnownToGCC : 1;
+  /// True if this attribute is supported by #pragma clang attribute.
+  unsigned IsSupportedByPragmaAttribute : 1;
+  /// The syntaxes supported by this attribute and how they're spelled.
+  struct Spelling {
+    AttributeCommonInfo::Syntax Syntax;
+    std::string FullName;
+  };
+  std::vector<Spelling> Spellings;
+
+  ParsedAttrInfo(AttributeCommonInfo::Kind AttrKind =
+                     AttributeCommonInfo::UnknownAttribute)
+      : AttrKind(AttrKind), NumArgs(0), OptArgs(0), HasCustomParsing(0),
+        IsTargetSpecific(0), IsType(0), IsStmt(0), IsKnownToGCC(0),
+        IsSupportedByPragmaAttribute(0) {}
+
+  virtual ~ParsedAttrInfo() = default;
+
+  /// Check if this attribute appertains to D, and issue a diagnostic if not.
+  virtual bool diagAppertainsToDecl(Sema &S, const ParsedAttr &Attr,
+                                    const Decl *D) const {
+    return true;
+  }
+  /// Check if this attribute is allowed by the language we are compiling, and
+  /// issue a diagnostic if not.
+  virtual bool diagLangOpts(Sema &S, const ParsedAttr &Attr) const {
+    return true;
+  }
+  /// Check if this attribute is allowed when compiling for the given target.
+  virtual bool existsInTarget(const TargetInfo &Target) const {
+    return true;
+  }
+  /// Convert the spelling index of Attr to a semantic spelling enum value.
+  virtual unsigned
+  spellingIndexToSemanticSpelling(const ParsedAttr &Attr) const {
+    return UINT_MAX;
+  }
+  /// Populate Rules with the match rules of this attribute.
+  virtual void getPragmaAttributeMatchRules(
+      llvm::SmallVectorImpl<std::pair<attr::SubjectMatchRule, bool>> &Rules,
+      const LangOptions &LangOpts) const {
+  }
+
+  static const ParsedAttrInfo &get(const AttributeCommonInfo &A);
+};
+
+typedef llvm::Registry<ParsedAttrInfo> ParsedAttrInfoRegistry;
 
 /// Represents information about a change in availability for
 /// an entity, which is part of the encoding of the 'availability'
@@ -181,6 +248,8 @@
 
   const Expr *MessageExpr;
 
+  const ParsedAttrInfo &Info;
+
   ArgsUnion *getArgsBuffer() { return getTrailingObjects<ArgsUnion>(); }
   ArgsUnion const *getArgsBuffer() const {
     return getTrailingObjects<ArgsUnion>();
@@ -207,7 +276,8 @@
         EllipsisLoc(ellipsisLoc), NumArgs(numArgs), Invalid(false),
         UsedAsTypeAttr(false), IsAvailability(false),
         IsTypeTagForDatatype(false), IsProperty(false), HasParsedType(false),
-        HasProcessingCache(false), IsPragmaClangAttribute(false) {
+        HasProcessingCache(false), IsPragmaClangAttribute(false),
+        Info(ParsedAttrInfo::get(*this)) {
     if (numArgs)
       memcpy(getArgsBuffer(), args, numArgs * sizeof(ArgsUnion));
   }
@@ -225,7 +295,8 @@
         NumArgs(1), Invalid(false), UsedAsTypeAttr(false), IsAvailability(true),
         IsTypeTagForDatatype(false), IsProperty(false), HasParsedType(false),
         HasProcessingCache(false), IsPragmaClangAttribute(false),
-        UnavailableLoc(unavailable), MessageExpr(messageExpr) {
+        UnavailableLoc(unavailable), MessageExpr(messageExpr),
+        Info(ParsedAttrInfo::get(*this)) {
     ArgsUnion PVal(Parm);
     memcpy(getArgsBuffer(), &PVal, sizeof(ArgsUnion));
     new (getAvailabilityData()) detail::AvailabilityData(
@@ -242,7 +313,7 @@
         NumArgs(3), Invalid(false), UsedAsTypeAttr(false),
         IsAvailability(false), IsTypeTagForDatatype(false), IsProperty(false),
         HasParsedType(false), HasProcessingCache(false),
-        IsPragmaClangAttribute(false) {
+        IsPragmaClangAttribute(false), Info(ParsedAttrInfo::get(*this)) {
     ArgsUnion *Args = getArgsBuffer();
     Args[0] = Parm1;
     Args[1] = Parm2;
@@ -259,7 +330,7 @@
         NumArgs(1), Invalid(false), UsedAsTypeAttr(false),
         IsAvailability(false), IsTypeTagForDatatype(true), IsProperty(false),
         HasParsedType(false), HasProcessingCache(false),
-        IsPragmaClangAttribute(false) {
+        IsPragmaClangAttribute(false), Info(ParsedAttrInfo::get(*this)) {
     ArgsUnion PVal(ArgKind);
     memcpy(getArgsBuffer(), &PVal, sizeof(ArgsUnion));
     detail::TypeTagForDatatypeData &ExtraData = getTypeTagForDatatypeDataSlot();
@@ -277,7 +348,7 @@
         NumArgs(0), Invalid(false), UsedAsTypeAttr(false),
         IsAvailability(false), IsTypeTagForDatatype(false), IsProperty(false),
         HasParsedType(true), HasProcessingCache(false),
-        IsPragmaClangAttribute(false) {
+        IsPragmaClangAttribute(false), Info(ParsedAttrInfo::get(*this)) {
     new (&getTypeBuffer()) ParsedType(typeArg);
   }
 
@@ -291,7 +362,7 @@
         NumArgs(0), Invalid(false), UsedAsTypeAttr(false),
         IsAvailability(false), IsTypeTagForDatatype(false), IsProperty(true),
         HasParsedType(false), HasProcessingCache(false),
-        IsPragmaClangAttribute(false) {
+        IsPragmaClangAttribute(false), Info(ParsedAttrInfo::get(*this)) {
     new (&getPropertyDataBuffer()) detail::PropertyData(getterId, setterId);
   }
 
@@ -534,7 +605,10 @@
     }
   }
 
-  AttributeCommonInfo::Kind getKind() const { return getParsedKind(); }
+  AttributeCommonInfo::Kind getKind() const {
+    return AttributeCommonInfo::Kind(Info.AttrKind);
+  }
+  const ParsedAttrInfo &getInfo() const { return Info; }
 };
 
 class AttributePool;
Index: clang/include/clang/Basic/AttributeCommonInfo.h
===================================================================
--- clang/include/clang/Basic/AttributeCommonInfo.h
+++ clang/include/clang/Basic/AttributeCommonInfo.h
@@ -134,6 +134,11 @@
   const IdentifierInfo *getScopeName() const { return ScopeName; }
   SourceLocation getScopeLoc() const { return ScopeLoc; }
 
+  /// Gets the full name, which consists of both scope and name and with
+  /// surrounding underscores removed as appropriate (e.g. __gnu__::__attr__
+  /// will be normalized to gnu::attr).
+  std::string getFullName() const;
+
   bool isDeclspecAttribute() const { return SyntaxUsed == AS_Declspec; }
   bool isMicrosoftAttribute() const { return SyntaxUsed == AS_Microsoft; }
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to