[cfe-commits] r76766 - in /cfe/trunk: include/clang/AST/Decl.h include/clang/AST/DeclCXX.h include/clang/Basic/DiagnosticSemaKinds.td lib/AST/DeclCXX.cpp lib/Sema/Sema.h lib/Sema/SemaDecl.cpp lib/Sema/SemaDeclCXX.cpp test/CXX/class/class.union/p1.cpp

Douglas Gregor dgregor at apple.com
Wed Jul 22 11:25:24 PDT 2009


Author: dgregor
Date: Wed Jul 22 13:25:24 2009
New Revision: 76766

URL: http://llvm.org/viewvc/llvm-project?rev=76766&view=rev
Log:
"This patch implements the restrictions on union members detailed in
[class.union]p1", from John McCall!

Added:
    cfe/trunk/test/CXX/class/class.union/p1.cpp
Modified:
    cfe/trunk/include/clang/AST/Decl.h
    cfe/trunk/include/clang/AST/DeclCXX.h
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/lib/AST/DeclCXX.cpp
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp

Modified: cfe/trunk/include/clang/AST/Decl.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Decl.h?rev=76766&r1=76765&r2=76766&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/Decl.h (original)
+++ cfe/trunk/include/clang/AST/Decl.h Wed Jul 22 13:25:24 2009
@@ -673,6 +673,7 @@
   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 @@
       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 @@
   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

Modified: cfe/trunk/include/clang/AST/DeclCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=76766&r1=76765&r2=76766&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/DeclCXX.h (original)
+++ cfe/trunk/include/clang/AST/DeclCXX.h Wed Jul 22 13:25:24 2009
@@ -297,12 +297,51 @@
   /// 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 @@
 
 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 @@
   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 @@
   // (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; }

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=76766&r1=76765&r2=76766&view=diff

==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Wed Jul 22 13:25:24 2009
@@ -339,6 +339,18 @@
   "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{member function|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)">;

Modified: cfe/trunk/lib/AST/DeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=76766&r1=76765&r2=76766&view=diff

==============================================================================
--- cfe/trunk/lib/AST/DeclCXX.cpp (original)
+++ cfe/trunk/lib/AST/DeclCXX.cpp Wed Jul 22 13:25:24 2009
@@ -30,7 +30,8 @@
     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() { }
@@ -123,7 +124,7 @@
   }
   if (vbaseCount > 0) {
     // build AST for inhireted, direct or indirect, virtual bases.
-    this->VBases = new(C) CXXBaseSpecifier [vbaseCount];
+    this->VBases = new (C) CXXBaseSpecifier [vbaseCount];
     this->NumVBases = vbaseCount;
     for (int i = 0; i < vbaseCount; i++) {
       QualType QT = UniqueVbases[i]->getType();
@@ -225,12 +226,19 @@
   // 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,
@@ -254,6 +262,11 @@
   // 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 [...].

Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=76766&r1=76765&r2=76766&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Wed Jul 22 13:25:24 2009
@@ -541,6 +541,14 @@
                             SourceLocation TSSL,
                             AccessSpecifier AS, NamedDecl *PrevDecl,
                             Declarator *D = 0);
+
+  enum CXXSpecialMember {
+    CXXDefaultConstructor = 0,
+    CXXCopyConstructor = 1,
+    CXXCopyAssignment = 2,
+    CXXDestructor = 3
+  };
+  void DiagnoseNontrivial(const RecordType* Record, CXXSpecialMember mem);
   
   virtual DeclPtrTy ActOnIvar(Scope *S, SourceLocation DeclStart,
                               DeclPtrTy IntfDecl,

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=76766&r1=76765&r2=76766&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Wed Jul 22 13:25:24 2009
@@ -2265,6 +2265,8 @@
       CurClass->setPOD(false);
       CurClass->setPolymorphic(true);
       CurClass->setHasTrivialConstructor(false);
+      CurClass->setHasTrivialCopyConstructor(false);
+      CurClass->setHasTrivialCopyAssignment(false);
     }
   }
 
@@ -2505,6 +2507,7 @@
       
       // 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))
@@ -4085,6 +4088,57 @@
     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 CXXSpecialMember invalid = (CXXSpecialMember) -1;
+
+        CXXSpecialMember member;
+        if (!RDecl->hasTrivialCopyConstructor())
+          member = CXXCopyConstructor;
+        else if (!RDecl->hasTrivialConstructor())
+          member = CXXDefaultConstructor;
+        else if (!RDecl->hasTrivialCopyAssignment())
+          member = CXXCopyAssignment;
+        else if (!RDecl->hasTrivialDestructor())
+          member = CXXDestructor;
+        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);
 
@@ -4113,6 +4167,133 @@
   return NewFD;
 }
 
+/// DiagnoseNontrivial - Given that a class has a non-trivial
+/// special member, figure out why.
+void Sema::DiagnoseNontrivial(const RecordType* T, CXXSpecialMember member) {
+  QualType QT(T, 0U);
+  CXXRecordDecl* RD = cast<CXXRecordDecl>(T->getDecl());
+
+  // Check whether the member was user-declared.
+  switch (member) {
+  case CXXDefaultConstructor:
+    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 CXXCopyConstructor:
+    if (RD->hasUserDeclaredCopyConstructor()) {
+      SourceLocation CtorLoc =
+        RD->getCopyConstructor(Context, 0)->getLocation();
+      Diag(CtorLoc, diag::note_nontrivial_user_defined) << QT << member;
+      return;
+    }
+    break;
+
+  case CXXCopyAssignment:
+    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 CXXDestructor:
+    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 != CXXDestructor) {
+    // 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 CXXDefaultConstructor:
+    hasTrivial = &CXXRecordDecl::hasTrivialConstructor; break;
+  case CXXCopyConstructor:
+    hasTrivial = &CXXRecordDecl::hasTrivialCopyConstructor; break;
+  case CXXCopyAssignment:
+    hasTrivial = &CXXRecordDecl::hasTrivialCopyAssignment; break;
+  case CXXDestructor:
+    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

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=76766&r1=76765&r2=76766&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Wed Jul 22 13:25:24 2009
@@ -400,19 +400,40 @@
     // 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 @@
   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 @@
                                  /*isImplicitlyDeclared=*/true);
     DefaultCon->setAccess(AS_public);
     DefaultCon->setImplicit();
+    DefaultCon->setTrivial(ClassDecl->hasTrivialConstructor());
     ClassDecl->addDecl(DefaultCon);
   }
 
@@ -1283,6 +1281,7 @@
                                    /*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 @@
                             /*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 @@
                                   /*isImplicitlyDeclared=*/true);
     Destructor->setAccess(AS_public);
     Destructor->setImplicit();
+    Destructor->setTrivial(ClassDecl->hasTrivialDestructor());
     ClassDecl->addDecl(Destructor);
   }
 }

Added: cfe/trunk/test/CXX/class/class.union/p1.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/class/class.union/p1.cpp?rev=76766&view=auto

==============================================================================
--- cfe/trunk/test/CXX/class/class.union/p1.cpp (added)
+++ cfe/trunk/test/CXX/class/class.union/p1.cpp Wed Jul 22 13:25:24 2009
@@ -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 member function}}
+};
+
+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);
+}
+ */





More information about the cfe-commits mailing list