This patch implements the restrictions on union members detailed in [class.union]p1, analyzing code like this:

class Dtor {
~Dtor() { abort(); }
};
union U3 {
struct s6 : Dtor {
} m6;
};

to produce errors like this:

test/CXX/class/class.union/p1.cpp:79:5: error: union member 'm6' has a non-trivial destructor
} m6;
^
test/CXX/class/class.union/p1.cpp:78:15: note: because type 'struct U3::s6' has a base class with a non-trivial destructor
struct s6 : Dtor {
^
test/CXX/class/class.union/p1.cpp:30:3: note: because type 'class Dtor' has a user-declared destructor
~Dtor() { abort(); }
^

This resolves bug #3404, as well as paving the way for implementing type traits based on having trivial copy constructors &c. which we'll be wanting shortly.

I went ahead and implemented a few bits of convenient API — in particular, CXXRecordDecl::method_iterator and ::ctor_iterator — and fixed a few mildly-related bugs, including a very small memory leak which happened on every derivation from a virtual base class. If people want me to tease these out into a separate patch, that's not a problem.

John.
Index: test/CXX/class/class.union/p1.cpp
===================================================================
--- test/CXX/class/class.union/p1.cpp   (revision 0)
+++ test/CXX/class/class.union/p1.cpp   (revision 0)
@@ -0,0 +1,105 @@
+// RUN: clang-cc -fsyntax-only -verify %s 
+
+void abort();
+
+class Okay {
+  int a_;
+};
+
+class Virtual {
+  virtual void foo() { abort(); } // expected-note 3 {{because type 'class 
Virtual' has a virtual method}}
+};
+
+class VirtualBase : virtual Okay { // expected-note 3 {{because type 'class 
VirtualBase' has a virtual base class}}
+};
+
+class Ctor {
+  Ctor() { abort(); } // expected-note 3 {{because type 'class Ctor' has a 
user-declared constructor}}
+};
+
+class CopyCtor {
+  CopyCtor(CopyCtor &cc) { abort(); } // expected-note 3 {{because type 'class 
CopyCtor' has a user-declared copy constructor}}
+};
+
+// FIXME: this should eventually trigger on the operator's declaration line
+class CopyAssign { // expected-note 3 {{because type 'class CopyAssign' has a 
user-declared copy assignment operator}}
+  CopyAssign& operator=(CopyAssign& CA) { abort(); }
+};
+
+class Dtor {
+  ~Dtor() { abort(); } // expected-note 3 {{because type 'class Dtor' has a 
user-declared destructor}}
+};
+
+union U1 {
+  Virtual v; // expected-error {{union member 'v' has a non-trivial copy 
constructor}}
+  VirtualBase vbase; // expected-error {{union member 'vbase' has a 
non-trivial copy constructor}}
+  Ctor ctor; // expected-error {{union member 'ctor' has a non-trivial 
constructor}}
+  CopyCtor copyctor; // expected-error {{union member 'copyctor' has a 
non-trivial copy constructor}}
+  CopyAssign copyassign; // expected-error {{union member 'copyassign' has a 
non-trivial copy assignment operator}}
+  Dtor dtor; // expected-error {{union member 'dtor' has a non-trivial 
destructor}}
+  Okay okay;
+};
+
+union U2 {
+  struct {
+    Virtual v; // expected-note {{because type 'struct U2::<anonymous>' has a 
member with a non-trivial copy constructor}}
+  } m1; // expected-error {{union member 'm1' has a non-trivial copy 
constructor}}
+  struct {
+    VirtualBase vbase; // expected-note {{because type 'struct 
U2::<anonymous>' has a member with a non-trivial copy constructor}}
+  } m2; // expected-error {{union member 'm2' has a non-trivial copy 
constructor}}
+  struct {
+    Ctor ctor; // expected-note {{because type 'struct U2::<anonymous>' has a 
member with a non-trivial constructor}}
+  } m3; // expected-error {{union member 'm3' has a non-trivial constructor}}
+  struct {
+    CopyCtor copyctor; // expected-note {{because type 'struct 
U2::<anonymous>' has a member with a non-trivial copy constructor}}
+  } m4; // expected-error {{union member 'm4' has a non-trivial copy 
constructor}}
+  struct {
+    CopyAssign copyassign; // expected-note {{because type 'struct 
U2::<anonymous>' has a member with a non-trivial copy assignment operator}}
+  } m5; // expected-error {{union member 'm5' has a non-trivial copy 
assignment operator}}
+  struct {
+    Dtor dtor; // expected-note {{because type 'struct U2::<anonymous>' has a 
member with a non-trivial destructor}}
+  } m6; // expected-error {{union member 'm6' has a non-trivial destructor}}
+  struct {
+    Okay okay;
+  } m7;
+};
+
+union U3 {
+  struct s1 : Virtual { // expected-note {{because type 'struct U3::s1' has a 
base class with a non-trivial copy constructor}}
+  } m1; // expected-error {{union member 'm1' has a non-trivial copy 
constructor}}
+  struct s2 : VirtualBase { // expected-note {{because type 'struct U3::s2' 
has a base class with a non-trivial copy constructor}}
+  } m2; // expected-error {{union member 'm2' has a non-trivial copy 
constructor}}
+  struct s3 : Ctor { // expected-note {{because type 'struct U3::s3' has a 
base class with a non-trivial constructor}}
+  } m3; // expected-error {{union member 'm3' has a non-trivial constructor}}
+  struct s4 : CopyCtor { // expected-note {{because type 'struct U3::s4' has a 
base class with a non-trivial copy constructor}}
+  } m4; // expected-error {{union member 'm4' has a non-trivial copy 
constructor}}
+  struct s5 : CopyAssign { // expected-note {{because type 'struct U3::s5' has 
a base class with a non-trivial copy assignment operator}}
+  } m5; // expected-error {{union member 'm5' has a non-trivial copy 
assignment operator}}
+  struct s6 : Dtor { // expected-note {{because type 'struct U3::s6' has a 
base class with a non-trivial destructor}}
+  } m6; // expected-error {{union member 'm6' has a non-trivial destructor}}
+  struct s7 : Okay {
+  } m7;
+};
+
+template <class A, class B> struct Either {
+  bool tag;
+  union {
+    A a;
+    B b;
+  };
+
+  Either(A& a) : tag(true), a(a) {}
+  Either(B& b) : tag(false), b(b) {}
+};
+
+/* FIXME: this should work, but crashes in template code.
+void fred() {
+  Either<int,Virtual> virt(0);
+  Either<int,VirtualBase> vbase(0);
+  Either<int,Ctor> ctor(0);
+  Either<int,CopyCtor> copyctor(0);
+  Either<int,CopyAssign> copyassign(0);
+  Either<int,Dtor> dtor(0);
+  Either<int,Okay> okay(0);
+}
+ */
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td  (revision 76721)
+++ include/clang/Basic/DiagnosticSemaKinds.td  (working copy)
@@ -339,6 +339,18 @@ def err_implicit_object_parameter_init :
   "cannot initialize object parameter of type %0 with an expression "
   "of type %1">;
 
