From 92f241f1881246a657849e27d080fa939293d677 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Sat, 8 Dec 2012 02:53:02 +0000 Subject: [PATCH] Properly compute triviality for explicitly-defaulted or deleted special members. Remove pre-standard restriction on explicitly-defaulted copy constructors with 'incorrect' parameter types, and instead just make those special members non-trivial as the standard requires. This required making CXXRecordDecl correctly handle classes which have both a trivial and a non-trivial special member of the same kind. This also fixes PR13217 by reimplementing DiagnoseNontrivial in terms of the new triviality computation technology. llvm-svn: 169667 --- clang/include/clang/AST/Decl.h | 2 +- clang/include/clang/AST/DeclCXX.h | 52 +- clang/include/clang/Basic/DiagnosticSemaKinds.td | 48 +- clang/include/clang/Sema/Sema.h | 6 +- clang/lib/AST/Decl.cpp | 7 - clang/lib/AST/DeclCXX.cpp | 67 ++- clang/lib/Sema/SemaDecl.cpp | 185 +------ clang/lib/Sema/SemaDeclCXX.cpp | 582 +++++++++++++++++---- clang/lib/Sema/SemaExprCXX.cpp | 51 +- clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | 13 +- clang/lib/Sema/SemaType.cpp | 2 + clang/test/CXX/basic/basic.types/p10.cpp | 2 +- clang/test/CXX/class/class.union/p1.cpp | 53 +- .../dcl.fct.def/dcl.fct.def.default/p1.cpp | 5 +- .../dcl.meaning/dcl.fct/dcl.fct.def.default/p2.cpp | 4 +- clang/test/CXX/special/class.copy/p12-0x.cpp | 120 +++++ clang/test/CXX/special/class.copy/p25-0x.cpp | 143 +++++ clang/test/CXX/special/class.ctor/p5-0x.cpp | 35 +- clang/test/SemaCXX/anonymous-struct.cpp | 4 +- .../test/SemaCXX/cxx0x-cursory-default-delete.cpp | 18 +- clang/test/SemaCXX/cxx98-compat.cpp | 20 +- 21 files changed, 978 insertions(+), 441 deletions(-) create mode 100644 clang/test/CXX/special/class.copy/p12-0x.cpp create mode 100644 clang/test/CXX/special/class.copy/p25-0x.cpp diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index d9ab9cc..88adbeb 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -1736,7 +1736,7 @@ public: /// Whether this is a (C++11) constexpr function or constexpr constructor. bool isConstexpr() const { return IsConstexpr; } - void setConstexpr(bool IC); + void setConstexpr(bool IC) { IsConstexpr = IC; } /// \brief Whether this function has been deleted. /// diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h index 4728e50..0228794 100644 --- a/clang/include/clang/AST/DeclCXX.h +++ b/clang/include/clang/AST/DeclCXX.h @@ -360,9 +360,20 @@ class CXXRecordDecl : public RecordDecl { /// \brief The trivial special members which this class has, per /// C++11 [class.ctor]p5, C++11 [class.copy]p12, C++11 [class.copy]p25, - /// C++11 [class.dtor]p5. + /// C++11 [class.dtor]p5, or would have if the member were not suppressed. + /// + /// This excludes any user-declared but not user-provided special members + /// which have been declared but not yet defined. unsigned HasTrivialSpecialMembers : 6; + /// \brief The declared special members of this class which are known to be + /// non-trivial. + /// + /// This excludes any user-declared but not user-provided special members + /// which have been declared but not yet defined, and any implicit special + /// members which have not yet been declared. + unsigned DeclaredNonTrivialSpecialMembers : 6; + /// HasIrrelevantDestructor - True when this class has a destructor with no /// semantic effect. bool HasIrrelevantDestructor : 1; @@ -565,9 +576,6 @@ class CXXRecordDecl : public RecordDecl { void markedVirtualFunctionPure(); friend void FunctionDecl::setPure(bool); - void markedConstructorConstexpr(CXXConstructorDecl *CD); - friend void FunctionDecl::setConstexpr(bool); - friend class ASTNodeImporter; protected: @@ -1035,7 +1043,6 @@ public: /// \brief Determine whether this class has a trivial default constructor /// (C++11 [class.ctor]p5). - /// FIXME: This can be wrong when the class has multiple default constructors. bool hasTrivialDefaultConstructor() const { return hasDefaultConstructor() && (data().HasTrivialSpecialMembers & SMF_DefaultConstructor); @@ -1044,8 +1051,9 @@ public: /// \brief Determine whether this class has a non-trivial default constructor /// (C++11 [class.ctor]p5). bool hasNonTrivialDefaultConstructor() const { - return hasDefaultConstructor() && - !(data().HasTrivialSpecialMembers & SMF_DefaultConstructor); + return (data().DeclaredNonTrivialSpecialMembers & SMF_DefaultConstructor) || + (needsImplicitDefaultConstructor() && + !(data().HasTrivialSpecialMembers & SMF_DefaultConstructor)); } /// \brief Determine whether this class has at least one constexpr constructor @@ -1072,7 +1080,6 @@ public: /// \brief Determine whether this class has a trivial copy constructor /// (C++ [class.copy]p6, C++11 [class.copy]p12) - /// FIXME: This can be wrong if the class has multiple copy constructors. bool hasTrivialCopyConstructor() const { return data().HasTrivialSpecialMembers & SMF_CopyConstructor; } @@ -1080,13 +1087,14 @@ public: /// \brief Determine whether this class has a non-trivial copy constructor /// (C++ [class.copy]p6, C++11 [class.copy]p12) bool hasNonTrivialCopyConstructor() const { - return !(data().HasTrivialSpecialMembers & SMF_CopyConstructor); + return data().DeclaredNonTrivialSpecialMembers & SMF_CopyConstructor || + !hasTrivialCopyConstructor(); } /// \brief Determine whether this class has a trivial move constructor /// (C++11 [class.copy]p12) - /// FIXME: This can be wrong if the class has multiple move constructors, - /// or if the implicit move constructor would be deleted. + /// FIXME: This can be wrong if the implicit move constructor would be + /// deleted. bool hasTrivialMoveConstructor() const { return hasMoveConstructor() && (data().HasTrivialSpecialMembers & SMF_MoveConstructor); @@ -1097,14 +1105,13 @@ public: /// FIXME: This can be wrong if the implicit move constructor would be /// deleted. bool hasNonTrivialMoveConstructor() const { - return hasMoveConstructor() && - !(data().HasTrivialSpecialMembers & SMF_MoveConstructor); + return (data().DeclaredNonTrivialSpecialMembers & SMF_MoveConstructor) || + (needsImplicitMoveConstructor() && + !(data().HasTrivialSpecialMembers & SMF_MoveConstructor)); } /// \brief Determine whether this class has a trivial copy assignment operator /// (C++ [class.copy]p11, C++11 [class.copy]p25) - /// FIXME: This can be wrong if the class has multiple copy assignment - /// operators. bool hasTrivialCopyAssignment() const { return data().HasTrivialSpecialMembers & SMF_CopyAssignment; } @@ -1112,13 +1119,13 @@ public: /// \brief Determine whether this class has a non-trivial copy assignment /// operator (C++ [class.copy]p11, C++11 [class.copy]p25) bool hasNonTrivialCopyAssignment() const { - return !(data().HasTrivialSpecialMembers & SMF_CopyAssignment); + return data().DeclaredNonTrivialSpecialMembers & SMF_CopyAssignment || + !hasTrivialCopyAssignment(); } /// \brief Determine whether this class has a trivial move assignment operator /// (C++11 [class.copy]p25) - /// FIXME: This can be wrong if the class has multiple move assignment - /// operators, or if the implicit move assignment operator would be deleted. + /// FIXME: This can be wrong if the implicit move assignment would be deleted. bool hasTrivialMoveAssignment() const { return hasMoveAssignment() && (data().HasTrivialSpecialMembers & SMF_MoveAssignment); @@ -1128,8 +1135,9 @@ public: /// operator (C++11 [class.copy]p25) /// FIXME: This can be wrong if the implicit move assignment would be deleted. bool hasNonTrivialMoveAssignment() const { - return hasMoveAssignment() && - !(data().HasTrivialSpecialMembers & SMF_MoveAssignment); + return (data().DeclaredNonTrivialSpecialMembers & SMF_MoveAssignment) || + (needsImplicitMoveAssignment() && + !(data().HasTrivialSpecialMembers & SMF_MoveAssignment)); } /// \brief Determine whether this class has a trivial destructor @@ -1447,6 +1455,10 @@ public: return (PathAccess > DeclAccess ? PathAccess : DeclAccess); } + /// \brief Indicates that the declaration of a defaulted or deleted special + /// member function is now complete. + void finishedDefaultedOrDeletedMember(CXXMethodDecl *MD); + /// \brief Indicates that the definition of this class is now complete. virtual void completeDefinition(); diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index c21cd79..399449d 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -1073,6 +1073,7 @@ def err_missing_default_ctor : Error< "%select{|implicit default }0constructor for %1 must explicitly initialize " "the %select{base class|member}2 %3 which does not have a default " "constructor">; + def err_illegal_union_or_anon_struct_member : Error< "%select{anonymous struct|union}0 member %1 has a non-trivial " "%select{constructor|copy constructor|move constructor|copy assignment " @@ -1082,16 +1083,40 @@ def warn_cxx98_compat_nontrivial_union_or_anon_struct_member : Warning< "%select{constructor|copy constructor|move constructor|copy assignment " "operator|move assignment operator|destructor}2 is incompatible with C++98">, InGroup, DefaultIgnore; + +def note_nontrivial_virtual_dtor : Note< + "destructor for %0 is not trivial because it is virtual">; 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|move constructor|copy assignment " - "operator|move assignment operator|destructor}2">; -def note_nontrivial_user_defined : Note< - "because type %0 has a user-declared %select{constructor|copy constructor|" - "move constructor|copy assignment operator|move assignment operator|" - "destructor}1">; +def note_nontrivial_no_def_ctor : Note< + "because %select{base class of |field of |}0type %1 has no " + "default constructor">; +def note_user_declared_ctor : Note< + "implicit default constructor suppressed by user-declared constructor">; +def note_nontrivial_no_copy : Note< + "because no %select{<>|constructor|constructor|assignment operator|" + "assignment operator|<>}2 can be used to " + "%select{<>|copy|move|copy|move|<>}2 " + "%select{base class|field|an object}0 of type %3">; +def note_nontrivial_user_provided : Note< + "because %select{base class of |field of |}0type %1 has a user-provided " + "%select{default constructor|copy constructor|move constructor|" + "copy assignment operator|move assignment operator|destructor}2">; +def note_nontrivial_in_class_init : Note< + "because field %0 has an initializer">; +def note_nontrivial_param_type : Note< + "because its parameter is %diff{of type $, not $|of the wrong type}2,3">; +def note_nontrivial_default_arg : Note<"because it has a default argument">; +def note_nontrivial_variadic : Note<"because it is a variadic function">; +def note_nontrivial_subobject : Note< + "because the function selected to %select{construct|copy|move|copy|move|" + "destroy}2 %select{base class|field}0 of type %1 is not trivial">; +def note_nontrivial_user_declared_ctor : Note< + "because type %0 has a user-declared constructor">; +def note_nontrivial_objc_ownership : Note< + "because type %0 has a member with %select{no|no|__strong|__weak|" + "__autoreleasing}1 ownership">; + def err_static_data_member_not_allowed_in_anon_struct : Error< "static data member %0 not allowed in anonymous struct">; def ext_static_data_member_in_union : ExtWarn< @@ -3706,9 +3731,6 @@ def note_arc_retain_cycle_owner : Note< } // end "ARC Retain Cycle" category -def note_nontrivial_objc_ownership : Note< - "because type %0 has %select{no|no|__strong|__weak|__autoreleasing}1 " - "ownership">; def warn_arc_object_memaccess : Warning< "%select{destination for|source of}0 this %1 call is a pointer to " "ownership-qualified type %2">, InGroup; @@ -5429,10 +5451,6 @@ def err_defaulted_special_member_copy_const_param : Error< "the parameter for this explicitly-defaulted copy " "%select{constructor|assignment operator}0 is const, but a member or base " "requires it to be non-const">; -def err_defaulted_special_member_copy_non_const_param : Error< - "explicitly-defaulted copy %select{constructor|assignment operator}0 with " - "a non-const parameter must be defaulted outside the class, unless a base or " - "member requires the parameter to be non-const">; def err_defaulted_copy_assign_not_ref : Error< "the parameter for an explicitly-defaulted copy assignment operator must be an " "lvalue reference type">; diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 59013d5..e6b4ac3 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -1530,7 +1530,9 @@ public: Declarator *D = 0); bool CheckNontrivialField(FieldDecl *FD); - void DiagnoseNontrivial(const RecordType* Record, CXXSpecialMember mem); + void DiagnoseNontrivial(const CXXRecordDecl *Record, CXXSpecialMember CSM); + bool SpecialMemberIsTrivial(CXXMethodDecl *MD, CXXSpecialMember CSM, + bool Diagnose = false); CXXSpecialMember getSpecialMember(const CXXMethodDecl *MD); void ActOnLastBitfield(SourceLocation DeclStart, SmallVectorImpl &AllIvarDecls); @@ -4438,7 +4440,7 @@ public: StorageClass& SC); Decl *ActOnConversionDeclarator(CXXConversionDecl *Conversion); - void CheckExplicitlyDefaultedMethods(CXXRecordDecl *Record); + void CheckExplicitlyDefaultedAndDeletedMethods(CXXRecordDecl *Record); void CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD); //===--------------------------------------------------------------------===// diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index 3c31d41..538dcee 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -1658,13 +1658,6 @@ void FunctionDecl::setPure(bool P) { Parent->markedVirtualFunctionPure(); } -void FunctionDecl::setConstexpr(bool IC) { - IsConstexpr = IC; - CXXConstructorDecl *CD = dyn_cast(this); - if (IC && CD) - CD->getParent()->markedConstructorConstexpr(CD); -} - bool FunctionDecl::isMain() const { const TranslationUnitDecl *tunit = dyn_cast(getDeclContext()->getRedeclContext()); diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp index d3a0c1a..dfcc154 100644 --- a/clang/lib/AST/DeclCXX.cpp +++ b/clang/lib/AST/DeclCXX.cpp @@ -43,6 +43,7 @@ CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D) HasMutableFields(false), HasOnlyCMembers(true), HasInClassInitializer(false), HasUninitializedReferenceMember(false), HasTrivialSpecialMembers(SMF_All), + DeclaredNonTrivialSpecialMembers(0), HasIrrelevantDestructor(true), HasConstexprNonCopyMoveConstructor(false), DefaultedDefaultConstructorIsConstexpr(true), @@ -261,7 +262,7 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, if (!BaseClassDecl->hasConstexprDefaultConstructor()) data().DefaultedDefaultConstructorIsConstexpr = false; } - + // C++ [class.ctor]p3: // A destructor is trivial if all the direct base classes of its class // have trivial destructors. @@ -470,14 +471,6 @@ void CXXRecordDecl::markedVirtualFunctionPure() { data().Abstract = true; } -void CXXRecordDecl::markedConstructorConstexpr(CXXConstructorDecl *CD) { - if (!CD->isCopyOrMoveConstructor()) - data().HasConstexprNonCopyMoveConstructor = true; - - if (CD->isDefaultConstructor()) - data().HasConstexprDefaultConstructor = true; -} - void CXXRecordDecl::addedMember(Decl *D) { if (!D->isImplicit() && !isa(D) && @@ -638,6 +631,20 @@ void CXXRecordDecl::addedMember(Decl *D) { } if (SMKind) { + // If this is the first declaration of a special member, we no longer have + // an implicit trivial special member. + data().HasTrivialSpecialMembers &= + data().DeclaredSpecialMembers | ~SMKind; + + if (!Method->isImplicit() && !Method->isUserProvided()) { + // This method is user-declared but not user-provided. We can't work out + // whether it's trivial yet (not until we get to the end of the class). + // We'll handle this method in finishedDefaultedOrDeletedMember. + } else if (Method->isTrivial()) + data().HasTrivialSpecialMembers |= SMKind; + else + data().DeclaredNonTrivialSpecialMembers |= SMKind; + // Note when we have declared a declared special member, and suppress the // implicit declaration of this special member. data().DeclaredSpecialMembers |= SMKind; @@ -658,14 +665,6 @@ void CXXRecordDecl::addedMember(Decl *D) { // This is an extension in C++03. data().PlainOldData = false; } - - // C++11 [class.ctor]p5, C++11 [class.copy]p12, C++11 [class.copy]p25, - // C++11 [class.dtor]p5: - // A [special member] is trivial if it is not user-provided [...] - // FIXME: This is bogus. A class can have both (say) a trivial copy - // constructor *and* a user-provided copy constructor. - if (Method->isUserProvided()) - data().HasTrivialSpecialMembers &= ~SMKind; } return; @@ -910,6 +909,40 @@ void CXXRecordDecl::addedMember(Decl *D) { data().Conversions.addDecl(getASTContext(), Shadow, Shadow->getAccess()); } +void CXXRecordDecl::finishedDefaultedOrDeletedMember(CXXMethodDecl *D) { + assert(!D->isImplicit() && !D->isUserProvided()); + + // The kind of special member this declaration is, if any. + unsigned SMKind = 0; + + if (CXXConstructorDecl *Constructor = dyn_cast(D)) { + if (Constructor->isDefaultConstructor()) { + SMKind |= SMF_DefaultConstructor; + if (Constructor->isConstexpr()) + data().HasConstexprDefaultConstructor = true; + } + if (Constructor->isCopyConstructor()) + SMKind |= SMF_CopyConstructor; + else if (Constructor->isMoveConstructor()) + SMKind |= SMF_MoveConstructor; + else if (Constructor->isConstexpr()) + // We may now know that the constructor is constexpr. + data().HasConstexprNonCopyMoveConstructor = true; + } else if (isa(D)) + SMKind |= SMF_Destructor; + else if (D->isCopyAssignmentOperator()) + SMKind |= SMF_CopyAssignment; + else if (D->isMoveAssignmentOperator()) + SMKind |= SMF_MoveAssignment; + + // Update which trivial / non-trivial special members we have. + // addedMember will have skipped this step for this member. + if (D->isTrivial()) + data().HasTrivialSpecialMembers |= SMKind; + else + data().DeclaredNonTrivialSpecialMembers |= SMKind; +} + bool CXXRecordDecl::isCLike() const { if (getTagKind() == TTK_Class || getTagKind() == TTK_Interface || !TemplateOrInstantiation.isNull()) diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 502a855..be30053 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -9772,7 +9772,7 @@ bool Sema::CheckNontrivialField(FieldDecl *FD) { QualType EltTy = Context.getBaseElementType(FD->getType()); if (const RecordType *RT = EltTy->getAs()) { - CXXRecordDecl* RDecl = cast(RT->getDecl()); + CXXRecordDecl *RDecl = cast(RT->getDecl()); if (RDecl->getDefinition()) { // We check for copy constructors before constructors // because otherwise we'll never get complaints about @@ -9814,192 +9814,13 @@ bool Sema::CheckNontrivialField(FieldDecl *FD) { diag::warn_cxx98_compat_nontrivial_union_or_anon_struct_member : diag::err_illegal_union_or_anon_struct_member) << (int)FD->getParent()->isUnion() << FD->getDeclName() << member; - DiagnoseNontrivial(RT, member); + DiagnoseNontrivial(RDecl, member); return !getLangOpts().CPlusPlus0x; } } } - - return false; -} - -/// If the given constructor is user-declared, produce a diagnostic explaining -/// that it makes the class non-trivial. -static bool diagnoseNonTrivialUserDeclaredCtor(Sema &S, QualType QT, - CXXConstructorDecl *CD, - Sema::CXXSpecialMember CSM) { - if (CD->isImplicit()) - return false; - - SourceLocation CtorLoc = CD->getLocation(); - S.Diag(CtorLoc, diag::note_nontrivial_user_defined) << QT << CSM; - return true; -} - -/// DiagnoseNontrivial - Given that a class has a non-trivial -/// special member, figure out why. -/// FIXME: These checks are not correct in C++11 mode. Currently, this is OK -/// since we only use this in C++11 for a -Wc++98-compat warning. -void Sema::DiagnoseNontrivial(const RecordType* T, CXXSpecialMember member) { - QualType QT(T, 0U); - CXXRecordDecl* RD = cast(T->getDecl()); - - // Check whether the member was user-declared. - switch (member) { - case CXXInvalid: - break; - - 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 (diagnoseNonTrivialUserDeclaredCtor(*this, QT, *CI, member)) - return; - - // No user-delcared constructors; look for constructor templates. - typedef CXXRecordDecl::specific_decl_iterator - tmpl_iter; - for (tmpl_iter TI(RD->decls_begin()), TE(RD->decls_end()); - TI != TE; ++TI) { - CXXConstructorDecl *CD = - dyn_cast(TI->getTemplatedDecl()); - if (CD && diagnoseNonTrivialUserDeclaredCtor(*this, QT, CD, member)) - return; - } - } - break; - - case CXXCopyConstructor: - if (RD->hasUserDeclaredCopyConstructor()) { - SourceLocation CtorLoc = - RD->getCopyConstructor(0)->getLocation(); - Diag(CtorLoc, diag::note_nontrivial_user_defined) << QT << member; - return; - } - break; - - case CXXMoveConstructor: - if (RD->hasUserDeclaredMoveConstructor()) { - SourceLocation CtorLoc = RD->getMoveConstructor()->getLocation(); - Diag(CtorLoc, diag::note_nontrivial_user_defined) << QT << member; - return; - } - break; - - case CXXCopyAssignment: - if (RD->hasUserDeclaredCopyAssignment()) { - SourceLocation AssignLoc = - RD->getCopyAssignmentOperator(0)->getLocation(); - Diag(AssignLoc, diag::note_nontrivial_user_defined) << QT << member; - return; - } - break; - - case CXXMoveAssignment: - if (RD->hasUserDeclaredMoveAssignment()) { - SourceLocation AssignLoc = RD->getMoveAssignmentOperator()->getLocation(); - Diag(AssignLoc, diag::note_nontrivial_user_defined) << QT << member; - return; - } - break; - - case CXXDestructor: - if (RD->hasUserDeclaredDestructor()) { - SourceLocation DtorLoc = LookupDestructor(RD)->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->getLocStart(); - 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->getLocStart(); - Diag(MLoc, diag::note_nontrivial_has_virtual) << QT << 0; - return; - } - } - } - bool (CXXRecordDecl::*hasNonTrivial)() const; - switch (member) { - case CXXDefaultConstructor: - hasNonTrivial = &CXXRecordDecl::hasNonTrivialDefaultConstructor; break; - case CXXCopyConstructor: - hasNonTrivial = &CXXRecordDecl::hasNonTrivialCopyConstructor; break; - case CXXCopyAssignment: - hasNonTrivial = &CXXRecordDecl::hasNonTrivialCopyAssignment; break; - case CXXMoveConstructor: - hasNonTrivial = &CXXRecordDecl::hasNonTrivialMoveConstructor; break; - case CXXMoveAssignment: - hasNonTrivial = &CXXRecordDecl::hasNonTrivialMoveAssignment; break; - case CXXDestructor: - hasNonTrivial = &CXXRecordDecl::hasNonTrivialDestructor; break; - case CXXInvalid: - llvm_unreachable("unexpected special member"); - } - - // 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()->getAs(); - assert(BaseRT && "Don't know how to handle dependent bases"); - CXXRecordDecl *BaseRecTy = cast(BaseRT->getDecl()); - if ((BaseRecTy->*hasNonTrivial)()) { - SourceLocation BaseLoc = bi->getLocStart(); - 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 = Context.getBaseElementType(fi->getType()); - if (const RecordType *EltRT = EltTy->getAs()) { - CXXRecordDecl* EltRD = cast(EltRT->getDecl()); - - if ((EltRD->*hasNonTrivial)()) { - SourceLocation FLoc = fi->getLocation(); - Diag(FLoc, diag::note_nontrivial_has_nontrivial) << QT << 0 << member; - DiagnoseNontrivial(EltRT, member); - return; - } - } - - if (EltTy->isObjCLifetimeType()) { - switch (EltTy.getObjCLifetime()) { - case Qualifiers::OCL_None: - case Qualifiers::OCL_ExplicitNone: - break; - - case Qualifiers::OCL_Autoreleasing: - case Qualifiers::OCL_Weak: - case Qualifiers::OCL_Strong: - Diag(fi->getLocation(), diag::note_nontrivial_objc_ownership) - << QT << EltTy.getObjCLifetime(); - return; - } - } - } + return false; } /// TranslateIvarVisibility - Translate visibility from a token ID to an diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 88cc0aa..f4b9a92 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -3990,42 +3990,6 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) { } } - // C++0x [dcl.constexpr]p8: A constexpr specifier for a non-static member - // function that is not a constructor declares that member function to be - // const. [...] The class of which that function is a member shall be - // a literal type. - // - // If the class has virtual bases, any constexpr members will already have - // been diagnosed by the checks performed on the member declaration, so - // suppress this (less useful) diagnostic. - if (LangOpts.CPlusPlus0x && !Record->isDependentType() && - !Record->isLiteral() && !Record->getNumVBases()) { - for (CXXRecordDecl::method_iterator M = Record->method_begin(), - MEnd = Record->method_end(); - M != MEnd; ++M) { - if (M->isConstexpr() && M->isInstance() && !isa(*M)) { - switch (Record->getTemplateSpecializationKind()) { - case TSK_ImplicitInstantiation: - case TSK_ExplicitInstantiationDeclaration: - case TSK_ExplicitInstantiationDefinition: - // If a template instantiates to a non-literal type, but its members - // instantiate to constexpr functions, the template is technically - // ill-formed, but we allow it for sanity. - continue; - - case TSK_Undeclared: - case TSK_ExplicitSpecialization: - RequireLiteralType(M->getLocation(), Context.getRecordType(Record), - diag::err_constexpr_method_non_literal); - break; - } - - // Only produce one error per class. - break; - } - } - } - // Declare inherited constructors. We do this eagerly here because: // - The standard requires an eager diagnostic for conflicting inherited // constructors from different classes. @@ -4036,12 +4000,25 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) { DeclareInheritedConstructors(Record); } -void Sema::CheckExplicitlyDefaultedMethods(CXXRecordDecl *Record) { +void Sema::CheckExplicitlyDefaultedAndDeletedMethods(CXXRecordDecl *Record) { for (CXXRecordDecl::method_iterator MI = Record->method_begin(), ME = Record->method_end(); - MI != ME; ++MI) + MI != ME; ++MI) { if (!MI->isInvalidDecl() && MI->isExplicitlyDefaulted()) CheckExplicitlyDefaultedSpecialMember(*MI); + + if (!MI->isImplicit() && !MI->isUserProvided()) { + // For an explicitly defaulted or deleted special member, we defer + // determining triviality until the class is complete. That time is now! + CXXSpecialMember CSM = getSpecialMember(*MI); + if (CSM != CXXInvalid) { + MI->setTrivial(SpecialMemberIsTrivial(*MI, CSM)); + + // Inform the class that we've finished declaring this member. + Record->finishedDefaultedOrDeletedMember(*MI); + } + } + } } /// Is the special member function which would be selected to perform the @@ -4231,33 +4208,11 @@ void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) { const FunctionProtoType *Type = MD->getType()->getAs(); - // Compute argument constness, constexpr, and triviality. bool CanHaveConstParam = false; - bool Trivial = false; - switch (CSM) { - case CXXDefaultConstructor: - Trivial = RD->hasTrivialDefaultConstructor(); - break; - case CXXCopyConstructor: + if (CSM == CXXCopyConstructor) CanHaveConstParam = RD->implicitCopyConstructorHasConstParam(); - Trivial = RD->hasTrivialCopyConstructor(); - break; - case CXXCopyAssignment: + else if (CSM == CXXCopyAssignment) CanHaveConstParam = RD->implicitCopyAssignmentHasConstParam(); - Trivial = RD->hasTrivialCopyAssignment(); - break; - case CXXMoveConstructor: - Trivial = RD->hasTrivialMoveConstructor(); - break; - case CXXMoveAssignment: - Trivial = RD->hasTrivialMoveAssignment(); - break; - case CXXDestructor: - Trivial = RD->hasTrivialDestructor(); - break; - case CXXInvalid: - llvm_unreachable("non-special member explicitly defaulted!"); - } QualType ReturnType = Context.VoidTy; if (CSM == CXXCopyAssignment || CSM == CXXMoveAssignment) { @@ -4306,14 +4261,6 @@ void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) { } HadError = true; } - - // If a function is explicitly defaulted on its first declaration, it shall - // have the same parameter type as if it had been implicitly declared. - // (Presumably this is to prevent it from being trivial?) - if (!HasConstParam && CanHaveConstParam && First) - Diag(MD->getLocation(), - diag::err_defaulted_special_member_copy_non_const_param) - << (CSM == CXXCopyAssignment); } else if (ExpectedParams) { // A copy assignment operator can take its argument by value, but a // defaulted one cannot. @@ -4363,10 +4310,6 @@ void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) { // -- it is implicitly considered to have the same exception-specification // as if it had been implicitly declared, MD->setType(QualType(ImplicitType, 0)); - - // Such a function is also trivial if the implicitly-declared function - // would have been. - MD->setTrivial(Trivial); } if (ShouldDeleteSpecialMember(MD, CSM)) { @@ -4805,6 +4748,427 @@ bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM, return false; } +/// Perform lookup for a special member of the specified kind, and determine +/// whether it is trivial. If the triviality can be determined without the +/// lookup, skip it. This is intended for use when determining whether a +/// special member of a containing object is trivial, and thus does not ever +/// perform overload resolution for default constructors. +/// +/// If \p Selected is not \c NULL, \c *Selected will be filled in with the +/// member that was most likely to be intended to be trivial, if any. +static bool findTrivialSpecialMember(Sema &S, CXXRecordDecl *RD, + Sema::CXXSpecialMember CSM, unsigned Quals, + CXXMethodDecl **Selected) { + if (Selected) + *Selected = 0; + + switch (CSM) { + case Sema::CXXInvalid: + llvm_unreachable("not a special member"); + + case Sema::CXXDefaultConstructor: + // C++11 [class.ctor]p5: + // A default constructor is trivial if: + // - all the [direct subobjects] have trivial default constructors + // + // Note, no overload resolution is performed in this case. + if (RD->hasTrivialDefaultConstructor()) + return true; + + if (Selected) { + // If there's a default constructor which could have been trivial, dig it + // out. Otherwise, if there's any user-provided default constructor, point + // to that as an example of why there's not a trivial one. + CXXConstructorDecl *DefCtor = 0; + if (RD->needsImplicitDefaultConstructor()) + S.DeclareImplicitDefaultConstructor(RD); + for (CXXRecordDecl::ctor_iterator CI = RD->ctor_begin(), + CE = RD->ctor_end(); CI != CE; ++CI) { + if (!CI->isDefaultConstructor()) + continue; + DefCtor = *CI; + if (!DefCtor->isUserProvided()) + break; + } + + *Selected = DefCtor; + } + + return false; + + case Sema::CXXDestructor: + // C++11 [class.dtor]p5: + // A destructor is trivial if: + // - all the direct [subobjects] have trivial destructors + if (RD->hasTrivialDestructor()) + return true; + + if (Selected) { + if (RD->needsImplicitDestructor()) + S.DeclareImplicitDestructor(RD); + *Selected = RD->getDestructor(); + } + + return false; + + case Sema::CXXCopyConstructor: + // C++11 [class.copy]p12: + // A copy constructor is trivial if: + // - the constructor selected to copy each direct [subobject] is trivial + if (RD->hasTrivialCopyConstructor()) { + if (Quals == Qualifiers::Const) + // We must either select the trivial copy constructor or reach an + // ambiguity; no need to actually perform overload resolution. + return true; + } else if (!Selected) { + return false; + } + // In C++98, we are not supposed to perform overload resolution here, but we + // treat that as a language defect, as suggested on cxx-abi-dev, to treat + // cases like B as having a non-trivial copy constructor: + // struct A { template A(T&); }; + // struct B { mutable A a; }; + goto NeedOverloadResolution; + + case Sema::CXXCopyAssignment: + // C++11 [class.copy]p25: + // A copy assignment operator is trivial if: + // - the assignment operator selected to copy each direct [subobject] is + // trivial + if (RD->hasTrivialCopyAssignment()) { + if (Quals == Qualifiers::Const) + return true; + } else if (!Selected) { + return false; + } + // In C++98, we are not supposed to perform overload resolution here, but we + // treat that as a language defect. + goto NeedOverloadResolution; + + case Sema::CXXMoveConstructor: + case Sema::CXXMoveAssignment: + NeedOverloadResolution: + Sema::SpecialMemberOverloadResult *SMOR = + S.LookupSpecialMember(RD, CSM, + Quals & Qualifiers::Const, + Quals & Qualifiers::Volatile, + /*RValueThis*/false, /*ConstThis*/false, + /*VolatileThis*/false); + + // The standard doesn't describe how to behave if the lookup is ambiguous. + // We treat it as not making the member non-trivial, just like the standard + // mandates for the default constructor. This should rarely matter, because + // the member will also be deleted. + if (SMOR->getKind() == Sema::SpecialMemberOverloadResult::Ambiguous) + return true; + + if (!SMOR->getMethod()) { + assert(SMOR->getKind() == + Sema::SpecialMemberOverloadResult::NoMemberOrDeleted); + return false; + } + + // We deliberately don't check if we found a deleted special member. We're + // not supposed to! + if (Selected) + *Selected = SMOR->getMethod(); + return SMOR->getMethod()->isTrivial(); + } + + llvm_unreachable("unknown special method kind"); +} + +CXXConstructorDecl *findUserDeclaredCtor(CXXRecordDecl *RD) { + for (CXXRecordDecl::ctor_iterator CI = RD->ctor_begin(), CE = RD->ctor_end(); + CI != CE; ++CI) + if (!CI->isImplicit()) + return *CI; + + // Look for constructor templates. + typedef CXXRecordDecl::specific_decl_iterator tmpl_iter; + for (tmpl_iter TI(RD->decls_begin()), TE(RD->decls_end()); TI != TE; ++TI) { + if (CXXConstructorDecl *CD = + dyn_cast(TI->getTemplatedDecl())) + return CD; + } + + return 0; +} + +/// The kind of subobject we are checking for triviality. The values of this +/// enumeration are used in diagnostics. +enum TrivialSubobjectKind { + /// The subobject is a base class. + TSK_BaseClass, + /// The subobject is a non-static data member. + TSK_Field, + /// The object is actually the complete object. + TSK_CompleteObject +}; + +/// Check whether the special member selected for a given type would be trivial. +static bool checkTrivialSubobjectCall(Sema &S, SourceLocation SubobjLoc, + QualType SubType, + Sema::CXXSpecialMember CSM, + TrivialSubobjectKind Kind, + bool Diagnose) { + CXXRecordDecl *SubRD = SubType->getAsCXXRecordDecl(); + if (!SubRD) + return true; + + CXXMethodDecl *Selected; + if (findTrivialSpecialMember(S, SubRD, CSM, SubType.getCVRQualifiers(), + Diagnose ? &Selected : 0)) + return true; + + if (Diagnose) { + if (!Selected && CSM == Sema::CXXDefaultConstructor) { + S.Diag(SubobjLoc, diag::note_nontrivial_no_def_ctor) + << Kind << SubType.getUnqualifiedType(); + if (CXXConstructorDecl *CD = findUserDeclaredCtor(SubRD)) + S.Diag(CD->getLocation(), diag::note_user_declared_ctor); + } else if (!Selected) + S.Diag(SubobjLoc, diag::note_nontrivial_no_copy) + << Kind << SubType.getUnqualifiedType() << CSM << SubType; + else if (Selected->isUserProvided()) { + if (Kind == TSK_CompleteObject) + S.Diag(Selected->getLocation(), diag::note_nontrivial_user_provided) + << Kind << SubType.getUnqualifiedType() << CSM; + else { + S.Diag(SubobjLoc, diag::note_nontrivial_user_provided) + << Kind << SubType.getUnqualifiedType() << CSM; + S.Diag(Selected->getLocation(), diag::note_declared_at); + } + } else { + if (Kind != TSK_CompleteObject) + S.Diag(SubobjLoc, diag::note_nontrivial_subobject) + << Kind << SubType.getUnqualifiedType() << CSM; + + // Explain why the defaulted or deleted special member isn't trivial. + S.SpecialMemberIsTrivial(Selected, CSM, Diagnose); + } + } + + return false; +} + +/// Check whether the members of a class type allow a special member to be +/// trivial. +static bool checkTrivialClassMembers(Sema &S, CXXRecordDecl *RD, + Sema::CXXSpecialMember CSM, + bool ConstArg, bool Diagnose) { + for (CXXRecordDecl::field_iterator FI = RD->field_begin(), + FE = RD->field_end(); FI != FE; ++FI) { + if (FI->isInvalidDecl() || FI->isUnnamedBitfield()) + continue; + + QualType FieldType = S.Context.getBaseElementType(FI->getType()); + + // Pretend anonymous struct or union members are members of this class. + if (FI->isAnonymousStructOrUnion()) { + if (!checkTrivialClassMembers(S, FieldType->getAsCXXRecordDecl(), + CSM, ConstArg, Diagnose)) + return false; + continue; + } + + // C++11 [class.ctor]p5: + // A default constructor is trivial if [...] + // -- no non-static data member of its class has a + // brace-or-equal-initializer + if (CSM == Sema::CXXDefaultConstructor && FI->hasInClassInitializer()) { + if (Diagnose) + S.Diag(FI->getLocation(), diag::note_nontrivial_in_class_init) << *FI; + return false; + } + + // Objective C ARC 4.3.5: + // [...] nontrivally ownership-qualified types are [...] not trivially + // default constructible, copy constructible, move constructible, copy + // assignable, move assignable, or destructible [...] + if (S.getLangOpts().ObjCAutoRefCount && + FieldType.hasNonTrivialObjCLifetime()) { + if (Diagnose) + S.Diag(FI->getLocation(), diag::note_nontrivial_objc_ownership) + << RD << FieldType.getObjCLifetime(); + return false; + } + + if (ConstArg && !FI->isMutable()) + FieldType.addConst(); + if (!checkTrivialSubobjectCall(S, FI->getLocation(), FieldType, CSM, + TSK_Field, Diagnose)) + return false; + } + + return true; +} + +/// Diagnose why the specified class does not have a trivial special member of +/// the given kind. +void Sema::DiagnoseNontrivial(const CXXRecordDecl *RD, CXXSpecialMember CSM) { + QualType Ty = Context.getRecordType(RD); + if (CSM == CXXCopyConstructor || CSM == CXXCopyAssignment) + Ty.addConst(); + + checkTrivialSubobjectCall(*this, RD->getLocation(), Ty, CSM, + TSK_CompleteObject, /*Diagnose*/true); +} + +/// Determine whether a defaulted or deleted special member function is trivial, +/// as specified in C++11 [class.ctor]p5, C++11 [class.copy]p12, +/// C++11 [class.copy]p25, and C++11 [class.dtor]p5. +bool Sema::SpecialMemberIsTrivial(CXXMethodDecl *MD, CXXSpecialMember CSM, + bool Diagnose) { + // Note that we can't work out CSM for ourselves. Consider this: + // + // struct S { S(int); S(const S&=0) = delete; }; + // + // The same function is a trivial copy constructor but a non-trivial default + // constructor. + assert(!MD->isUserProvided() && CSM != CXXInvalid && "not special enough"); + + CXXRecordDecl *RD = MD->getParent(); + + bool ConstArg = false; + ParmVarDecl *Param0 = MD->getNumParams() ? MD->getParamDecl(0) : 0; + + // C++11 [class.copy]p12, p25: + // A [special member] is trivial if its declared parameter type is the same + // as if it had been implicitly declared [...] + switch (CSM) { + case CXXDefaultConstructor: + case CXXDestructor: + // Trivial default constructors and destructors cannot have parameters. + break; + + case CXXCopyConstructor: + case CXXCopyAssignment: { + // Trivial copy operations always have const, non-volatile parameter types. + ConstArg = true; + const ReferenceType *RT = Param0->getType()->getAs(); + if (!RT || RT->getPointeeType().getCVRQualifiers() != Qualifiers::Const) { + if (Diagnose) + Diag(Param0->getLocation(), diag::note_nontrivial_param_type) + << Param0->getSourceRange() << Param0->getType() + << Context.getLValueReferenceType( + Context.getRecordType(RD).withConst()); + return false; + } + break; + } + + case CXXMoveConstructor: + case CXXMoveAssignment: { + // Trivial move operations always have non-cv-qualified parameters. + const RValueReferenceType *RT = + Param0->getType()->getAs(); + if (!RT || RT->getPointeeType().getCVRQualifiers()) { + if (Diagnose) + Diag(Param0->getLocation(), diag::note_nontrivial_param_type) + << Param0->getSourceRange() << Param0->getType() + << Context.getRValueReferenceType(Context.getRecordType(RD)); + return false; + } + break; + } + + case CXXInvalid: + llvm_unreachable("not a special member"); + } + + // FIXME: We require that the parameter-declaration-clause is equivalent to + // that of an implicit declaration, not just that the declared parameter type + // matches, in order to prevent absuridities like a function simultaneously + // being a trivial copy constructor and a non-trivial default constructor. + // This issue has not yet been assigned a core issue number. + if (MD->getMinRequiredArguments() < MD->getNumParams()) { + if (Diagnose) + Diag(MD->getParamDecl(MD->getMinRequiredArguments())->getLocation(), + diag::note_nontrivial_default_arg) + << MD->getParamDecl(MD->getMinRequiredArguments())->getSourceRange(); + return false; + } + if (MD->isVariadic()) { + if (Diagnose) + Diag(MD->getLocation(), diag::note_nontrivial_variadic); + return false; + } + + // C++11 [class.ctor]p5, C++11 [class.dtor]p5: + // A copy/move [constructor or assignment operator] is trivial if + // -- the [member] selected to copy/move each direct base class subobject + // is trivial + // + // C++11 [class.copy]p12, C++11 [class.copy]p25: + // A [default constructor or destructor] is trivial if + // -- all the direct base classes have trivial [default constructors or + // destructors] + for (CXXRecordDecl::base_class_iterator BI = RD->bases_begin(), + BE = RD->bases_end(); BI != BE; ++BI) + if (!checkTrivialSubobjectCall(*this, BI->getLocStart(), + ConstArg ? BI->getType().withConst() + : BI->getType(), + CSM, TSK_BaseClass, Diagnose)) + return false; + + // C++11 [class.ctor]p5, C++11 [class.dtor]p5: + // A copy/move [constructor or assignment operator] for a class X is + // trivial if + // -- for each non-static data member of X that is of class type (or array + // thereof), the constructor selected to copy/move that member is + // trivial + // + // C++11 [class.copy]p12, C++11 [class.copy]p25: + // A [default constructor or destructor] is trivial if + // -- 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 [default + // constructor or destructor] + if (!checkTrivialClassMembers(*this, RD, CSM, ConstArg, Diagnose)) + return false; + + // C++11 [class.dtor]p5: + // A destructor is trivial if [...] + // -- the destructor is not virtual + if (CSM == CXXDestructor && MD->isVirtual()) { + if (Diagnose) + Diag(MD->getLocation(), diag::note_nontrivial_virtual_dtor) << RD; + return false; + } + + // C++11 [class.ctor]p5, C++11 [class.copy]p12, C++11 [class.copy]p25: + // A [special member] for class X is trivial if [...] + // -- class X has no virtual functions and no virtual base classes + if (CSM != CXXDestructor && MD->getParent()->isDynamicClass()) { + if (!Diagnose) + return false; + + if (RD->getNumVBases()) { + // Check for virtual bases. We already know that the corresponding + // member in all bases is trivial, so vbases must all be direct. + CXXBaseSpecifier &BS = *RD->vbases_begin(); + assert(BS.isVirtual()); + Diag(BS.getLocStart(), diag::note_nontrivial_has_virtual) << RD << 1; + return false; + } + + // Must have a virtual method. + for (CXXRecordDecl::method_iterator MI = RD->method_begin(), + ME = RD->method_end(); MI != ME; ++MI) { + if (MI->isVirtual()) { + SourceLocation MLoc = MI->getLocStart(); + Diag(MLoc, diag::note_nontrivial_has_virtual) << RD << 0; + return false; + } + } + + llvm_unreachable("dynamic class with no vbases and no virtual functions"); + } + + // Looks like it's trivial! + return true; +} + /// \brief Data used with FindHiddenVirtualMethod namespace { struct FindHiddenVirtualMethodData { @@ -7113,7 +7477,46 @@ void Sema::ActOnFinishDelayedMemberInitializers(Decl *D) { CXXRecordDecl *ClassDecl = cast(D); if (!ClassDecl->isDependentType()) - CheckExplicitlyDefaultedMethods(ClassDecl); + CheckExplicitlyDefaultedAndDeletedMethods(ClassDecl); + + // C++11 [dcl.constexpr]p8: A constexpr specifier for a non-static member + // function that is not a constructor declares that member function to be + // const. [...] The class of which that function is a member shall be + // a literal type. + // + // If the class has virtual bases, any constexpr members will already have + // been diagnosed by the checks performed on the member declaration, so + // suppress this (less useful) diagnostic. + // + // We delay this until we know whether an explicitly-defaulted (or deleted) + // destructor for the class is trivial. + if (LangOpts.CPlusPlus0x && !ClassDecl->isDependentType() && + !ClassDecl->isLiteral() && !ClassDecl->getNumVBases()) { + for (CXXRecordDecl::method_iterator M = ClassDecl->method_begin(), + MEnd = ClassDecl->method_end(); + M != MEnd; ++M) { + if (M->isConstexpr() && M->isInstance() && !isa(*M)) { + switch (ClassDecl->getTemplateSpecializationKind()) { + case TSK_ImplicitInstantiation: + case TSK_ExplicitInstantiationDeclaration: + case TSK_ExplicitInstantiationDefinition: + // If a template instantiates to a non-literal type, but its members + // instantiate to constexpr functions, the template is technically + // ill-formed, but we allow it for sanity. + continue; + + case TSK_Undeclared: + case TSK_ExplicitSpecialization: + RequireLiteralType(M->getLocation(), Context.getRecordType(ClassDecl), + diag::err_constexpr_method_non_literal); + break; + } + + // Only produce one error per class. + break; + } + } + } } void Sema::DeclareInheritedConstructors(CXXRecordDecl *ClassDecl) { @@ -10395,35 +10798,6 @@ void Sema::SetDeclDeleted(Decl *Dcl, SourceLocation DelLoc) { // recovery. } Fn->setDeletedAsWritten(); - - CXXMethodDecl *MD = dyn_cast(Dcl); - if (!MD) - return; - - // A deleted special member function is trivial if the corresponding - // implicitly-declared function would have been. - switch (getSpecialMember(MD)) { - case CXXInvalid: - break; - case CXXDefaultConstructor: - MD->setTrivial(MD->getParent()->hasTrivialDefaultConstructor()); - break; - case CXXCopyConstructor: - MD->setTrivial(MD->getParent()->hasTrivialCopyConstructor()); - break; - case CXXMoveConstructor: - MD->setTrivial(MD->getParent()->hasTrivialMoveConstructor()); - break; - case CXXCopyAssignment: - MD->setTrivial(MD->getParent()->hasTrivialCopyAssignment()); - break; - case CXXMoveAssignment: - MD->setTrivial(MD->getParent()->hasTrivialMoveAssignment()); - break; - case CXXDestructor: - MD->setTrivial(MD->getParent()->hasTrivialDestructor()); - break; - } } void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) { diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index b785e54..5345e8d 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -3058,6 +3058,13 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, // // 1: http://gcc.gnu/.org/onlinedocs/gcc/Type-Traits.html // 2: http://docwiki.embarcadero.com/RADStudio/XE/en/Type_Trait_Functions_(C%2B%2B0x)_Index + // + // Note that these builtins do not behave as documented in g++: if a class + // has both a trivial and a non-trivial special member of a particular kind, + // they return false! For now, we emulate this behavior. + // FIXME: This appears to be a g++ bug: more complex cases reveal that it + // does not correctly compute triviality in the presence of multiple special + // members of the same kind. Revisit this once the g++ bug is fixed. case UTT_HasTrivialDefaultConstructor: // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html: // If __is_pod (type) is true then the trait is true, else if type is @@ -3065,9 +3072,9 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, // constructor ([class.ctor]) then the trait is true, else it is false. if (T.isPODType(Self.Context)) return true; - if (const RecordType *RT = - C.getBaseElementType(T)->getAs()) - return cast(RT->getDecl())->hasTrivialDefaultConstructor(); + if (CXXRecordDecl *RD = C.getBaseElementType(T)->getAsCXXRecordDecl()) + return RD->hasTrivialDefaultConstructor() && + !RD->hasNonTrivialDefaultConstructor(); return false; case UTT_HasTrivialCopy: // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html: @@ -3077,8 +3084,9 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, // is true, else it is false. if (T.isPODType(Self.Context) || T->isReferenceType()) return true; - if (const RecordType *RT = T->getAs()) - return cast(RT->getDecl())->hasTrivialCopyConstructor(); + if (CXXRecordDecl *RD = T->getAsCXXRecordDecl()) + return RD->hasTrivialCopyConstructor() && + !RD->hasNonTrivialCopyConstructor(); return false; case UTT_HasTrivialAssign: // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html: @@ -3093,12 +3101,13 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, // errors if the copy assignment operator is actually used, q.v. // [class.copy]p12). - if (C.getBaseElementType(T).isConstQualified()) + if (T.isConstQualified()) return false; if (T.isPODType(Self.Context)) return true; - if (const RecordType *RT = T->getAs()) - return cast(RT->getDecl())->hasTrivialCopyAssignment(); + if (CXXRecordDecl *RD = T->getAsCXXRecordDecl()) + return RD->hasTrivialCopyAssignment() && + !RD->hasNonTrivialCopyAssignment(); return false; case UTT_HasTrivialDestructor: // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html: @@ -3115,9 +3124,8 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, T.getObjCLifetime() == Qualifiers::OCL_Autoreleasing) return true; - if (const RecordType *RT = - C.getBaseElementType(T)->getAs()) - return cast(RT->getDecl())->hasTrivialDestructor(); + if (CXXRecordDecl *RD = C.getBaseElementType(T)->getAsCXXRecordDecl()) + return RD->hasTrivialDestructor(); return false; // TODO: Propagate nothrowness for implicitly declared special members. case UTT_HasNothrowAssign: @@ -3134,9 +3142,8 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, return false; if (T.isPODType(Self.Context) || T->isObjCLifetimeType()) return true; - if (const RecordType *RT = T->getAs()) { - CXXRecordDecl* RD = cast(RT->getDecl()); - if (RD->hasTrivialCopyAssignment()) + if (CXXRecordDecl *RD = T->getAsCXXRecordDecl()) { + if (RD->hasTrivialCopyAssignment() && !RD->hasNonTrivialCopyAssignment()) return true; bool FoundAssign = false; @@ -3175,9 +3182,9 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, // false. if (T.isPODType(C) || T->isReferenceType() || T->isObjCLifetimeType()) return true; - if (const RecordType *RT = T->getAs()) { - CXXRecordDecl *RD = cast(RT->getDecl()); - if (RD->hasTrivialCopyConstructor()) + if (CXXRecordDecl *RD = T->getAsCXXRecordDecl()) { + if (RD->hasTrivialCopyConstructor() && + !RD->hasNonTrivialCopyConstructor()) return true; bool FoundConstructor = false; @@ -3216,9 +3223,9 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, // throw an exception then the trait is true, else it is false. if (T.isPODType(C) || T->isObjCLifetimeType()) return true; - if (const RecordType *RT = C.getBaseElementType(T)->getAs()) { - CXXRecordDecl *RD = cast(RT->getDecl()); - if (RD->hasTrivialDefaultConstructor()) + if (CXXRecordDecl *RD = C.getBaseElementType(T)->getAsCXXRecordDecl()) { + if (RD->hasTrivialDefaultConstructor() && + !RD->hasNonTrivialDefaultConstructor()) return true; DeclContext::lookup_const_iterator Con, ConEnd; @@ -3245,11 +3252,9 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html: // If type is a class type with a virtual destructor ([class.dtor]) // then the trait is true, else it is false. - if (const RecordType *Record = T->getAs()) { - CXXRecordDecl *RD = cast(Record->getDecl()); + if (CXXRecordDecl *RD = T->getAsCXXRecordDecl()) if (CXXDestructorDecl *Destructor = Self.LookupDestructor(RD)) return Destructor->isVirtual(); - } return false; // These type trait expressions are modeled on the specifications for the diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 2355544..337534e 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -1581,10 +1581,10 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, SemaRef.CheckOverrideControl(Method); // If a function is defined as defaulted or deleted, mark it as such now. - if (D->isDefaulted()) - Method->setDefaulted(); + if (D->isExplicitlyDefaulted()) + SemaRef.SetDeclDefaulted(Method, Method->getLocation()); if (D->isDeletedAsWritten()) - Method->setDeletedAsWritten(); + SemaRef.SetDeclDeleted(Method, Method->getLocation()); // If there's a function template, let our caller handle it. if (FunctionTemplate) { @@ -1610,13 +1610,6 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, Owner->addDecl(Method); } - if (D->isExplicitlyDefaulted()) { - SemaRef.SetDeclDefaulted(Method, Method->getLocation()); - } else { - assert(!D->isDefaulted() && - "should not implicitly default uninstantiated function"); - } - return Method; } diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 7b2973f..2c7b7c1 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -4564,6 +4564,8 @@ bool Sema::RequireLiteralType(SourceLocation Loc, QualType T, Diag(Dtor->getLocation(), Dtor->isUserProvided() ? diag::note_non_literal_user_provided_dtor : diag::note_non_literal_nontrivial_dtor) << RD; + if (!Dtor->isUserProvided()) + SpecialMemberIsTrivial(Dtor, CXXDestructor, /*Diagnose*/true); } return true; diff --git a/clang/test/CXX/basic/basic.types/p10.cpp b/clang/test/CXX/basic/basic.types/p10.cpp index 191d42b..6401c29 100644 --- a/clang/test/CXX/basic/basic.types/p10.cpp +++ b/clang/test/CXX/basic/basic.types/p10.cpp @@ -39,7 +39,7 @@ struct UserProvDtor { struct NonTrivDtor { constexpr NonTrivDtor(); constexpr int f(); // expected-error {{non-literal type 'NonTrivDtor' cannot have constexpr members}} - virtual ~NonTrivDtor() = default; // expected-note {{has a non-trivial destructor}} + virtual ~NonTrivDtor() = default; // expected-note {{has a non-trivial destructor}} expected-note {{because it is virtual}} }; struct NonTrivDtorBase { ~NonTrivDtorBase(); diff --git a/clang/test/CXX/class/class.union/p1.cpp b/clang/test/CXX/class/class.union/p1.cpp index 556a9bb..439cc9c 100644 --- a/clang/test/CXX/class/class.union/p1.cpp +++ b/clang/test/CXX/class/class.union/p1.cpp @@ -14,25 +14,25 @@ class VirtualBase : virtual Okay { // expected-note 4 {{because type 'VirtualBas }; class Ctor { - Ctor() { abort(); } // expected-note 4 {{because type 'Ctor' has a user-declared constructor}} + Ctor() { abort(); } // expected-note 2{{because type 'Ctor' has a user-provided default constructor}} expected-note 2{{here}} }; class Ctor2 { - Ctor2(); // expected-note 3 {{because type 'Ctor2' has a user-declared constructor}} + Ctor2(); // expected-note {{because type 'Ctor2' has a user-provided default constructor}} expected-note 2{{here}} }; -class CtorTmpl { - template CtorTmpl(); // expected-note {{because type 'CtorTmpl' has a user-declared constructor}} +class CtorTmpl { // expected-note {{because type 'CtorTmpl' has no default constructor}} + template CtorTmpl(); // expected-note {{implicit default constructor suppressed by user-declared constructor}} }; -class CopyCtor { - CopyCtor(CopyCtor &cc) { abort(); } // expected-note 4 {{because type 'CopyCtor' has a user-declared copy constructor}} +class CopyCtor { // expected-note 2{{because no constructor can be used to copy an object of type 'const CopyCtor'}} + CopyCtor(CopyCtor &cc) { abort(); } }; -class CopyAssign { - CopyAssign& operator=(CopyAssign& CA) { abort(); } // expected-note 4 {{because type 'CopyAssign' has a user-declared copy assignment operator}} +class CopyAssign { // expected-note 2 {{because no assignment operator can be used to copy an object of type 'const CopyAssign'}} + CopyAssign& operator=(CopyAssign& CA) { abort(); } }; class Dtor { - ~Dtor() { abort(); } // expected-note 4 {{because type 'Dtor' has a user-declared destructor}} + ~Dtor() { abort(); } // expected-note 2 {{because type 'Dtor' has a user-provided destructor}} expected-note 2{{here}} }; union U1 { @@ -49,25 +49,25 @@ union U1 { union U2 { struct { - Virtual v; // expected-note {{because type 'U2:: struct trivially_copyable_check { + static_assert(B == __has_trivial_copy(T), ""); + static_assert(B == __is_trivially_constructible(T, T), ""); + static_assert(B == __is_trivially_constructible(T, const T &), ""); + static_assert(B == __is_trivially_constructible(T, T &&), ""); + typedef void type; +}; +template using trivially_copyable = + typename trivially_copyable_check::type; +template using not_trivially_copyable = + typename trivially_copyable_check::type; + +struct Trivial {}; +using _ = trivially_copyable; + +// A copy/move constructor for class X is trivial if it is not user-provided, +struct UserProvided { + UserProvided(const UserProvided &); +}; +using _ = not_trivially_copyable; + +// its declared parameter type is the same as if it had been implicitly +// declared, +struct NonConstCopy { + NonConstCopy(NonConstCopy &) = default; +}; +using _ = not_trivially_copyable; + +// class X has no virtual functions +struct VFn { + virtual void f(); +}; +using _ = not_trivially_copyable; + +// and no virtual base classes +struct VBase : virtual Trivial {}; +using _ = not_trivially_copyable; + +// and the constructor selected to copy/move each [direct subobject] is trivial +struct TemplateCtor { + template TemplateCtor(T &); +}; +using _ = trivially_copyable; +struct TemplateCtorMember { + TemplateCtor tc; +}; +using _ = trivially_copyable; + +// We can select a non-trivial copy ctor even if there is a trivial one. +struct MutableTemplateCtorMember { + mutable TemplateCtor mtc; +}; +// FIXME: This is wrong! The "trivial" copy constructor calls the templated +// constructor for the mutable member. +static_assert(!__is_trivially_constructible(MutableTemplateCtorMember, const MutableTemplateCtorMember &), ""); // expected-error {{}} +static_assert(__is_trivially_constructible(MutableTemplateCtorMember, MutableTemplateCtorMember &&), ""); +struct MutableTemplateCtorMember2 { + MutableTemplateCtorMember2(const MutableTemplateCtorMember2 &) = default; + MutableTemplateCtorMember2(MutableTemplateCtorMember2 &&) = default; + mutable TemplateCtor mtc; +}; +static_assert(!__is_trivially_constructible(MutableTemplateCtorMember2, const MutableTemplateCtorMember2 &), ""); +static_assert(__is_trivially_constructible(MutableTemplateCtorMember2, MutableTemplateCtorMember2 &&), ""); + +// Both trivial and non-trivial special members. +struct TNT { + TNT(const TNT &) = default; // trivial + TNT(TNT &); // non-trivial + + TNT(TNT &&) = default; // trivial + TNT(const TNT &&); // non-trivial +}; + +static_assert(!__has_trivial_copy(TNT), "lie deliberately for gcc compatibility"); +static_assert(__is_trivially_constructible(TNT, TNT), ""); +static_assert(!__is_trivially_constructible(TNT, TNT &), ""); +static_assert(__is_trivially_constructible(TNT, const TNT &), ""); +static_assert(!__is_trivially_constructible(TNT, volatile TNT &), ""); +static_assert(__is_trivially_constructible(TNT, TNT &&), ""); +static_assert(!__is_trivially_constructible(TNT, const TNT &&), ""); +static_assert(!__is_trivially_constructible(TNT, volatile TNT &&), ""); + +// This has only trivial special members. +struct DerivedFromTNT : TNT {}; + +static_assert(__has_trivial_copy(DerivedFromTNT), ""); +static_assert(__is_trivially_constructible(DerivedFromTNT, DerivedFromTNT), ""); +static_assert(__is_trivially_constructible(DerivedFromTNT, DerivedFromTNT &), ""); +static_assert(__is_trivially_constructible(DerivedFromTNT, const DerivedFromTNT &), ""); +static_assert(!__is_trivially_constructible(DerivedFromTNT, volatile DerivedFromTNT &), ""); +static_assert(__is_trivially_constructible(DerivedFromTNT, DerivedFromTNT &&), ""); +static_assert(__is_trivially_constructible(DerivedFromTNT, const DerivedFromTNT &&), ""); +static_assert(!__is_trivially_constructible(DerivedFromTNT, volatile DerivedFromTNT &&), ""); + +// This has only trivial special members. +struct TNTMember { + TNT tnt; +}; + +static_assert(__has_trivial_copy(TNTMember), ""); +static_assert(__is_trivially_constructible(TNTMember, TNTMember), ""); +static_assert(__is_trivially_constructible(TNTMember, TNTMember &), ""); +static_assert(__is_trivially_constructible(TNTMember, const TNTMember &), ""); +static_assert(!__is_trivially_constructible(TNTMember, volatile TNTMember &), ""); +static_assert(__is_trivially_constructible(TNTMember, TNTMember &&), ""); +static_assert(__is_trivially_constructible(TNTMember, const TNTMember &&), ""); +static_assert(!__is_trivially_constructible(TNTMember, volatile TNTMember &&), ""); + +struct NCCTNT : NonConstCopy, TNT {}; + +static_assert(!__has_trivial_copy(NCCTNT), ""); +static_assert(!__is_trivially_constructible(NCCTNT, NCCTNT), ""); +static_assert(!__is_trivially_constructible(NCCTNT, NCCTNT &), ""); +static_assert(!__is_trivially_constructible(NCCTNT, const NCCTNT &), ""); +static_assert(!__is_trivially_constructible(NCCTNT, volatile NCCTNT &), ""); +static_assert(!__is_trivially_constructible(NCCTNT, NCCTNT &&), ""); +static_assert(!__is_trivially_constructible(NCCTNT, const NCCTNT &&), ""); +static_assert(!__is_trivially_constructible(NCCTNT, volatile NCCTNT &&), ""); diff --git a/clang/test/CXX/special/class.copy/p25-0x.cpp b/clang/test/CXX/special/class.copy/p25-0x.cpp new file mode 100644 index 0000000..e9df3b3 --- /dev/null +++ b/clang/test/CXX/special/class.copy/p25-0x.cpp @@ -0,0 +1,143 @@ +// RUN: %clang_cc1 -std=c++11 -verify %s + +template struct trivially_assignable_check { + static_assert(B == __has_trivial_assign(T), ""); + static_assert(B == __is_trivially_assignable(T&, T), ""); + static_assert(B == __is_trivially_assignable(T&, const T &), ""); + static_assert(B == __is_trivially_assignable(T&, T &&), ""); + static_assert(B == __is_trivially_assignable(T&&, T), ""); + static_assert(B == __is_trivially_assignable(T&&, const T &), ""); + static_assert(B == __is_trivially_assignable(T&&, T &&), ""); + typedef void type; +}; +template using trivially_assignable = + typename trivially_assignable_check::type; +template using not_trivially_assignable = + typename trivially_assignable_check::type; + +struct Trivial {}; +using _ = trivially_assignable; + +// A copy/move assignment operator for class X is trivial if it is not user-provided, +struct UserProvided { + UserProvided &operator=(const UserProvided &); +}; +using _ = not_trivially_assignable; + +// its declared parameter type is the same as if it had been implicitly +// declared, +struct NonConstCopy { + NonConstCopy &operator=(NonConstCopy &) = default; +}; +using _ = not_trivially_assignable; + +// class X has no virtual functions +struct VFn { + virtual void f(); +}; +using _ = not_trivially_assignable; + +// and no virtual base classes +struct VBase : virtual Trivial {}; +using _ = not_trivially_assignable; + +// and the assignment operator selected to copy/move each [direct subobject] is trivial +struct TemplateCtor { + template TemplateCtor operator=(T &); +}; +using _ = trivially_assignable; +struct TemplateCtorMember { + TemplateCtor tc; +}; +using _ = trivially_assignable; +struct MutableTemplateCtorMember { + mutable TemplateCtor mtc; +}; +// FIXME: This is wrong! The "trivial" copy constructor calls the templated +// constructor for the mutable member. +static_assert(!__is_trivially_assignable(MutableTemplateCtorMember, const MutableTemplateCtorMember &), ""); // expected-error {{}} +static_assert(__is_trivially_assignable(MutableTemplateCtorMember, MutableTemplateCtorMember &&), ""); + +// Both trivial and non-trivial special members. +struct TNT { + TNT &operator=(const TNT &) = default; // trivial + TNT &operator=(TNT &); // non-trivial + + TNT &operator=(TNT &&) = default; // trivial + TNT &operator=(const TNT &&); // non-trivial +}; + +static_assert(!__has_trivial_assign(TNT), "lie deliberately for gcc compatibility"); +static_assert(__is_trivially_assignable(TNT, TNT), ""); +static_assert(!__is_trivially_assignable(TNT, TNT &), ""); +static_assert(__is_trivially_assignable(TNT, const TNT &), ""); +static_assert(!__is_trivially_assignable(TNT, volatile TNT &), ""); +static_assert(__is_trivially_assignable(TNT, TNT &&), ""); +static_assert(!__is_trivially_assignable(TNT, const TNT &&), ""); +static_assert(!__is_trivially_assignable(TNT, volatile TNT &&), ""); + +// This has only trivial special members. +struct DerivedFromTNT : TNT {}; + +static_assert(__has_trivial_assign(DerivedFromTNT), ""); +static_assert(__is_trivially_assignable(DerivedFromTNT, DerivedFromTNT), ""); +static_assert(__is_trivially_assignable(DerivedFromTNT, DerivedFromTNT &), ""); +static_assert(__is_trivially_assignable(DerivedFromTNT, const DerivedFromTNT &), ""); +static_assert(!__is_trivially_assignable(DerivedFromTNT, volatile DerivedFromTNT &), ""); +static_assert(__is_trivially_assignable(DerivedFromTNT, DerivedFromTNT &&), ""); +static_assert(__is_trivially_assignable(DerivedFromTNT, const DerivedFromTNT &&), ""); +static_assert(!__is_trivially_assignable(DerivedFromTNT, volatile DerivedFromTNT &&), ""); + +// This has only trivial special members. +struct TNTMember { + TNT tnt; +}; + +static_assert(__has_trivial_assign(TNTMember), ""); +static_assert(__is_trivially_assignable(TNTMember, TNTMember), ""); +static_assert(__is_trivially_assignable(TNTMember, TNTMember &), ""); +static_assert(__is_trivially_assignable(TNTMember, const TNTMember &), ""); +static_assert(!__is_trivially_assignable(TNTMember, volatile TNTMember &), ""); +static_assert(__is_trivially_assignable(TNTMember, TNTMember &&), ""); +static_assert(__is_trivially_assignable(TNTMember, const TNTMember &&), ""); +static_assert(!__is_trivially_assignable(TNTMember, volatile TNTMember &&), ""); + +struct NCCTNT : NonConstCopy, TNT {}; + +static_assert(!__has_trivial_assign(NCCTNT), ""); +static_assert(!__is_trivially_assignable(NCCTNT, NCCTNT), ""); +static_assert(!__is_trivially_assignable(NCCTNT, NCCTNT &), ""); +static_assert(!__is_trivially_assignable(NCCTNT, const NCCTNT &), ""); +static_assert(!__is_trivially_assignable(NCCTNT, volatile NCCTNT &), ""); +static_assert(!__is_trivially_assignable(NCCTNT, NCCTNT &&), ""); +static_assert(!__is_trivially_assignable(NCCTNT, const NCCTNT &&), ""); +static_assert(!__is_trivially_assignable(NCCTNT, volatile NCCTNT &&), ""); + +struct MultipleTrivial { + // All four of these are trivial. + MultipleTrivial &operator=(const MultipleTrivial &) & = default; + MultipleTrivial &operator=(const MultipleTrivial &) && = default; + MultipleTrivial &operator=(MultipleTrivial &&) & = default; + MultipleTrivial &operator=(MultipleTrivial &&) && = default; +}; + +using _ = trivially_assignable; + +struct RefQualifier { + RefQualifier &operator=(const RefQualifier &) & = default; + RefQualifier &operator=(const RefQualifier &) &&; + RefQualifier &operator=(RefQualifier &&) &; + RefQualifier &operator=(RefQualifier &&) && = default; +}; +struct DerivedFromRefQualifier : RefQualifier { + // Both of these call the trivial copy operation. + DerivedFromRefQualifier &operator=(const DerivedFromRefQualifier &) & = default; + DerivedFromRefQualifier &operator=(const DerivedFromRefQualifier &) && = default; + // Both of these call the non-trivial move operation. + DerivedFromRefQualifier &operator=(DerivedFromRefQualifier &&) & = default; + DerivedFromRefQualifier &operator=(DerivedFromRefQualifier &&) && = default; +}; +static_assert(__is_trivially_assignable(DerivedFromRefQualifier&, const DerivedFromRefQualifier&), ""); +static_assert(__is_trivially_assignable(DerivedFromRefQualifier&&, const DerivedFromRefQualifier&), ""); +static_assert(!__is_trivially_assignable(DerivedFromRefQualifier&, DerivedFromRefQualifier&&), ""); +static_assert(!__is_trivially_assignable(DerivedFromRefQualifier&&, DerivedFromRefQualifier&&), ""); diff --git a/clang/test/CXX/special/class.ctor/p5-0x.cpp b/clang/test/CXX/special/class.ctor/p5-0x.cpp index 1aaeef2..ab8fdb0 100644 --- a/clang/test/CXX/special/class.ctor/p5-0x.cpp +++ b/clang/test/CXX/special/class.ctor/p5-0x.cpp @@ -149,26 +149,41 @@ static_assert(__has_trivial_constructor(Trivial), "Trivial is nontrivial"); class NonTrivialDefCtor1 { NonTrivialDefCtor1(); }; static_assert(!__has_trivial_constructor(NonTrivialDefCtor1), "NonTrivialDefCtor1 is trivial"); +#define ASSERT_NONTRIVIAL_IMPL(Class, Bases, Body) \ + class Class Bases { Body }; \ + static_assert(!__has_trivial_constructor(Class), ""); +#define ASSERT_NONTRIVIAL(Class, Bases, Body) \ + ASSERT_NONTRIVIAL_IMPL(Class, Bases, Body) \ + ASSERT_NONTRIVIAL_IMPL(Def ## Class, Bases, Def ## Class() = default; Body) \ + ASSERT_NONTRIVIAL_IMPL(Del ## Class, Bases, Del ## Class() = delete; Body) + // - its class has no virtual functions (10.3) and no virtual base classes (10.1), and -class NonTrivialDefCtor2 { virtual void f(); }; -static_assert(!__has_trivial_constructor(NonTrivialDefCtor2), "NonTrivialDefCtor2 is trivial"); -class NonTrivialDefCtor3 : virtual Trivial {}; -static_assert(!__has_trivial_constructor(NonTrivialDefCtor3), "NonTrivialDefCtor3 is trivial"); +ASSERT_NONTRIVIAL(NonTrivialDefCtor2, , virtual void f();) +ASSERT_NONTRIVIAL(NonTrivialDefCtor3, : virtual Trivial, ) // - no non-static data member of its class has a brace-or-equal-initializer, and -class NonTrivialDefCtor4 { int m = 52; }; -static_assert(!__has_trivial_constructor(NonTrivialDefCtor4), "NonTrivialDefCtor4 is trivial"); +ASSERT_NONTRIVIAL(NonTrivialDefCtor4, , int m = 52;) // - all the direct base classes of its class have trivial default constructors, and -class NonTrivialDefCtor5 : NonTrivialDefCtor1 {}; -static_assert(!__has_trivial_constructor(NonTrivialDefCtor5), "NonTrivialDefCtor5 is trivial"); +ASSERT_NONTRIVIAL(NonTrivialDefCtor5, : NonTrivialDefCtor1, ) // - for all the non-static data members of its class that are of class type (or array thereof), each such class // has a trivial default constructor. -class NonTrivialDefCtor6 { NonTrivialDefCtor1 t; }; -static_assert(!__has_trivial_constructor(NonTrivialDefCtor6), "NonTrivialDefCtor5 is trivial"); +ASSERT_NONTRIVIAL(NonTrivialDefCtor6, , NonTrivialDefCtor1 t;) + +// FIXME: No core issue number yet. +// - its parameter-declaration-clause is equivalent to that of an implicit declaration. +struct NonTrivialDefCtor7 { + NonTrivialDefCtor7(...) = delete; +}; +static_assert(!__has_trivial_constructor(NonTrivialDefCtor7), ""); +struct NonTrivialDefCtor8 { + NonTrivialDefCtor8(int = 0) = delete; +}; +static_assert(!__has_trivial_constructor(NonTrivialDefCtor8), ""); // Otherwise, the default constructor is non-trivial. + class Trivial2 { Trivial2() = delete; }; static_assert(__has_trivial_constructor(Trivial2), "Trivial2 is trivial"); diff --git a/clang/test/SemaCXX/anonymous-struct.cpp b/clang/test/SemaCXX/anonymous-struct.cpp index 19a88d7..8a61041 100644 --- a/clang/test/SemaCXX/anonymous-struct.cpp +++ b/clang/test/SemaCXX/anonymous-struct.cpp @@ -1,7 +1,7 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s struct S { - S(); // expected-note {{because type 'S' has a user-declared constructor}} + S(); // expected-note {{because type 'S' has a user-provided default constructor}} }; struct { // expected-error {{anonymous structs and classes must be class members}} @@ -9,7 +9,7 @@ struct { // expected-error {{anonymous structs and classes must be class members struct E { struct { - S x; // expected-error {{anonymous struct member 'x' has a non-trivial constructor}} + S x; // expected-error {{anonymous struct member 'x' has a non-trivial constructor}} }; static struct { }; diff --git a/clang/test/SemaCXX/cxx0x-cursory-default-delete.cpp b/clang/test/SemaCXX/cxx0x-cursory-default-delete.cpp index 641760e..b1078dc 100644 --- a/clang/test/SemaCXX/cxx0x-cursory-default-delete.cpp +++ b/clang/test/SemaCXX/cxx0x-cursory-default-delete.cpp @@ -36,9 +36,9 @@ struct non_const_derived : non_const_copy { }; struct bad_decls { - bad_decls(volatile bad_decls&) = default; // expected-error {{may not be volatile}} expected-error {{must be defaulted outside the class}} + bad_decls(volatile bad_decls&) = default; // expected-error {{may not be volatile}} bad_decls&& operator = (bad_decls) = default; // expected-error {{lvalue reference}} expected-error {{must return 'bad_decls &'}} - bad_decls& operator = (volatile bad_decls&) = default; // expected-error {{may not be volatile}} expected-error {{must be defaulted outside the class}} + bad_decls& operator = (volatile bad_decls&) = default; // expected-error {{may not be volatile}} bad_decls& operator = (const bad_decls&) const = default; // expected-error {{may not have 'const', 'constexpr' or 'volatile' qualifiers}} }; @@ -57,14 +57,18 @@ struct except_spec_d_good : except_spec_a, except_spec_b { ~except_spec_d_good(); }; except_spec_d_good::~except_spec_d_good() = default; -// FIXME: This should error in the virtual override check. -// It doesn't because we generate the implicit specification later than -// appropriate. +struct except_spec_d_good2 : except_spec_a, except_spec_b { + ~except_spec_d_good2() = default; +}; struct except_spec_d_bad : except_spec_a, except_spec_b { - ~except_spec_d_bad() = default; + ~except_spec_d_bad() noexcept; }; +// FIXME: This should error because this exception spec is not +// compatible with the implicit exception spec. +except_spec_d_bad::~except_spec_d_bad() noexcept = default; -// FIXME: This should error because the exceptions spec doesn't match. +// FIXME: This should error because this exception spec is not +// compatible with the implicit exception spec. struct except_spec_d_mismatch : except_spec_a, except_spec_b { except_spec_d_mismatch() throw(A) = default; }; diff --git a/clang/test/SemaCXX/cxx98-compat.cpp b/clang/test/SemaCXX/cxx98-compat.cpp index d497d45..830ab9b 100644 --- a/clang/test/SemaCXX/cxx98-compat.cpp +++ b/clang/test/SemaCXX/cxx98-compat.cpp @@ -254,13 +254,13 @@ namespace CopyCtorIssues { namespace UnionOrAnonStructMembers { struct NonTrivCtor { - NonTrivCtor(); // expected-note 2{{user-declared constructor}} + NonTrivCtor(); // expected-note 2{{user-provided default constructor}} }; struct NonTrivCopy { - NonTrivCopy(const NonTrivCopy&); // expected-note 2{{user-declared copy constructor}} + NonTrivCopy(const NonTrivCopy&); // expected-note 2{{user-provided copy constructor}} }; struct NonTrivDtor { - ~NonTrivDtor(); // expected-note 2{{user-declared destructor}} + ~NonTrivDtor(); // expected-note 2{{user-provided destructor}} }; union BadUnion { NonTrivCtor ntc; // expected-warning {{union member 'ntc' with a non-trivial constructor is incompatible with C++98}} @@ -338,8 +338,8 @@ namespace NullPointerTemplateArg { namespace PR13480 { struct basic_iterator { - basic_iterator(const basic_iterator &it) {} - basic_iterator(basic_iterator &it) {} // expected-note {{because type 'PR13480::basic_iterator' has a user-declared copy constructor}} + basic_iterator(const basic_iterator &it) {} // expected-note {{because type 'PR13480::basic_iterator' has a user-provided copy constructor}} + basic_iterator(basic_iterator &it) {} }; union test { @@ -349,12 +349,12 @@ namespace PR13480 { namespace AssignOpUnion { struct a { - void operator=(const a &it) {} - void operator=(a &it) {} // expected-note {{because type 'AssignOpUnion::a' has a user-declared copy assignment operator}} + void operator=(const a &it) {} // expected-note {{because type 'AssignOpUnion::a' has a user-provided copy assignment operator}} + void operator=(a &it) {} }; struct b { - void operator=(const b &it) {} // expected-note {{because type 'AssignOpUnion::b' has a user-declared copy assignment operator}} + void operator=(const b &it) {} // expected-note {{because type 'AssignOpUnion::b' has a user-provided copy assignment operator}} }; union test1 { @@ -364,9 +364,9 @@ namespace AssignOpUnion { } namespace rdar11736429 { - struct X { + struct X { // expected-note {{because type 'rdar11736429::X' has no default constructor}} X(const X&) = delete; // expected-warning{{deleted function definitions are incompatible with C++98}} \ - // expected-note{{because type 'rdar11736429::X' has a user-declared constructor}} + // expected-note {{implicit default constructor suppressed by user-declared constructor}} }; union S { -- 2.7.4