[cfe-commits] [PATCH] Automatically generate Attr

Douglas Gregor dgregor at apple.com
Tue Aug 17 22:29:17 PDT 2010


Hi Sean,

On Aug 14, 2010, at 2:50 AM, Sean Hunt wrote:
> This is a freakin' huge patch, the primary purpose of which is to make it so that subclasses of Attr are generated automagically by TableGen.
> 
> A few other changes slipped through from my main working branch and didn't seem like undoing (such as renaming Sema::MergeAttributes to Sema::MergeDeclAttributeS) since they will get done anyways in the future.
> 
> The most noticeable other change is in the way that attributes are stored; they are now stored in SmallVectors rather than as linked lists. I can't recall exactly why this is at the moment, but Doug Gregor and I had a long talk where we decided it was optimal, so assuming we were both sane at the time, it is the correct thing to do.*

I really wish I remembered this discussion :)

SmallVectors do make it easier to copy attributes around and keep the order right, and they could improve iteration performance (although I doubt it will matter).

> A nice extra interface was added to Decl as well as generally - the specific_attr_iterator. This is an iterator to iterate over a specific type of attr, much as specific_decl_iterator already does elsewhere.

Yep, good stuff.

> Some other notes about newly-generated attribute classes:
> 
> - The constructor arguments are a SourceLocation and a Context&,
>   followed by the attributes arguments in the order that they were
>   defined in Attr.td
> 
> - Every argument in Attr.td has an appropriate accessor, and there are
>   sometimes a few extra ones.
> 
> Also, it just occurs to me I've forgotten to add CMake build commands for the three new .inc files; it's very late so I'll hold off on those for the final version.

Okay, we'll want those in there when you commit, otherwise we'll break some builders (and a couple developers, too).

> One last note about EnumArguments for attributes - I will add an additional flag to specify where the value comes from - the attribute spelling, a string literal, or an identifier. This will come later, when TableGen-enhanced code becomes responsible for the parsing and semantic analysis of attributes.

Okay.

diff --git a/include/clang/AST/Attr.h b/include/clang/AST/Attr.h
index 699fff9..bd06f0f 100644
--- a/include/clang/AST/Attr.h
+++ b/include/clang/AST/Attr.h
@@ -15,8 +15,10 @@
 #define LLVM_CLANG_AST_ATTR_H
 
 #include "llvm/Support/Casting.h"
+#include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringRef.h"
 #include "clang/Basic/AttrKinds.h"
+#include "clang/Basic/SourceLocation.h"
 #include <cassert>
 #include <cstring>
 #include <algorithm>
@@ -27,25 +29,33 @@ namespace clang {
   class IdentifierInfo;
   class ObjCInterfaceDecl;
   class Expr;
+  class FunctionDecl;
+  class TypeSourceInfo;
 }
 
 // Defined in ASTContext.h
 void *operator new(size_t Bytes, clang::ASTContext &C,
-                   size_t Alignment = 16) throw ();
+                   size_t Alignment = 8) throw ();

Why are you changing the alignment here? I don't disagree with the change, but it should be orthogonal to your attributes work.
 
@@ -59,38 +69,36 @@ protected:
     assert(0 && "Attrs cannot be released with regular 'delete'.");
   }
 
+public:
+  // Forward so that the regular new and delete do not hide global ones.
+  void* operator new(size_t Bytes, ASTContext &C,
+                     size_t Alignment = 16) throw() {
+    return ::operator new(Bytes, C, Alignment);
+  }
+  void operator delete(void *Ptr, ASTContext &C,
+                       size_t Alignment = 16) throw() {
+    return ::operator delete(Ptr, C, Alignment);
+  }

... especially when you stuck with 16-byte alignment here :)

diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h
index 3ff38dc..a362765 100644
--- a/include/clang/AST/DeclBase.h
+++ b/include/clang/AST/DeclBase.h
@@ -308,24 +308,52 @@ public:
   }
 
   bool hasAttrs() const { return HasAttrs; }