+def err_illegal_union_member : Error<
+  "union member %0 has a non-trivial %select{constructor|"
+  "copy constructor|copy assignment operator|destructor}1">;
+def note_nontrivial_has_virtual : Note<
+  "because type %0 has a virtual %select{method|base class}1">;
+def note_nontrivial_has_nontrivial : Note<
+  "because type %0 has a %select{member|base class}1 with a non-trivial "
+  "%select{constructor|copy constructor|copy assignment 
operator|destructor}2">;
+def note_nontrivial_user_defined : Note<
+  "because type %0 has a user-declared %select{constructor|copy constructor|"
+  "copy assignment operator|destructor}1">;
+
 def err_different_return_type_for_overriding_virtual_function : Error<
   "virtual function %0 has a different return type (%1) than the "
   "function it overrides (which has return type %2)">;
Index: include/clang/AST/DeclCXX.h
===================================================================
--- include/clang/AST/DeclCXX.h (revision 76721)
+++ include/clang/AST/DeclCXX.h (working copy)
@@ -297,12 +297,51 @@ class CXXRecordDecl : public RecordDecl 
   /// pure virtual function, (that can come from a base class).
   bool Abstract : 1;
   
-  /// HasTrivialConstructor - True when this class has a trivial constructor
+  /// HasTrivialConstructor - True when this class has a trivial constructor.
+  ///
+  /// C++ [class.ctor]p5.  A constructor is trivial if it is an
+  /// implicitly-declared default constructor and if:
+  /// * its class has no virtual functions and no virtual base classes, and
+  /// * all the direct base classes of its class have trivial constructors, and
+  /// * for all the nonstatic data members of its class that are of class type
+  ///   (or array thereof), each such class has a trivial constructor.
   bool HasTrivialConstructor : 1;
   
