[cfe-commits] r100923 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.td lib/Sema/SemaDeclCXX.cpp test/SemaCXX/class-base-member-init.cpp test/SemaCXX/constructor-initializer.cpp test/SemaCXX/warn-reorder-ctor-initialization.cpp

John McCall rjmccall at apple.com
Sat Apr 10 02:28:51 PDT 2010


Author: rjmccall
Date: Sat Apr 10 04:28:51 2010
New Revision: 100923

URL: http://llvm.org/viewvc/llvm-project?rev=100923&view=rev
Log:
Diagnose more cases of initializing distinct members of an anonymous union
member.  Use a better diagnostic for this case.  Also fix a bug with nested
anonymous structs/unions for -Wreorder;  this last was PR6575.


Modified:
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
    cfe/trunk/test/SemaCXX/class-base-member-init.cpp
    cfe/trunk/test/SemaCXX/constructor-initializer.cpp
    cfe/trunk/test/SemaCXX/warn-reorder-ctor-initialization.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=100923&r1=100922&r2=100923&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Sat Apr 10 04:28:51 2010
@@ -2461,10 +2461,11 @@
 def err_only_constructors_take_base_inits : Error<
   "only constructors take base initializers">;
 
-def error_multiple_mem_initialization : Error <
-  "multiple initializations given for non-static member '%0'">;
-
-def error_multiple_base_initialization : Error <
+def err_multiple_mem_initialization : Error <
+  "multiple initializations given for non-static member %0">;
+def err_multiple_mem_union_initialization : Error <
+  "initializing multiple members of anonymous union">;
+def err_multiple_base_initialization : Error <
   "multiple initializations given for base %0">;
 
 def err_mem_init_not_member_or_class : Error<

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=100923&r1=100922&r2=100923&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Sat Apr 10 04:28:51 2010
@@ -1660,11 +1660,20 @@
   if (MemberMaybeAnon && Field->isAnonymousStructOrUnion())
     Field = Member->getAnonUnionMember();
   
-  // If the field is a member of an anonymous union, we use record decl of the
-  // union as the key.
+  // If the field is a member of an anonymous struct or union, our key
+  // is the anonymous record decl that's a direct child of the class.
   RecordDecl *RD = Field->getParent();
-  if (RD->isAnonymousStructOrUnion() && RD->isUnion())
+  if (RD->isAnonymousStructOrUnion()) {
+    while (true) {
+      RecordDecl *Parent = cast<RecordDecl>(RD->getDeclContext());
+      if (Parent->isAnonymousStructOrUnion())
+        RD = Parent;
+      else
+        break;
+    }
+      
     return static_cast<void *>(RD);
+  }
 
   return static_cast<void *>(Field);
 }
@@ -1754,6 +1763,71 @@
   }
 }
 
