[cfe-commits] [PATCH][Review request] - Anonymous union/struct redesign

John McCall rjmccall at apple.com
Wed Nov 17 00:19:03 PST 2010


On Nov 16, 2010, at 11:01 PM, Francois Pichet wrote:
> After this patch is approved, I'll submit another patch for the
> ms-anonymous struct using the same infrastructure.
> After that I think some redesign could be done in SemInit.cpp
> regarding anonymous handling. I didn't do it in this patch because I
> think this patch is already large enough.

Seems reasonable.

@@ -180,6 +181,10 @@
 
   /// \brief Determine whether this declaration is a C++ class member.
   bool isCXXClassMember() const {
+    // IndirectField are always class member.
+    if (isa<IndirectFieldDecl>(this))
+      return true;
+

This isn't correct.  Also, you shouldn't need to modify this method.

+class IndirectFieldDecl : public ValueDecl {
+  llvm::SmallVector<NamedDecl*, 2> Chaining;

You can't use SmallVector in an AST node;  AST nodes are never destructed.
It needs to be an array allocated by the ASTContext.  Feel free to make
ASTReader a friend.

Whatever actually creates the storage should assert that the length is >= 2.
 
+protected:
+  IndirectFieldDecl(DeclContext *DC, SourceLocation L,
+                    DeclarationName N, QualType T)
+    : ValueDecl(IndirectField, DC, L, N, T) {}
+
+public:
+  static IndirectFieldDecl *Create(ASTContext &C, DeclContext *DC,
+                                   SourceLocation L, IdentifierInfo *Id,
+                                   QualType T);
+  
+  void SetChaining(const llvm::SmallVector<NamedDecl*, 2>& C) { Chaining = C; }

We don't need a setter for this.

+  const llvm::SmallVector<NamedDecl*, 2>& GetChaining() { return Chaining; }

Iterators, please.  chain_begin() and chain_end().

+  FieldDecl *getAnonField() const {
+    assert(Chaining.size() > 0);
+    return dyn_cast<FieldDecl>(Chaining.back());
+  }

This can be cast<FieldDecl>;  the final member will always be a FieldDecl.

Please add an accessor to get the base declaration, i.e. *chain_begin().  It
might also help to have asserting accessors to grab the first member as a
FieldDecl or VarDecl.

       /// \brief A FieldDecl record.
       DECL_FIELD,
+      /// \brief A IndirectFieldDecl record.
+      DECL_INDIRECTFIELD,
       /// \brief A VarDecl record.
       DECL_VAR,

Please put this at the end of the enum;  we've tried to keep this numbering
consistent, just in case it ever matters.

+  llvm::SmallVector<NamedDecl *, 2> Chaining;
+  Chaining.reserve(NumParams);
+  for (unsigned I = 0; I != NumParams; ++I)
+    Chaining.push_back(cast<NamedDecl>(Importer.Import(D->GetChaining()[I])));

Importer.Import can fail;  please test for null returns.

+++ lib/Sema/SemaDecl.cpp	(working copy)

+        
+        llvm::SmallVector<NamedDecl*, 2> ChainingCopy = Chaining;
+        ChainingCopy.push_back(*F);

You can just push *F onto Chaining here and then pop it after
IndirectFieldDecl::Create returns.  Similarly for the recursive case.

@@ -1920,6 +1934,8 @@
         }
       } else if (isa<AccessSpecDecl>(*Mem)) {
         // Any access specifier is fine.
+      } else if (isa<IndirectFieldDecl>(*Mem)) {
+        // Any access specifier is fine.

Fix the comment, please.

+++ lib/Sema/SemaDeclCXX.cpp	(working copy)
@@ -1067,11 +1067,16 @@
     FieldDecl *Member = 0;
     DeclContext::lookup_result Result
       = ClassDecl->lookup(MemberOrBase);
-    if (Result.first != Result.second)
+    if (Result.first != Result.second) {
       Member = dyn_cast<FieldDecl>(*Result.first);
+    
+	  // Handle anonymous union case.
+	  if (!Member)
+      if (IndirectFieldDecl* IndirectField
+          = dyn_cast<IndirectFieldDecl>(*Result.first))
+        Member = IndirectField->getAnonField();
+  }
 
-    // FIXME: Handle members of an anonymous union.
-

I think this would be cleaner if we built the member initializer with an
IndirectFieldDecl*, but we can fix that in a later patch.

@@ -2599,15 +2604,21 @@
     //   In addition, if class T has a user-declared constructor (12.1), every 
     //   non-static data member of class T shall have a name different from T.
     for (DeclContext::lookup_result R = Record->lookup(Record->getDeclName());
-         R.first != R.second; ++R.first)
+         R.first != R.second; ++R.first) {
       if (FieldDecl *Field = dyn_cast<FieldDecl>(*R.first)) {
-        if (Record->hasUserDeclaredConstructor() ||
-            !Field->getDeclContext()->Equals(Record)) {
+        if (Record->hasUserDeclaredConstructor()) {
+         Diag(Field->getLocation(), diag::err_member_name_of_class)
+            << Field->getDeclName();
+          break;
+        }
+      }
+      else if (IndirectFieldDecl *Field =
+	             dyn_cast<IndirectFieldDecl>(*R.first)) {
         Diag(Field->getLocation(), diag::err_member_name_of_class)
           << Field->getDeclName();

This can be
  NamedDecl *D = *R.first;
  if (isa<FieldDecl>(D) || isa<IndirectFieldDecl>(D)) {
    ...
  }

If you find yourself making this check a lot, feel free to add a method to
Decl like isAnyFieldDecl().

-        break;
+	      break;

Watch the tabs.

+++ lib/Sema/SemaExpr.cpp	(working copy)

+VarDecl *Sema::BuildAnonymousStructUnionMemberPath(IndirectFieldDecl *Field,
                                    llvm::SmallVectorImpl<FieldDecl *> &Path) {

I'm not convinced this method needs to exist anymore, but if it does:

+    if (i == 0 && dyn_cast<VarDecl>(Field->GetChaining()[i]))
+      BaseObject = cast<VarDecl>(Field->GetChaining()[i]);
+    else if (FieldDecl *F = dyn_cast<FieldDecl>(Field->GetChaining()[i]))
+      Path.insert(Path.begin(), F);    
+    else
+      llvm_unreachable(0);

Please walk the chain backwards instead of repeatedly inserting at the
front of a vector.  Also, this code will be much plainer if you pull the check
for an initial var out of the loop.

+    
+    if (dyn_cast<IndirectFieldDecl>(D))
+      return IMA_AnonymousMember;
+

isa<>, please, but note:

-
-      // If this is a member of an anonymous record, move out to the
-      // innermost non-anonymous struct or union.  If there isn't one,
-      // that's a special case.
-      while (R->isAnonymousStructOrUnion()) {
-        R = dyn_cast<CXXRecordDecl>(R->getParent());
-        if (!R) return IMA_AnonymousMember;
-      }

This logic only returns IMA_AnonymousMember for non-class-members.
But we don't actually end up in this method at all in that case anymore,
so IMA_AnonymousMember can just disappear.

Instead of trying to redirect non-class IndirectFieldDecls into
BuildPossibleImplicitMemberExpr, it should be fine for just have BuildDeclarationNameExpr
(the override taking a single declaration) test for IndirectFieldDecl
and call BuildAnonymousStructUnionMemberReference.

John.



More information about the cfe-commits mailing list