-  /// HasTrivialDestructor - True when this class has a trivial destructor
-  bool HasTrivialDestructor : 1;
+  /// HasTrivialCopyConstructor - True when this class has a trivial copy
+  /// constructor.
+  ///
+  /// C++ [class.copy]p6.  A copy constructor for class X is trivial
+  /// if it is implicitly declared and if
+  /// * class X has no virtual functions and no virtual base classes, and
+  /// * each direct base class of X has a trivial copy constructor, and
+  /// * for all the nonstatic data members of X that are of class type (or
+  ///   array thereof), each such class type has a trivial copy constructor;
+  /// otherwise the copy constructor is non-trivial.
+  bool HasTrivialCopyConstructor : 1;
+
+  /// HasTrivialCopyAssignment - True when this class has a trivial copy
+  /// assignment operator.
+  ///
+  /// C++ [class.copy]p11.  A copy assignment operator for class X is
+  /// trivial if it is implicitly declared and if
+  /// * class X has no virtual functions and no virtual base classes, and
+  /// * each direct base class of X has a trivial copy assignment operator, and
+  /// * for all the nonstatic data members of X that are of class type (or
+  ///   array thereof), each such class type has a trivial copy assignment
+  ///   operator;
+  /// otherwise the copy assignment operator is non-trivial.
+  bool HasTrivialCopyAssignment : 1;
   
+  /// HasTrivialDestructor - True when this class has a trivial destructor.
+  ///
+  /// C++ [class.dtor]p3.  A destructor is trivial if it is an
+  /// implicitly-declared destructor and if:
+  /// * all of the direct base classes of its class have trivial destructors
+  ///   and
+  /// * for all of the non-static data members of its class that are of class
+  ///   type (or array thereof), each such class has a trivial destructor.
+  bool HasTrivialDestructor : 1;
+
   /// Bases - Base classes of this class.
   /// FIXME: This is wasted space for a union.
   CXXBaseSpecifier *Bases;
@@ -342,11 +381,11 @@ protected:
 
 public:
   /// base_class_iterator - Iterator that traverses the base classes
-  /// of a clas.
+  /// of a class.
   typedef CXXBaseSpecifier*       base_class_iterator;
 
   /// base_class_const_iterator - Iterator that traverses the base
