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::' 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::' 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::' 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::' 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::' 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::' 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 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 virt(0); + Either vbase(0); + Either ctor(0); + Either copyctor(0); + Either copyassign(0); + Either dtor(0); + Either 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 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 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(BaseDecl)-> - hasTrivialConstructor()); + if (!cast(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(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(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(BaseDecl)-> - hasTrivialDestructor()); + if (!cast(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(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(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(RT->getDecl()); + + if (!RDecl->hasTrivialConstructor()) + cast(Record)->setHasTrivialConstructor(false); + if (!RDecl->hasTrivialCopyConstructor()) + cast(Record)->setHasTrivialCopyConstructor(false); + if (!RDecl->hasTrivialCopyAssignment()) + cast(Record)->setHasTrivialCopyAssignment(false); + if (!RDecl->hasTrivialDestructor()) + cast(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(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(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(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(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(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 [...].