+namespace {
+bool CheckRedundantInit(Sema &S,
+                        CXXBaseOrMemberInitializer *Init,
+                        CXXBaseOrMemberInitializer *&PrevInit) {
+  if (!PrevInit) {
+    PrevInit = Init;
+    return false;
+  }
+
+  if (FieldDecl *Field = Init->getMember())
+    S.Diag(Init->getSourceLocation(),
+           diag::err_multiple_mem_initialization)
+      << Field->getDeclName()
+      << Init->getSourceRange();
+  else {
+    Type *BaseClass = Init->getBaseClass();
+    assert(BaseClass && "neither field nor base");
+    S.Diag(Init->getSourceLocation(),
+           diag::err_multiple_base_initialization)
+      << QualType(BaseClass, 0)
+      << Init->getSourceRange();
+  }
+  S.Diag(PrevInit->getSourceLocation(), diag::note_previous_initializer)
+    << 0 << PrevInit->getSourceRange();
+
+  return true;
+}
+
+typedef std::pair<NamedDecl *, CXXBaseOrMemberInitializer *> UnionEntry;
+typedef llvm::DenseMap<RecordDecl*, UnionEntry> RedundantUnionMap;
+
+bool CheckRedundantUnionInit(Sema &S,
+                             CXXBaseOrMemberInitializer *Init,
+                             RedundantUnionMap &Unions) {
+  FieldDecl *Field = Init->getMember();
+  RecordDecl *Parent = Field->getParent();
+  if (!Parent->isAnonymousStructOrUnion())
+    return false;
+
+  NamedDecl *Child = Field;
+  do {
+    if (Parent->isUnion()) {
+      UnionEntry &En = Unions[Parent];
+      if (En.first && En.first != Child) {
+        S.Diag(Init->getSourceLocation(),
+               diag::err_multiple_mem_union_initialization)
+          << Field->getDeclName()
+          << Init->getSourceRange();
+        S.Diag(En.second->getSourceLocation(), diag::note_previous_initializer)
+          << 0 << En.second->getSourceRange();
+        return true;
+      } else if (!En.first) {
+        En.first = Child;
+        En.second = Init;
+      }
+    }
+
+    Child = Parent;
+    Parent = cast<RecordDecl>(Parent->getDeclContext());
+  } while (Parent->isAnonymousStructOrUnion());
+
+  return false;
+}
+}
+
 /// ActOnMemInitializers - Handle the member initializers for a constructor.
 void Sema::ActOnMemInitializers(DeclPtrTy ConstructorDecl,
                                 SourceLocation ColonLoc,
@@ -1774,34 +1848,29 @@
   
   CXXBaseOrMemberInitializer **MemInits =
     reinterpret_cast<CXXBaseOrMemberInitializer **>(meminits);
-  
+
+  // Mapping for the duplicate initializers check.
+  // For member initializers, this is keyed with a FieldDecl*.
+  // For base initializers, this is keyed with a Type*.
   llvm::DenseMap<void*, CXXBaseOrMemberInitializer *> Members;
+
+  // Mapping for the inconsistent anonymous-union initializers check.
+  RedundantUnionMap MemberUnions;
+
   bool HadError = false;
   for (unsigned i = 0; i < NumMemInits; i++) {
-    CXXBaseOrMemberInitializer *Member = MemInits[i];
+    CXXBaseOrMemberInitializer *Init = MemInits[i];
 
-    void *KeyToMember = GetKeyForMember(Context, Member);
-    CXXBaseOrMemberInitializer *&PrevMember = Members[KeyToMember];
-    if (!PrevMember) {
-      PrevMember = Member;
-      continue;
+    if (Init->isMemberInitializer()) {
+      FieldDecl *Field = Init->getMember();
+      if (CheckRedundantInit(*this, Init, Members[Field]) ||
+          CheckRedundantUnionInit(*this, Init, MemberUnions))
+        HadError = true;
+    } else {
+      void *Key = GetKeyForBase(Context, QualType(Init->getBaseClass(), 0));
+      if (CheckRedundantInit(*this, Init, Members[Key]))
+        HadError = true;
     }
-    if (FieldDecl *Field = Member->getMember())
-      Diag(Member->getSourceLocation(),
-           diag::error_multiple_mem_initialization)
-        << Field->getNameAsString()
-        << Member->getSourceRange();
-    else {
-      Type *BaseClass = Member->getBaseClass();
-      assert(BaseClass && "ActOnMemInitializers - neither field or base");
-      Diag(Member->getSourceLocation(),
-           diag::error_multiple_base_initialization)
-        << QualType(BaseClass, 0)
-        << Member->getSourceRange();
-    }
-    Diag(PrevMember->getSourceLocation(), diag::note_previous_initializer)
-      << 0;
-    HadError = true;
   }
 
   if (HadError)

Modified: cfe/trunk/test/SemaCXX/class-base-member-init.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/class-base-member-init.cpp?rev=100923&r1=100922&r2=100923&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/class-base-member-init.cpp (original)
+++ cfe/trunk/test/SemaCXX/class-base-member-init.cpp Sat Apr 10 04:28:51 2010
@@ -51,3 +51,26 @@
       t(2) { } // expected-error {{multiple initializations given for non-static member 't'}}
   };
 }
+
+namespace test4 {
+  class A {
+    union {
+      struct {
+        int a;
+        int b;
+      };
+
+      int c;
+
+      union {
+        int d;
+        int e;
+      };
+    };
+
+    A(char _) : a(0), b(0) {}
+    A(short _) : a(0), c(0) {} // expected-error {{initializing multiple members of anonymous union}} expected-note {{previous initialization is here}}
+    A(int _) : d(0), e(0) {} // expected-error {{initializing multiple members of anonymous union}} expected-note {{previous initialization is here}}
+    A(long _) : a(0), d(0) {} // expected-error {{initializing multiple members of anonymous union}} expected-note {{previous initialization is here}}
+  };
+}

Modified: cfe/trunk/test/SemaCXX/constructor-initializer.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/constructor-initializer.cpp?rev=100923&r1=100922&r2=100923&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/constructor-initializer.cpp (original)
+++ cfe/trunk/test/SemaCXX/constructor-initializer.cpp Sat Apr 10 04:28:51 2010
@@ -73,8 +73,9 @@
   union { int a; char* p; };
   union { int b; double d; };
 
-  U() :  a(1), p(0), d(1.0)  {} // expected-error {{multiple initializations given for non-static member 'p'}} \
-                        // expected-note {{previous initialization is here}}
+  U() :  a(1), // expected-note {{previous initialization is here}}
+         p(0), // expected-error {{initializing multiple members of anonymous union}}
+         d(1.0)  {}
 };
 
 struct V {};

Modified: cfe/trunk/test/SemaCXX/warn-reorder-ctor-initialization.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/warn-reorder-ctor-initialization.cpp?rev=100923&r1=100922&r2=100923&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/warn-reorder-ctor-initialization.cpp (original)
+++ cfe/trunk/test/SemaCXX/warn-reorder-ctor-initialization.cpp Sat Apr 10 04:28:51 2010
@@ -108,3 +108,15 @@
     Foo y;
   };
 }
+
+// PR6575: this should not crash
+namespace test3 {
+  struct MyClass {
+    MyClass() : m_int(0) {}
+    union {
+      struct {
+        int m_int;
+      };
+    };
+  };
+}





More information about the cfe-commits mailing list