-  /// classes of a clas.
+  /// classes of a class.
   typedef const CXXBaseSpecifier* base_class_const_iterator;
 
   static CXXRecordDecl *Create(ASTContext &C, TagKind TK, DeclContext *DC,
@@ -379,6 +418,28 @@ public:
   base_class_iterator       vbases_end()         { return VBases + NumVBases; }
   base_class_const_iterator vbases_end()   const { return VBases + NumVBases; }
 
+  /// Iterator access to method members.  The method iterator visits
+  /// all method members of the class, including non-instance methods,
+  /// special methods, etc.
+  typedef specific_decl_iterator<CXXMethodDecl> method_iterator;
+  
+  method_iterator method_begin() const {
+    return method_iterator(decls_begin());
+  }
+  method_iterator method_end() const {
+    return method_iterator(decls_end());
+  }
+
+  /// Iterator access to constructor members.
+  typedef specific_decl_iterator<CXXConstructorDecl> ctor_iterator;
+  
+  ctor_iterator ctor_begin() const {
+    return ctor_iterator(decls_begin());
+  }
+  ctor_iterator ctor_end() const {
+    return ctor_iterator(decls_end());
+  }
+
   /// hasConstCopyConstructor - Determines whether this class has a
   /// copy constructor that accepts a const-qualified argument.
   bool hasConstCopyConstructor(ASTContext &Context) const;
@@ -487,6 +548,22 @@ public:
   // (C++ [class.ctor]p5)
   void setHasTrivialConstructor(bool TC) { HasTrivialConstructor = TC; }
   
+  // hasTrivialCopyConstructor - Whether this class has a trivial copy
+  // constructor (C++ [class.copy]p6)
+  bool hasTrivialCopyConstructor() const { return HasTrivialCopyConstructor; }
+  
+  // setHasTrivialCopyConstructor - Set whether this class has a trivial
+  // copy constructor (C++ [class.copy]p6)
+  void setHasTrivialCopyConstructor(bool TC) { HasTrivialCopyConstructor = TC; 
}
+
+  // hasTrivialCopyAssignment - Whether this class has a trivial copy
+  // assignment operator (C++ [class.copy]p11)
+  bool hasTrivialCopyAssignment() const { return HasTrivialCopyAssignment; }
+  
+  // setHasTrivialCopyAssignment - Set whether this class has a
+  // trivial copy assignment operator (C++ [class.copy]p11)
+  void setHasTrivialCopyAssignment(bool TC) { HasTrivialCopyAssignment = TC; }
+
   // hasTrivialDestructor - Whether this class has a trivial destructor
   // (C++ [class.dtor]p3)
   bool hasTrivialDestructor() const { return HasTrivialDestructor; }
Index: include/clang/AST/Decl.h
===================================================================
--- include/clang/AST/Decl.h    (revision 76721)
+++ include/clang/AST/Decl.h    (working copy)
@@ -673,6 +673,7 @@ private:  
   bool HasInheritedPrototype : 1;
   bool HasWrittenPrototype : 1;
   bool IsDeleted : 1;
+  bool IsTrivial : 1; // sunk from CXXMethodDecl
 
   // Move to DeclGroup when it is implemented.
   SourceLocation TypeSpecStartLoc;
@@ -712,8 +713,8 @@ protected:
       ParamInfo(0), Body(),
       SClass(S), IsInline(isInline), C99InlineDefinition(false), 
       IsVirtualAsWritten(false), IsPure(false), HasInheritedPrototype(false), 
-      HasWrittenPrototype(true), IsDeleted(false), TypeSpecStartLoc(TSSL),
-      EndRangeLoc(L), TemplateOrSpecialization() {}
+      HasWrittenPrototype(true), IsDeleted(false), IsTrivial(false),
+      TypeSpecStartLoc(TSSL), EndRangeLoc(L), TemplateOrSpecialization() {}
 
   virtual ~FunctionDecl() {}
   virtual void Destroy(ASTContext& C);
@@ -782,6 +783,13 @@ public:
   bool isPure() const { return IsPure; }
   void setPure(bool P = true) { IsPure = P; }
 
+  /// Whether this function is "trivial" in some specialized C++ senses.
+  /// Can only be true for default constructors, copy constructors,
+  /// copy assignment operators, and destructors.  Not meaningful until
+  /// the class has been fully built by Sema.
+  bool isTrivial() const { return IsTrivial; }
+  void setTrivial(bool IT) { IsTrivial = IT; }
+
   /// \brief Whether this function has a prototype, either because one
   /// was explicitly written or because it was "inherited" by merging
   /// a declaration without a prototype with a declaration that has a
Index: lib/Sema/SemaDeclCXX.cpp
===================================================================
--- lib/Sema/SemaDeclCXX.cpp    (revision 76721)
+++ lib/Sema/SemaDeclCXX.cpp    (working copy)
@@ -400,19 +400,40 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *
     // C++ [class.ctor]p5:
     //   A constructor is trivial if its class has no virtual base classes.
     Class->setHasTrivialConstructor(false);
+
+    // C++ [class.copy]p6:
+    //   A copy constructor is trivial if its class has no virtual base 
classes.
+    Class->setHasTrivialCopyConstructor(false);
+
+    // C++ [class.copy]p11:
+    //   A copy assignment operator is trivial if its class has no virtual
+    //   base classes.
+    Class->setHasTrivialCopyAssignment(false);
   } else {
     // C++ [class.ctor]p5:
     //   A constructor is trivial if all the direct base classes of its 
     //   class have trivial constructors.
-    Class->setHasTrivialConstructor(cast<CXXRecordDecl>(BaseDecl)->
-                                    hasTrivialConstructor());
+    if (!cast<CXXRecordDecl>(BaseDecl)->hasTrivialConstructor())
+      Class->setHasTrivialConstructor(false);
+
+    // C++ [class.copy]p6:
+    //   A copy constructor is trivial if all the direct base classes of its
+    //   class have trivial copy constructors.
+    if (!cast<CXXRecordDecl>(BaseDecl)->hasTrivialCopyConstructor())
+      Class->setHasTrivialCopyConstructor(false);
+
+    // C++ [class.copy]p11:
+    //   A copy assignment operator is trivial if all the direct base classes
+    //   of its class have trivial copy assignment operators.
+    if (!cast<CXXRecordDecl>(BaseDecl)->hasTrivialCopyAssignment())
+      Class->setHasTrivialCopyAssignment(false);
   }
 
   // C++ [class.ctor]p3:
   //   A destructor is trivial if all the direct base classes of its class
   //   have trivial destructors.
