diff options
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.td | 31 | ||||
-rw-r--r-- | include/clang/Sema/Sema.h | 26 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 267 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 21 | ||||
-rw-r--r-- | lib/Sema/SemaExprCXX.cpp | 3 | ||||
-rw-r--r-- | lib/Sema/SemaInit.cpp | 48 | ||||
-rw-r--r-- | lib/Sema/SemaLookup.cpp | 20 | ||||
-rw-r--r-- | test/CXX/dcl.decl/dcl.init/dcl.init.aggr/p1-0x.cpp | 4 | ||||
-rw-r--r-- | test/CXX/special/class.copy/implicit-move.cpp | 6 | ||||
-rw-r--r-- | test/CXX/special/class.copy/p11.0x.copy.cpp | 36 | ||||
-rw-r--r-- | test/CXX/special/class.copy/p11.0x.move.cpp | 4 | ||||
-rw-r--r-- | test/CXX/special/class.ctor/p5-0x.cpp | 59 | ||||
-rw-r--r-- | test/CXX/special/class.dtor/p5-0x.cpp | 55 | ||||
-rw-r--r-- | test/SemaCXX/cxx0x-deleted-default-ctor.cpp | 46 | ||||
-rw-r--r-- | test/SemaCXX/cxx98-compat-flags.cpp | 6 | ||||
-rw-r--r-- | test/SemaCXX/cxx98-compat.cpp | 6 | ||||
-rw-r--r-- | test/SemaCXX/defaulted-private-dtor.cpp | 6 | ||||
-rw-r--r-- | test/SemaCXX/dr1301.cpp | 22 | ||||
-rw-r--r-- | test/SemaCXX/implicit-exception-spec.cpp | 4 | ||||
-rw-r--r-- | test/SemaCXX/value-initialization.cpp | 5 |
20 files changed, 410 insertions, 265 deletions
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 30780104d6..32ac7be9e5 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -2821,6 +2821,37 @@ def warn_cxx98_compat_friend_redefinition : Warning< "friend function %0 would be implicitly redefined in C++98">, InGroup<CXX98Compat>, DefaultIgnore; +def note_deleted_dtor_no_operator_delete : Note< + "virtual destructor requires an unambiguous, accessible 'operator delete'">; +def note_deleted_special_member_class_subobject : Note< + "%select{default constructor|copy constructor|move constructor|" + "copy assignment operator|move assignment operator|destructor}0 of " + "%select{||||union }4%1 is implicitly deleted because " + "%select{base class %3|field %3}2 has " + "%select{no|a deleted|multiple|an inaccessible|a non-trivial}4 " + "%select{%select{default constructor|copy constructor|move constructor|copy " + "assignment operator|move assignment operator|destructor}0|destructor}5" + "%select{||s||}4">; +def note_deleted_default_ctor_uninit_field : Note< + "default constructor of %0 is implicitly deleted because field %1 of " + "%select{reference|const-qualified}3 type %2 would not be initialized">; +def note_deleted_default_ctor_all_const : Note< + "default constructor of %0 is implicitly deleted because all " + "%select{data members|data members of an anonymous union member}1" + " are const-qualified">; +def note_deleted_copy_ctor_rvalue_reference : Note< + "copy constructor of %0 is implicitly deleted because field %1 is of " + "rvalue reference type %2">; +def note_deleted_copy_user_declared_move : Note< + "copy %select{constructor|assignment operator}0 is implicitly deleted because" + " %1 has a user-declared move %select{constructor|assignment operator}2">; +def note_deleted_assign_field : Note< + "%select{copy|move}0 assignment operator of %0 is implicitly deleted " + "because field %1 is of %select{reference|const-qualified}3 type %2">; +def note_deleted_move_assign_virtual_base : Note< + "move assignment operator of %0 is implicitly deleted because it has a " + "virtual base class %1">; + // This should eventually be an error. def warn_undefined_internal : Warning< "%select{function|variable}0 %q1 has internal linkage but is not defined">, diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index cd8b1e96d9..045b2fa69a 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -660,7 +660,17 @@ public: /// This is used for determining parameter types of other objects and is /// utterly meaningless on other types of special members. class SpecialMemberOverloadResult : public llvm::FastFoldingSetNode { + public: + enum Kind { + NoMemberOrDeleted, + Ambiguous, + SuccessNonConst, + SuccessConst + }; + + private: llvm::PointerIntPair<CXXMethodDecl*, 2> Pair; + public: SpecialMemberOverloadResult(const llvm::FoldingSetNodeID &ID) : FastFoldingSetNode(ID) @@ -669,15 +679,11 @@ public: CXXMethodDecl *getMethod() const { return Pair.getPointer(); } void setMethod(CXXMethodDecl *MD) { Pair.setPointer(MD); } - bool hasSuccess() const { return Pair.getInt() & 0x1; } - void setSuccess(bool B) { - Pair.setInt(unsigned(B) | hasConstParamMatch() << 1); - } + Kind getKind() const { return static_cast<Kind>(Pair.getInt()); } + void setKind(Kind K) { Pair.setInt(K); } - bool hasConstParamMatch() const { return Pair.getInt() & 0x2; } - void setConstParamMatch(bool B) { - Pair.setInt(B << 1 | unsigned(hasSuccess())); - } + bool hasSuccess() const { return getKind() >= SuccessNonConst; } + bool hasConstParamMatch() const { return getKind() == SuccessConst; } }; /// \brief A cache of special member function overload resolution results @@ -2421,6 +2427,7 @@ public: bool CanUseDecl(NamedDecl *D); bool DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc, const ObjCInterfaceDecl *UnknownObjCClass=0); + void NoteDeletedFunction(FunctionDecl *FD); std::string getDeletedOrUnavailableSuffix(const FunctionDecl *FD); bool DiagnosePropertyAccessorMismatch(ObjCPropertyDecl *PD, ObjCMethodDecl *Getter, @@ -3127,7 +3134,8 @@ public: /// \brief Determine if a special member function should have a deleted /// definition when it is defaulted. - bool ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM); + bool ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM, + bool Diagnose = false); /// \brief Declare the implicit default constructor for the given class. /// diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index c59e97af72..5a64d09bae 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -4333,6 +4333,7 @@ struct SpecialMemberDeletionInfo { Sema &S; CXXMethodDecl *MD; Sema::CXXSpecialMember CSM; + bool Diagnose; // Properties of the special member, computed for convenience. bool IsConstructor, IsAssignment, IsMove, ConstArg, VolatileArg; @@ -4341,8 +4342,8 @@ struct SpecialMemberDeletionInfo { bool AllFieldsAreConst; SpecialMemberDeletionInfo(Sema &S, CXXMethodDecl *MD, - Sema::CXXSpecialMember CSM) - : S(S), MD(MD), CSM(CSM), + Sema::CXXSpecialMember CSM, bool Diagnose) + : S(S), MD(MD), CSM(CSM), Diagnose(Diagnose), IsConstructor(false), IsAssignment(false), IsMove(false), ConstArg(false), VolatileArg(false), Loc(MD->getLocation()), AllFieldsAreConst(true) { @@ -4385,35 +4386,76 @@ struct SpecialMemberDeletionInfo { TQ & Qualifiers::Volatile); } - bool shouldDeleteForClassSubobject(CXXRecordDecl *Class, FieldDecl *Field); + typedef llvm::PointerUnion<CXXBaseSpecifier*, FieldDecl*> Subobject; - bool shouldDeleteForBase(CXXRecordDecl *BaseDecl, bool IsVirtualBase); + bool shouldDeleteForBase(CXXBaseSpecifier *Base); bool shouldDeleteForField(FieldDecl *FD); bool shouldDeleteForAllConstMembers(); + + bool shouldDeleteForClassSubobject(CXXRecordDecl *Class, Subobject Subobj); + bool shouldDeleteForSubobjectCall(Subobject Subobj, + Sema::SpecialMemberOverloadResult *SMOR, + bool IsDtorCallInCtor); }; } +/// Check whether we should delete a special member due to the implicit +/// definition containing a call to a special member of a subobject. +bool SpecialMemberDeletionInfo::shouldDeleteForSubobjectCall( + Subobject Subobj, Sema::SpecialMemberOverloadResult *SMOR, + bool IsDtorCallInCtor) { + CXXMethodDecl *Decl = SMOR->getMethod(); + FieldDecl *Field = Subobj.dyn_cast<FieldDecl*>(); + + int DiagKind = -1; + + if (SMOR->getKind() == Sema::SpecialMemberOverloadResult::NoMemberOrDeleted) + DiagKind = !Decl ? 0 : 1; + else if (SMOR->getKind() == Sema::SpecialMemberOverloadResult::Ambiguous) + DiagKind = 2; + else if (S.CheckDirectMemberAccess(Loc, Decl, S.PDiag()) + != Sema::AR_accessible) + DiagKind = 3; + else if (!IsDtorCallInCtor && Field && Field->getParent()->isUnion() && + !Decl->isTrivial()) { + // A member of a union must have a trivial corresponding special member. + // As a weird special case, a destructor call from a union's constructor + // must be accessible and non-deleted, but need not be trivial. Such a + // destructor is never actually called, but is semantically checked as + // if it were. + DiagKind = 4; + } + + if (DiagKind == -1) + return false; + + if (Diagnose) { + if (Field) { + S.Diag(Field->getLocation(), + diag::note_deleted_special_member_class_subobject) + << CSM << MD->getParent() << /*IsField*/true + << Field << DiagKind << IsDtorCallInCtor; + } else { + CXXBaseSpecifier *Base = Subobj.get<CXXBaseSpecifier*>(); + S.Diag(Base->getLocStart(), + diag::note_deleted_special_member_class_subobject) + << CSM << MD->getParent() << /*IsField*/false + << Base->getType() << DiagKind << IsDtorCallInCtor; + } + + if (DiagKind == 1) + S.NoteDeletedFunction(Decl); + // FIXME: Explain inaccessibility if DiagKind == 3. + } + + return true; +} + /// Check whether we should delete a special member function due to having a /// direct or virtual base class or static data member of class type M. bool SpecialMemberDeletionInfo::shouldDeleteForClassSubobject( - CXXRecordDecl *Class, FieldDecl *Field) { - // C++11 [class.ctor]p5, C++11 [class.copy]p11, C++11 [class.dtor]p5: - // -- any direct or virtual base class [...] has a type with a destructor - // that is deleted or inaccessible - if (!IsAssignment) { - CXXDestructorDecl *Dtor = S.LookupDestructor(Class); - if (Dtor->isDeleted()) - return true; - if (S.CheckDestructorAccess(Loc, Dtor, S.PDiag()) != Sema::AR_accessible) - return true; - - // C++11 [class.dtor]p5: - // -- X is a union-like class that has a variant member with a non-trivial - // destructor - if (CSM == Sema::CXXDestructor && Field && Field->getParent()->isUnion() && - !Dtor->isTrivial()) - return true; - } + CXXRecordDecl *Class, Subobject Subobj) { + FieldDecl *Field = Subobj.dyn_cast<FieldDecl*>(); // C++11 [class.ctor]p5: // -- any direct or virtual base class, or non-static data member with no @@ -4426,58 +4468,62 @@ bool SpecialMemberDeletionInfo::shouldDeleteForClassSubobject( // overload resolution, as applied to B's corresponding special member, // results in an ambiguity or a function that is deleted or inaccessible // from the defaulted special member - if (CSM != Sema::CXXDestructor && - !(CSM == Sema::CXXDefaultConstructor && + // C++11 [class.dtor]p5: + // -- any direct or virtual base class [...] has a type with a destructor + // that is deleted or inaccessible + if (!(CSM == Sema::CXXDefaultConstructor && Field && Field->hasInClassInitializer())) { Sema::SpecialMemberOverloadResult *SMOR = lookupIn(Class); - if (!SMOR->hasSuccess()) - return true; - CXXMethodDecl *Member = SMOR->getMethod(); - // A member of a union must have a trivial corresponding special member. - if (Field && Field->getParent()->isUnion() && !Member->isTrivial()) + if (shouldDeleteForSubobjectCall(Subobj, SMOR, false)) return true; - if (IsConstructor) { + // FIXME: CWG 1402 moves these bullets elsewhere. + if (CSM == Sema::CXXMoveConstructor) { CXXConstructorDecl *Ctor = cast<CXXConstructorDecl>(Member); - if (S.CheckConstructorAccess(Loc, Ctor, Ctor->getAccess(), S.PDiag()) - != Sema::AR_accessible) - return true; - // -- for the move constructor, a [...] direct or virtual base class with // a type that does not have a move constructor and is not trivially // copyable. - if (IsMove && !Ctor->isMoveConstructor() && !Class->isTriviallyCopyable()) + if (!Ctor->isMoveConstructor() && !Class->isTriviallyCopyable()) return true; - } else { - assert(IsAssignment && "unexpected kind of special member"); - if (S.CheckDirectMemberAccess(Loc, Member, S.PDiag()) - != Sema::AR_accessible) - return true; - + } else if (CSM == Sema::CXXMoveAssignment) { // -- for the move assignment operator, a direct base class with a type // that does not have a move assignment operator and is not trivially // copyable. - if (IsMove && !Member->isMoveAssignmentOperator() && - !Class->isTriviallyCopyable()) + if (!Member->isMoveAssignmentOperator() && !Class->isTriviallyCopyable()) return true; } } + // C++11 [class.ctor]p5, C++11 [class.copy]p11: + // -- any direct or virtual base class or non-static data member has a + // type with a destructor that is deleted or inaccessible + if (IsConstructor) { + Sema::SpecialMemberOverloadResult *SMOR = + S.LookupSpecialMember(Class, Sema::CXXDestructor, + false, false, false, false, false); + if (shouldDeleteForSubobjectCall(Subobj, SMOR, true)) + return true; + } + return false; } /// Check whether we should delete a special member function due to the class /// having a particular direct or virtual base class. -bool SpecialMemberDeletionInfo::shouldDeleteForBase(CXXRecordDecl *BaseDecl, - bool IsVirtualBase) { +bool SpecialMemberDeletionInfo::shouldDeleteForBase(CXXBaseSpecifier *Base) { // C++11 [class.copy]p23: // -- for the move assignment operator, any direct or indirect virtual // base class. - if (CSM == Sema::CXXMoveAssignment && IsVirtualBase) + if (CSM == Sema::CXXMoveAssignment && Base->isVirtual()) { + if (Diagnose) + S.Diag(Base->getLocStart(), diag::note_deleted_move_assign_virtual_base) + << MD->getParent() << Base->getType(); return true; + } - if (shouldDeleteForClassSubobject(BaseDecl, 0)) + if (shouldDeleteForClassSubobject(Base->getType()->getAsCXXRecordDecl(), + Base)) return true; return false; @@ -4492,29 +4538,52 @@ bool SpecialMemberDeletionInfo::shouldDeleteForField(FieldDecl *FD) { if (CSM == Sema::CXXDefaultConstructor) { // For a default constructor, all references must be initialized in-class // and, if a union, it must have a non-const member. - if (FieldType->isReferenceType() && !FD->hasInClassInitializer()) + if (FieldType->isReferenceType() && !FD->hasInClassInitializer()) { + if (Diagnose) + S.Diag(FD->getLocation(), diag::note_deleted_default_ctor_uninit_field) + << MD->getParent() << FD << FieldType << /*Reference*/0; return true; - - if (inUnion() && !FieldType.isConstQualified()) - AllFieldsAreConst = false; - + } // C++11 [class.ctor]p5: any non-variant non-static data member of // const-qualified type (or array thereof) with no // brace-or-equal-initializer does not have a user-provided default // constructor. if (!inUnion() && FieldType.isConstQualified() && !FD->hasInClassInitializer() && - (!FieldRecord || !FieldRecord->hasUserProvidedDefaultConstructor())) + (!FieldRecord || !FieldRecord->hasUserProvidedDefaultConstructor())) { + if (Diagnose) + S.Diag(FD->getLocation(), diag::note_deleted_default_ctor_uninit_field) + << MD->getParent() << FD << FieldType << /*Const*/1; return true; + } + + if (inUnion() && !FieldType.isConstQualified()) + AllFieldsAreConst = false; } else if (CSM == Sema::CXXCopyConstructor) { // For a copy constructor, data members must not be of rvalue reference // type. - if (FieldType->isRValueReferenceType()) + if (FieldType->isRValueReferenceType()) { + if (Diagnose) + S.Diag(FD->getLocation(), diag::note_deleted_copy_ctor_rvalue_reference) + << MD->getParent() << FD << FieldType; return true; + } } else if (IsAssignment) { // For an assignment operator, data members must not be of reference type. - if (FieldType->isReferenceType()) + if (FieldType->isReferenceType()) { + if (Diagnose) + S.Diag(FD->getLocation(), diag::note_deleted_assign_field) + << IsMove << MD->getParent() << FD << FieldType << /*Reference*/0; + return true; + } + if (!FieldRecord && FieldType.isConstQualified()) { + // C++11 [class.copy]p23: + // -- a non-static data member of const non-class type (or array thereof) + if (Diagnose) + S.Diag(FD->getLocation(), diag::note_deleted_assign_field) + << IsMove << MD->getParent() << FD << FieldType << /*Const*/1; return true; + } } if (FieldRecord) { @@ -4540,8 +4609,13 @@ bool SpecialMemberDeletionInfo::shouldDeleteForField(FieldDecl *FD) { // At least one member in each anonymous union must be non-const if (CSM == Sema::CXXDefaultConstructor && AllVariantFieldsAreConst && - FieldRecord->field_begin() != FieldRecord->field_end()) + FieldRecord->field_begin() != FieldRecord->field_end()) { + if (Diagnose) + S.Diag(FieldRecord->getLocation(), + diag::note_deleted_default_ctor_all_const) + << MD->getParent() << /*anonymous union*/1; return true; + } // Don't check the implicit member of the anonymous union type. // This is technically non-conformant, but sanity demands it. @@ -4550,10 +4624,6 @@ bool SpecialMemberDeletionInfo::shouldDeleteForField(FieldDecl *FD) { if (shouldDeleteForClassSubobject(FieldRecord, FD)) return true; - } else if (IsAssignment && FieldType.isConstQualified()) { - // C++11 [class.copy]p23: - // -- a non-static data member of const non-class type (or array thereof) - return true; } return false; @@ -4565,40 +4635,81 @@ bool SpecialMemberDeletionInfo::shouldDeleteForField(FieldDecl *FD) { bool SpecialMemberDeletionInfo::shouldDeleteForAllConstMembers() { // This is a silly definition, because it gives an empty union a deleted // default constructor. Don't do that. - return CSM == Sema::CXXDefaultConstructor && inUnion() && AllFieldsAreConst && - (MD->getParent()->field_begin() != MD->getParent()->field_end()); + if (CSM == Sema::CXXDefaultConstructor && inUnion() && AllFieldsAreConst && + (MD->getParent()->field_begin() != MD->getParent()->field_end())) { + if (Diagnose) + S.Diag(MD->getParent()->getLocation(), + diag::note_deleted_default_ctor_all_const) + << MD->getParent() << /*not anonymous union*/0; + return true; + } + return false; } /// Determine whether a defaulted special member function should be defined as /// deleted, as specified in C++11 [class.ctor]p5, C++11 [class.copy]p11, /// C++11 [class.copy]p23, and C++11 [class.dtor]p5. -bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM) { +bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM, + bool Diagnose) { assert(!MD->isInvalidDecl()); CXXRecordDecl *RD = MD->getParent(); assert(!RD->isDependentType() && "do deletion after instantiation"); if (!LangOpts.CPlusPlus0x || RD->isInvalidDecl()) return false; - // FIXME: Provide the ability to diagnose why a special member was deleted. - // C++11 [expr.lambda.prim]p19: // The closure type associated with a lambda-expression has a // deleted (8.4.3) default constructor and a deleted copy // assignment operator. if (RD->isLambda() && - (CSM == CXXDefaultConstructor || CSM == CXXCopyAssignment)) + (CSM == CXXDefaultConstructor || CSM == CXXCopyAssignment)) { + if (Diagnose) + Diag(RD->getLocation(), diag::note_lambda_decl); return true; + } + + // C++11 [class.copy]p7, p18: + // If the class definition declares a move constructor or move assignment + // operator, an implicitly declared copy constructor or copy assignment + // operator is defined as deleted. + if (MD->isImplicit() && + (CSM == CXXCopyConstructor || CSM == CXXCopyAssignment)) { + CXXMethodDecl *UserDeclaredMove = 0; + + // In Microsoft mode, a user-declared move only causes the deletion of the + // corresponding copy operation, not both copy operations. + if (RD->hasUserDeclaredMoveConstructor() && + (!getLangOpts().MicrosoftMode || CSM == CXXCopyConstructor)) { + if (!Diagnose) return true; + UserDeclaredMove = RD->getMoveConstructor(); + } else if (RD->hasUserDeclaredMoveAssignment() && + (!getLangOpts().MicrosoftMode || CSM == CXXCopyAssignment)) { + if (!Diagnose) return true; + UserDeclaredMove = RD->getMoveAssignmentOperator(); + } + + if (UserDeclaredMove) { + Diag(UserDeclaredMove->getLocation(), + diag::note_deleted_copy_user_declared_move) + << (CSM == CXXMoveAssignment) << RD + << UserDeclaredMove->isMoveAssignmentOperator(); + return true; + } + } // C++11 [class.dtor]p5: // -- for a virtual destructor, lookup of the non-array deallocation function // results in an ambiguity or in a function that is deleted or inaccessible - if (CSM == Sema::CXXDestructor && MD->isVirtual()) { + if (CSM == CXXDestructor && MD->isVirtual()) { FunctionDecl *OperatorDelete = 0; DeclarationName Name = Context.DeclarationNames.getCXXOperatorName(OO_Delete); if (FindDeallocationFunction(MD->getLocation(), MD->getParent(), Name, - OperatorDelete, false)) + OperatorDelete, false)) { + if (Diagnose) + Diag(RD->getLocation(), diag::note_deleted_dtor_no_operator_delete); return true; + } } // For an anonymous struct or union, the copy and assignment special members @@ -4611,17 +4722,17 @@ bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM) { // Do access control from the special member function ContextRAII MethodContext(*this, MD); - SpecialMemberDeletionInfo SMI(*this, MD, CSM); + SpecialMemberDeletionInfo SMI(*this, MD, CSM, Diagnose); for (CXXRecordDecl::base_class_iterator BI = RD->bases_begin(), BE = RD->bases_end(); BI != BE; ++BI) if (!BI->isVirtual() && - SMI.shouldDeleteForBase(BI->getType()->getAsCXXRecordDecl(), false)) + SMI.shouldDeleteForBase(BI)) return true; for (CXXRecordDecl::base_class_iterator BI = RD->vbases_begin(), BE = RD->vbases_end(); BI != BE; ++BI) - if (SMI.shouldDeleteForBase(BI->getType()->getAsCXXRecordDecl(), true)) + if (SMI.shouldDeleteForBase(BI)) return true; for (CXXRecordDecl::field_iterator FI = RD->field_begin(), @@ -7603,12 +7714,9 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) { // assignment operator, there is no user-declared move constructor, and // there is no user-declared move assignment operator, a copy assignment // operator is implicitly declared as defaulted. - if ((ClassDecl->hasUserDeclaredMoveConstructor() && - !getLangOpts().MicrosoftMode) || - ClassDecl->hasUserDeclaredMoveAssignment() || - ShouldDeleteSpecialMember(CopyAssignment, CXXCopyAssignment)) + if (ShouldDeleteSpecialMember(CopyAssignment, CXXCopyAssignment)) CopyAssignment->setDeletedAsWritten(); - + AddOverriddenMethods(ClassDecl, CopyAssignment); return CopyAssignment; } @@ -8522,12 +8630,9 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( // constructor, there is no user-declared move constructor, and there is no // user-declared move assignment operator, a copy constructor is implicitly // declared as defaulted. - if (ClassDecl->hasUserDeclaredMoveConstructor() || - (ClassDecl->hasUserDeclaredMoveAssignment() && - !getLangOpts().MicrosoftMode) || - ShouldDeleteSpecialMember(CopyConstructor, CXXCopyConstructor)) + if (ShouldDeleteSpecialMember(CopyConstructor, CXXCopyConstructor)) CopyConstructor->setDeletedAsWritten(); - + return CopyConstructor; } diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 88ef8cd5d8..97cb647229 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -108,6 +108,25 @@ static AvailabilityResult DiagnoseAvailabilityOfDecl(Sema &S, return Result; } +/// \brief Emit a note explaining that this function is deleted or unavailable. +void Sema::NoteDeletedFunction(FunctionDecl *Decl) { + CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Decl); + + if (Method && Method->isImplicit()) { + CXXSpecialMember CSM = getSpecialMember(Method); + // It is possible for us to no longer be able to determine why the special + // member function was deleted, due to a field or base class having acquired + // a new special member function by the addition of a default argument. + // FIXME: Add a test and a special-case diagnostic for this. + if (CSM != CXXInvalid && + ShouldDeleteSpecialMember(Method, CSM, /*Diagnose=*/true)) + return; + } + + Diag(Decl->getLocation(), diag::note_unavailable_here) + << 1 << Decl->isDeleted(); +} + /// \brief Determine whether the use of this declaration is valid, and /// emit any corresponding diagnostics. /// @@ -151,7 +170,7 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc, if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { if (FD->isDeleted()) { Diag(Loc, diag::err_deleted_function_use); - Diag(D->getLocation(), diag::note_unavailable_here) << 1 << true; + NoteDeletedFunction(FD); return true; } } diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index ec2332cc3c..4692bf8b4b 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -1899,8 +1899,7 @@ bool Sema::FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD, if (Operator->isDeleted()) { if (Diagnose) { Diag(StartLoc, diag::err_deleted_function_use); - Diag(Operator->getLocation(), diag::note_unavailable_here) - << /*function*/ 1 << /*deleted*/ 1; + NoteDeletedFunction(Operator); } return true; } diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 570b240332..125149edc2 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -4482,8 +4482,7 @@ static ExprResult CopyObject(Sema &S, S.Diag(Loc, diag::err_temp_copy_deleted) << (int)Entity.getKind() << CurInitExpr->getType() << CurInitExpr->getSourceRange(); - S.Diag(Best->Function->getLocation(), diag::note_unavailable_here) - << 1 << Best->Function->isDeleted(); + S.NoteDeletedFunction(Best->Function); return ExprError(); } @@ -4592,8 +4591,7 @@ static void CheckCXX98CompatAccessibleCopy(Sema &S, case OR_Deleted: S.Diag(Loc, Diag); - S.Diag(Best->Function->getLocation(), diag::note_unavailable_here) - << 1 << Best->Function->isDeleted(); + S.NoteDeletedFunction(Best->Function); break; } } @@ -5362,26 +5360,6 @@ InitializationSequence::Perform(Sema &S, return move(CurInit); } -/// \brief Provide some notes that detail why a function was implicitly -/// deleted. -static void diagnoseImplicitlyDeletedFunction(Sema &S, CXXMethodDecl *Method) { - // FIXME: This is a work in progress. It should dig deeper to figure out - // why the function was deleted (e.g., because one of its members doesn't - // have a copy constructor, for the copy-constructor case). - if (!Method->isImplicit()) { - S.Diag(Method->getLocation(), diag::note_callee_decl) - << Method->getDeclName(); - } - - if (Method->getParent()->isLambda()) { - S.Diag(Method->getParent()->getLocation(), diag::note_lambda_decl); - return; - } - - S.Diag(Method->getParent()->getLocation(), diag::note_defined_here) - << Method->getParent(); -} - //===----------------------------------------------------------------------===// // Diagnose initialization failures //===----------------------------------------------------------------------===// @@ -5469,8 +5447,7 @@ bool InitializationSequence::Diagnose(Sema &S, = FailedCandidateSet.BestViableFunction(S, Kind.getLocation(), Best, true); if (Ovl == OR_Deleted) { - S.Diag(Best->Function->getLocation(), diag::note_unavailable_here) - << 1 << Best->Function->isDeleted(); + S.NoteDeletedFunction(Best->Function); } else { llvm_unreachable("Inconsistent overload resolution?"); } @@ -5661,20 +5638,15 @@ bool InitializationSequence::Diagnose(Sema &S, // If this is a defaulted or implicitly-declared function, then // it was implicitly deleted. Make it clear that the deletion was // implicit. - if (S.isImplicitlyDeleted(Best->Function)) { + if (S.isImplicitlyDeleted(Best->Function)) S.Diag(Kind.getLocation(), diag::err_ovl_deleted_special_init) - << S.getSpecialMember(cast<CXXMethodDecl>(Best->Function)) + << S.getSpecialMember(cast<CXXMethodDecl>(Best->Function)) << DestType << ArgsRange; - - diagnoseImplicitlyDeletedFunction(S, - cast<CXXMethodDecl>(Best->Function)); - break; - } - - S.Diag(Kind.getLocation(), diag::err_ovl_deleted_init) - << true << DestType << ArgsRange; - S.Diag(Best->Function->getLocation(), diag::note_unavailable_here) - << 1 << Best->Function->isDeleted(); + else + S.Diag(Kind.getLocation(), diag::err_ovl_deleted_init) + << true << DestType << ArgsRange; + + S.NoteDeletedFunction(Best->Function); break; } diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index ed5a8da61c..a8d7b1e971 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -2274,8 +2274,9 @@ Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *RD, CXXDestructorDecl *DD = RD->getDestructor(); assert(DD && "record without a destructor"); Result->setMethod(DD); - Result->setSuccess(!DD->isDeleted()); - Result->setConstParamMatch(false); + Result->setKind(DD->isDeleted() ? + SpecialMemberOverloadResult::NoMemberOrDeleted : + SpecialMemberOverloadResult::SuccessNonConst); return Result; } @@ -2345,7 +2346,8 @@ Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *RD, // will always be a (possibly implicit) declaration to shadow any others. OverloadCandidateSet OCS((SourceLocation())); DeclContext::lookup_iterator I, E; - Result->setConstParamMatch(false); + SpecialMemberOverloadResult::Kind SuccessKind = + SpecialMemberOverloadResult::SuccessNonConst; llvm::tie(I, E) = RD->lookup(Name); assert((I != E) && @@ -2384,7 +2386,7 @@ Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *RD, QualType ArgType = M->getType()->getAs<FunctionProtoType>()->getArgType(0); if (!ArgType->isReferenceType() || ArgType->getPointeeType().isConstQualified()) - Result->setConstParamMatch(true); + SuccessKind = SpecialMemberOverloadResult::SuccessConst; } } else if (FunctionTemplateDecl *Tmpl = dyn_cast<FunctionTemplateDecl>(Cand)) { @@ -2406,18 +2408,22 @@ Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *RD, switch (OCS.BestViableFunction(*this, SourceLocation(), Best)) { case OR_Success: Result->setMethod(cast<CXXMethodDecl>(Best->Function)); - Result->setSuccess(true); + Result->setKind(SuccessKind); break; case OR_Deleted: Result->setMethod(cast<CXXMethodDecl>(Best->Function)); - Result->setSuccess(false); + Result->setKind(SpecialMemberOverloadResult::NoMemberOrDeleted); break; |