-  void initAttrs(Attr *attrs);
-  void addAttr(Attr *attr);
-  const Attr *getAttrs() const {
-    if (!HasAttrs) return 0;  // common case, no attributes.
-    return getAttrsImpl();    // Uncommon case, out of line hash lookup.
+  void setAttrs(const AttrVec& Attrs);
+  AttrVec& getAttrs() {
+    return const_cast<AttrVec&>(const_cast<const Decl*>(this)->getAttrs());
   }
+  const AttrVec &getAttrs() const;
   void swapAttrs(Decl *D);
-  void invalidateAttrs();
+  void dropAttrs();
 
-  template<typename T> const T *getAttr() const {
-    for (const Attr *attr = getAttrs(); attr; attr = attr->getNext())
-      if (const T *V = dyn_cast<T>(attr))
-        return V;
-    return 0;
+  void addAttr(Attr *A) {
+    if (hasAttrs())
+      getAttrs().push_back(A);
+    else
+      setAttrs(AttrVec(1, A));
   }
 
+  typedef AttrVec::const_iterator attr_iterator;
+
+  // FIXME: Do not rely on iterators having comparable singular values.
+  //        Note that this should error out if they do not.
+  attr_iterator attr_begin() const {
+    return hasAttrs() ? getAttrs().begin() : 0;
+  }
+  attr_iterator attr_end() const {
+    return hasAttrs() ? getAttrs().end() : 0;
+  }
+
+  template <typename T>
+  specific_attr_iterator<T> specific_attr_begin() const {
+    return specific_attr_iterator<T>(attr_begin());
+  }
+  template <typename T>
+  specific_attr_iterator<T> specific_attr_end() const {
+    return specific_attr_iterator<T>(attr_end());
+  }


A *true* C++ geek would name these attr_begin/attr_end, and dare his colleagues to call it "ambiguous" :)

--- a/include/clang/Basic/Attr.td
+++ b/include/clang/Basic/Attr.td
@@ -224,7 +228,7 @@ def IBOutlet : Attr {
 
 def IBOutletCollection : Attr {
   let Spellings = ["iboutletcollection"];
-  let Args = [ObjCInterfaceArgument<"Class">];
+  let Args = [ObjCInterfaceArgument<"Interface">];
 }
 
Note that this attribute got a type argument in Clang r111275.

@@ -290,26 +302,18 @@ def Override : Attr {
   let Spellings = ["override"];
   let Subjects = [CXXVirtualMethod];
   let Namespaces = ["", "std"];
-  let DoNotEmit = 0;
 }
 
 def Overloadable : Attr {
   let Spellings = ["overloadable"];
 }
 
-def OwnershipReturns : Attr {
-  let Spellings = ["ownership_returns"];
-  let Args = [StringArgument<"Module">, IntArgument<"SizeIdx">];
-}
-
-def OwnershipTakes : Attr {
-  let Spellings = ["ownership_takes"];
-  let Args = [StringArgument<"Module">, IntArgument<"PtrIdx">];
-}
-
-def OwnershipHolds : Attr {
-  let Spellings = ["ownership_holds"];
-  let Args = [StringArgument<"Module">, IntArgument<"PtrIdx">];
+def Ownership : Attr {
+  let Spellings = ["ownership_holds", "ownership_returns", "ownership_takes"];
+  let Args = [EnumArgument<"OwnKind", "OwnershipKind",
+                    ["ownership_holds", "ownership_returns", "ownership_takes"],
+                    ["Holds", "Returns", "Takes"]>,
+              StringArgument<"Module">, VariadicUnsignedArgument<"Args">];
 }

Very interesting! Any particular reason you wanted to combine these into a single attribute?
... ah, it actually does seem to clean up some of the uses.

--- a/include/clang/Frontend/PCHReader.h
+++ b/include/clang/Frontend/PCHReader.h
@@ -908,7 +908,7 @@ public:
   CXXTemporary *ReadCXXTemporary(const RecordData &Record, unsigned &Idx);
       
   /// \brief Reads attributes from the current stream position.
-  Attr *ReadAttributes(llvm::BitstreamCursor &DeclsCursor);
+  AttrVec ReadAttributes(llvm::BitstreamCursor &DeclsCursor);
 
   /// \brief Reads a statement.
   Stmt *ReadStmt(llvm::BitstreamCursor &Cursor);

Returning an AttrVec by-value could mean copying a bunch of data. Why not pass one in by reference?

--- a/include/clang/Frontend/PCHWriter.h
+++ b/include/clang/Frontend/PCHWriter.h
@@ -281,7 +281,7 @@ private:
   void WriteSelectors(Sema &SemaRef);
   void WriteReferencedSelectorsPool(Sema &SemaRef);
   void WriteIdentifierTable(Preprocessor &PP);
-  void WriteAttributeRecord(const Attr *Attr);
+  void WriteAttributeRecord(const AttrVec Attrs);
   void WriteDeclUpdateBlock();
 
   unsigned ParmVarDeclAbbrev;

Pass by reference-to-const, please!

--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -502,8 +502,7 @@ const llvm::fltSemantics &ASTContext::getFloatTypeSemantics(QualType T) const {
 CharUnits ASTContext::getDeclAlign(const Decl *D, bool RefAsPointee) {
   unsigned Align = Target.getCharWidth();
 
-  if (const AlignedAttr* AA = D->getAttr<AlignedAttr>())
-    Align = std::max(Align, AA->getMaxAlignment());
+  Align = std::max(Align, D->getMaxAlignment());
 
   if (const ValueDecl *VD = dyn_cast<ValueDecl>(D)) {
     QualType T = VD->getType();

This would have been a worthy cleanup on its own, but it's okay to commit with the rest of the patch.

I think this is a *great* cleanup of attribute class definition and (de-)serialization. Most of the comments above are minor, so please go ahead and commit when you've managed to address them.

	- Doug





More information about the cfe-commits mailing list