-  Class->setHasTrivialDestructor(cast<CXXRecordDecl>(BaseDecl)->
-                                 hasTrivialDestructor());
+  if (!cast<CXXRecordDecl>(BaseDecl)->hasTrivialDestructor())
+    Class->setHasTrivialDestructor(false);
   
   // Create the base specifier.
   // FIXME: Allocate via ASTContext?
@@ -1154,30 +1175,6 @@ void Sema::ActOnFinishCXXMemberSpecifica
   if (RD->isAbstract()) 
     AbstractClassUsageDiagnoser(*this, RD);
     
-  if (RD->hasTrivialConstructor() || RD->hasTrivialDestructor()) {
-    for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end();
-         i != e; ++i) {
-      // All the nonstatic data members must have trivial constructors.
-      QualType FTy = i->getType();
-      while (const ArrayType *AT = Context.getAsArrayType(FTy))
-        FTy = AT->getElementType();
-      
-      if (const RecordType *RT = FTy->getAsRecordType()) {
-        CXXRecordDecl *FieldRD = cast<CXXRecordDecl>(RT->getDecl());
-        
-        if (!FieldRD->hasTrivialConstructor())
-          RD->setHasTrivialConstructor(false);
-        if (!FieldRD->hasTrivialDestructor())
-          RD->setHasTrivialDestructor(false);
-        
-        // If RD has neither a trivial constructor nor a trivial destructor
-        // we don't need to continue checking.
-        if (!RD->hasTrivialConstructor() && !RD->hasTrivialDestructor())
-          break;
-      }
-    }
-  }
-      
   if (!RD->isDependentType())
     AddImplicitlyDeclaredMembersToClass(RD);
 }
@@ -1213,6 +1210,7 @@ void Sema::AddImplicitlyDeclaredMembersT
                                  /*isImplicitlyDeclared=*/true);
     DefaultCon->setAccess(AS_public);
     DefaultCon->setImplicit();
+    DefaultCon->setTrivial(ClassDecl->hasTrivialConstructor());
     ClassDecl->addDecl(DefaultCon);
   }
 
@@ -1283,6 +1281,7 @@ void Sema::AddImplicitlyDeclaredMembersT
                                    /*isImplicitlyDeclared=*/true);
     CopyConstructor->setAccess(AS_public);
     CopyConstructor->setImplicit();
+    CopyConstructor->setTrivial(ClassDecl->hasTrivialCopyConstructor());
 
     // Add the parameter to the constructor.
     ParmVarDecl *FromParam = ParmVarDecl::Create(Context, CopyConstructor,
@@ -1359,6 +1358,7 @@ void Sema::AddImplicitlyDeclaredMembersT
                             /*isStatic=*/false, /*isInline=*/true);
     CopyAssignment->setAccess(AS_public);
     CopyAssignment->setImplicit();
+    CopyAssignment->setTrivial(ClassDecl->hasTrivialCopyAssignment());
 
     // Add the parameter to the operator.
     ParmVarDecl *FromParam = ParmVarDecl::Create(Context, CopyAssignment,
@@ -1388,6 +1388,7 @@ void Sema::AddImplicitlyDeclaredMembersT
                                   /*isImplicitlyDeclared=*/true);
     Destructor->setAccess(AS_public);
     Destructor->setImplicit();
+    Destructor->setTrivial(ClassDecl->hasTrivialDestructor());
     ClassDecl->addDecl(Destructor);
   }
 }
Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp       (revision 76721)
+++ lib/Sema/SemaDecl.cpp       (working copy)
@@ -2234,6 +2234,8 @@ Sema::ActOnFunctionDeclarator(Scope* S, 
       CurClass->setPOD(false);
       CurClass->setPolymorphic(true);
       CurClass->setHasTrivialConstructor(false);
+      CurClass->setHasTrivialCopyConstructor(false);
+      CurClass->setHasTrivialCopyAssignment(false);
     }
   }
 
@@ -2474,6 +2476,7 @@ void Sema::CheckFunctionDeclaration(Func
       
       // C++ [class.dtor]p3: A destructor is trivial if it is an implicitly-
       // declared destructor.
+      // FIXME: C++0x: don't do this for "= default" destructors
       Record->setHasTrivialDestructor(false);
     } else if (CXXConversionDecl *Conversion 
                = dyn_cast<CXXConversionDecl>(NewFD))
@@ -4054,6 +4057,57 @@ FieldDecl *Sema::CheckFieldDecl(Declarat
     NewFD->setInvalidDecl();
   }
 
+  if (getLangOptions().CPlusPlus) {
+    QualType EltTy = T;
+    while (const ArrayType *AT = Context.getAsArrayType(EltTy))
+      EltTy = AT->getElementType();
+
+    if (const RecordType *RT = EltTy->getAsRecordType()) {
+      CXXRecordDecl* RDecl = cast<CXXRecordDecl>(RT->getDecl());
+
+      if (!RDecl->hasTrivialConstructor())
+        cast<CXXRecordDecl>(Record)->setHasTrivialConstructor(false);
+      if (!RDecl->hasTrivialCopyConstructor())
+        cast<CXXRecordDecl>(Record)->setHasTrivialCopyConstructor(false);
+      if (!RDecl->hasTrivialCopyAssignment())
+        cast<CXXRecordDecl>(Record)->setHasTrivialCopyAssignment(false);
+      if (!RDecl->hasTrivialDestructor())
+        cast<CXXRecordDecl>(Record)->setHasTrivialDestructor(false);
+
+      // C++ 9.5p1: An object of a class with a non-trivial
+      // constructor, a non-trivial copy constructor, a non-trivial
+      // destructor, or a non-trivial copy assignment operator
+      // cannot be a member of a union, nor can an array of such
+      // objects.
+      // TODO: C++0x alters this restriction significantly.
+      if (Record->isUnion()) {
+        // We check for copy constructors before constructors
+        // because otherwise we'll never get complaints about
+        // copy constructors.
+
+        const cxx_special_member invalid = (cxx_special_member) -1;
+
+        cxx_special_member member;
+        if (!RDecl->hasTrivialCopyConstructor())
+          member = cxx_copy_constructor;
+        else if (!RDecl->hasTrivialConstructor())
+          member = cxx_default_constructor;
+        else if (!RDecl->hasTrivialCopyAssignment())
+          member = cxx_copy_assignment;
+        else if (!RDecl->hasTrivialDestructor())
+          member = cxx_destructor;
+        else
+          member = invalid;
+
+        if (member != invalid) {
+          Diag(Loc, diag::err_illegal_union_member) << Name << member;
+          DiagnoseNontrivial(RT, member);
+          NewFD->setInvalidDecl();
+        }
+      }
+    }
+  }
+
   if (getLangOptions().CPlusPlus && !T->isPODType())
     cast<CXXRecordDecl>(Record)->setPOD(false);
 
@@ -4082,6 +4136,134 @@ FieldDecl *Sema::CheckFieldDecl(Declarat
   return NewFD;
 }
 
+/// DiagnoseNontrivial - Given that a class has a non-trivial
+/// special member, figure out why.
+void Sema::DiagnoseNontrivial(const RecordType* T, cxx_special_member member) {
+  QualType QT(T, 0U);
+  CXXRecordDecl* RD = cast<CXXRecordDecl>(T->getDecl());
+
+  // Check whether the member was user-declared.
+  switch (member) {
+  case cxx_default_constructor:
+    if (RD->hasUserDeclaredConstructor()) {
+      typedef CXXRecordDecl::ctor_iterator ctor_iter;
+      for (ctor_iter ci = RD->ctor_begin(), ce = RD->ctor_end(); ci != ce; 
++ci)
+        if (!ci->isImplicitlyDefined(Context)) {
+          SourceLocation CtorLoc = ci->getLocation();
+          Diag(CtorLoc, diag::note_nontrivial_user_defined) << QT << member;
+          return;
+        }
+
+      assert(0 && "found no user-declared constructors");
+      return;
+    }
+    break;
+
+  case cxx_copy_constructor:
+    if (RD->hasUserDeclaredCopyConstructor()) {
+      SourceLocation CtorLoc =
+        RD->getCopyConstructor(Context, 0)->getLocation();
+      Diag(CtorLoc, diag::note_nontrivial_user_defined) << QT << member;
+      return;
+    }
+    break;
+
+  case cxx_copy_assignment:
+    if (RD->hasUserDeclaredCopyAssignment()) {
+      // FIXME: this should use the location of the copy
+      // assignment, not the type.
+      SourceLocation TyLoc = RD->getSourceRange().getBegin();
+      Diag(TyLoc, diag::note_nontrivial_user_defined) << QT << member;
+      return;
+    }
+    break;
+
+  case cxx_destructor:
+    if (RD->hasUserDeclaredDestructor()) {
+      SourceLocation DtorLoc = RD->getDestructor(Context)->getLocation();
+      Diag(DtorLoc, diag::note_nontrivial_user_defined) << QT << member;
+      return;
+    }
+    break;
+  }
+
+  typedef CXXRecordDecl::base_class_iterator base_iter;
+
+  // Virtual bases and members inhibit trivial copying/construction,
+  // but not trivial destruction.
+  if (member != cxx_destructor) {
+
+    // Check for virtual bases.  vbases includes indirect virtual bases,
+    // so we just iterate through the direct bases.
+    for (base_iter bi = RD->bases_begin(), be = RD->bases_end(); bi != be; 
++bi)
+      if (bi->isVirtual()) {
+        SourceLocation BaseLoc = bi->getSourceRange().getBegin();
+        Diag(BaseLoc, diag::note_nontrivial_has_virtual) << QT << 1;
+        return;
+      }
+
+    // Check for virtual methods.
+    typedef CXXRecordDecl::method_iterator meth_iter;
+    for (meth_iter mi = RD->method_begin(), me = RD->method_end(); mi != me;
+         ++mi) {
+      if (mi->isVirtual()) {
+        SourceLocation MLoc = mi->getSourceRange().getBegin();
+        Diag(MLoc, diag::note_nontrivial_has_virtual) << QT << 0;
+        return;
+      }
+    }
+  }
+  
+  bool (CXXRecordDecl::*hasTrivial)() const;
+  switch (member) {
+  case cxx_default_constructor:
+    hasTrivial = &CXXRecordDecl::hasTrivialConstructor; break;
+  case cxx_copy_constructor:
+    hasTrivial = &CXXRecordDecl::hasTrivialCopyConstructor; break;
+  case cxx_copy_assignment:
+    hasTrivial = &CXXRecordDecl::hasTrivialCopyAssignment; break;
+  case cxx_destructor:
+    hasTrivial = &CXXRecordDecl::hasTrivialDestructor; break;
+  default:
+    assert(0 && "unexpected special member"); return;
+  }
+
+  // Check for nontrivial bases (and recurse).
+  for (base_iter bi = RD->bases_begin(), be = RD->bases_end(); bi != be; ++bi) 
{
+    const RecordType *BaseRT = bi->getType()->getAsRecordType();
+    assert(BaseRT);
+    CXXRecordDecl *BaseRecTy = cast<CXXRecordDecl>(BaseRT->getDecl());
+    if (!(BaseRecTy->*hasTrivial)()) {
+      SourceLocation BaseLoc = bi->getSourceRange().getBegin();
+      Diag(BaseLoc, diag::note_nontrivial_has_nontrivial) << QT << 1 << member;
+      DiagnoseNontrivial(BaseRT, member);
+      return;
+    }
+  }
+  
+  // Check for nontrivial members (and recurse).
+  typedef RecordDecl::field_iterator field_iter;
+  for (field_iter fi = RD->field_begin(), fe = RD->field_end(); fi != fe;
+       ++fi) {
+    QualType EltTy = (*fi)->getType();
+    while (const ArrayType *AT = Context.getAsArrayType(EltTy))
+      EltTy = AT->getElementType();
+
+    if (const RecordType *EltRT = EltTy->getAsRecordType()) {
+      CXXRecordDecl* EltRD = cast<CXXRecordDecl>(EltRT->getDecl());
+
+      if (!(EltRD->*hasTrivial)()) {
+        SourceLocation FLoc = (*fi)->getLocation();
+        Diag(FLoc, diag::note_nontrivial_has_nontrivial) << QT << 0 << member;
+        DiagnoseNontrivial(EltRT, member);
+        return;
+      }
+    }
+  }
+
+  assert(0 && "found no explanation for non-trivial member");
+}
+
 /// TranslateIvarVisibility - Translate visibility from a token ID to an 
 ///  AST enum value.
 static ObjCIvarDecl::AccessControl
Index: lib/Sema/Sema.h
===================================================================
--- lib/Sema/Sema.h     (revision 76721)
+++ lib/Sema/Sema.h     (working copy)
@@ -540,6 +540,14 @@ public:
                             SourceLocation TSSL,
                             AccessSpecifier AS, NamedDecl *PrevDecl,
                             Declarator *D = 0);
+
+  enum cxx_special_member {
+    cxx_default_constructor = 0,
+    cxx_copy_constructor = 1,
+    cxx_copy_assignment = 2,
+    cxx_destructor = 3
+  };
+  void DiagnoseNontrivial(const RecordType* Record, cxx_special_member mem);
   
   virtual DeclPtrTy ActOnIvar(Scope *S, SourceLocation DeclStart,
                               DeclPtrTy IntfDecl,
Index: lib/AST/DeclCXX.cpp
===================================================================
--- lib/AST/DeclCXX.cpp (revision 76721)
+++ lib/AST/DeclCXX.cpp (working copy)
@@ -30,7 +30,8 @@ CXXRecordDecl::CXXRecordDecl(Kind K, Tag
     UserDeclaredConstructor(false), UserDeclaredCopyConstructor(false),
     UserDeclaredCopyAssignment(false), UserDeclaredDestructor(false),
     Aggregate(true), PlainOldData(true), Polymorphic(false), Abstract(false),
-    HasTrivialConstructor(true), HasTrivialDestructor(true),
+    HasTrivialConstructor(true), HasTrivialCopyConstructor(true),
+    HasTrivialCopyAssignment(true), HasTrivialDestructor(true),
     Bases(0), NumBases(0), VBases(0), NumVBases(0),
     Conversions(DC, DeclarationName()),
     TemplateOrInstantiation() { }
@@ -128,8 +129,7 @@ CXXRecordDecl::setBases(ASTContext &C,
       QualType QT = UniqueVbases[i]->getType();
       CXXRecordDecl *VBaseClassDecl
         = cast<CXXRecordDecl>(QT->getAsRecordType()->getDecl());
-      this->VBases[i] = 
-        *new CXXBaseSpecifier(
+      this->VBases[i] = CXXBaseSpecifier(
                           VBaseClassDecl->getSourceRange(), true,
                           VBaseClassDecl->getTagKind() == RecordDecl::TK_class,
                           UniqueVbases[i]->getAccessSpecifier(), QT);
@@ -224,12 +224,19 @@ CXXRecordDecl::addedConstructor(ASTConte
   // C++ [class.ctor]p5:
   //   A constructor is trivial if it is an implicitly-declared default
   //   constructor.
+  // FIXME: C++0x: don't do this for "= default" default constructors.
   HasTrivialConstructor = false;
     
   // Note when we have a user-declared copy constructor, which will
   // suppress the implicit declaration of a copy constructor.
-  if (ConDecl->isCopyConstructor(Context))
+  if (ConDecl->isCopyConstructor(Context)) {
     UserDeclaredCopyConstructor = true;
+
+    // C++ [class.copy]p6:
+    //   A copy constructor is trivial if it is implicitly declared.
+    // FIXME: C++0x: don't do this for "= default" copy constructors.
+    HasTrivialCopyConstructor = false;
+  }
 }
 
 void CXXRecordDecl::addedAssignmentOperator(ASTContext &Context,
@@ -253,6 +260,11 @@ void CXXRecordDecl::addedAssignmentOpera
   // Suppress the implicit declaration of a copy constructor.
   UserDeclaredCopyAssignment = true;
 
+  // C++ [class.copy]p11:
+  //   A copy assignment operator is trivial if it is implicitly declared.
+  // FIXME: C++0x: don't do this for "= default" copy operators.
+  HasTrivialCopyAssignment = false;
+
   // C++ [class]p4:
   //   A POD-struct is an aggregate class that [...] has no user-defined copy
   //   assignment operator [...].
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to