diff options
20 files changed, 410 insertions, 265 deletions
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 30780104d6e..32ac7be9e55 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/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/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index cd8b1e96d9f..045b2fa69aa 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/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/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index c59e97af72a..5a64d09baee 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/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/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 88ef8cd5d8e..97cb647229c 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/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/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index ec2332cc3c7..4692bf8b4ba 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/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/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index 570b2403324..125149edc25 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/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/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index ed5a8da61c3..a8d7b1e971b 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/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; case OR_Ambiguous: + Result->setMethod(0); + Result->setKind(SpecialMemberOverloadResult::Ambiguous); + break; + case OR_No_Viable_Function: Result->setMethod(0); - Result->setSuccess(false); + Result->setKind(SpecialMemberOverloadResult::NoMemberOrDeleted); break; } diff --git a/clang/test/CXX/dcl.decl/dcl.init/dcl.init.aggr/p1-0x.cpp b/clang/test/CXX/dcl.decl/dcl.init/dcl.init.aggr/p1-0x.cpp index 47efde2db03..7764980e34f 100644 --- a/clang/test/CXX/dcl.decl/dcl.init/dcl.init.aggr/p1-0x.cpp +++ b/clang/test/CXX/dcl.decl/dcl.init/dcl.init.aggr/p1-0x.cpp @@ -8,7 +8,7 @@ private: protected: struct Inner { int m; }; public: - bool &br; + bool &br; // expected-note {{default constructor of 'Aggr' is implicitly deleted because field 'br' of reference type 'bool &' would not be initialized}} }; bool b; Aggr ag = { b }; @@ -54,7 +54,7 @@ struct NonAggr5 : Aggr { // expected-note 3 {{candidate constructor}} }; NonAggr5 na5 = { b }; // expected-error {{no matching constructor for initialization of 'NonAggr5'}} template<typename...BaseList> -struct MaybeAggr5a : BaseList... {}; // expected-note {{defined here}} +struct MaybeAggr5a : BaseList... {}; // expected-note {{default constructor of 'MaybeAggr5a<Aggr>' is implicitly deleted because base class 'Aggr' has a deleted default constructor}} MaybeAggr5a<> ma5a0 = {}; // ok MaybeAggr5a<Aggr> ma5a1 = {}; // expected-error {{call to implicitly-deleted default constructor of 'MaybeAggr5a<Aggr>'}} diff --git a/clang/test/CXX/special/class.copy/implicit-move.cpp b/clang/test/CXX/special/class.copy/implicit-move.cpp index cc39af97aeb..9ff6f48fad3 100644 --- a/clang/test/CXX/special/class.copy/implicit-move.cpp +++ b/clang/test/CXX/special/class.copy/implicit-move.cpp @@ -87,9 +87,9 @@ private: ~PrivateDestructor() noexcept; }; -struct InheritsPrivateDestructor : PrivateDestructor {}; // expected-note{{defined here}} -struct ContainsPrivateDestructor { // expected-note{{defined here}} - PrivateDestructor pd; +struct InheritsPrivateDestructor : PrivateDestructor {}; // expected-note{{base class 'PrivateDestructor' has an inaccessible destructor}} +struct ContainsPrivateDestructor { + PrivateDestructor pd; // expected-note{{field 'pd' has an inaccessible destructor}} }; struct NonTrivialCopyOnly { diff --git a/clang/test/CXX/special/class.copy/p11.0x.copy.cpp b/clang/test/CXX/special/class.copy/p11.0x.copy.cpp index cbe62b41cbf..b2b4f6a87f7 100644 --- a/clang/test/CXX/special/class.copy/p11.0x.copy.cpp +++ b/clang/test/CXX/special/class.copy/p11.0x.copy.cpp @@ -7,16 +7,16 @@ struct NonTrivial { // A defaulted copy constructor for a class X is defined as deleted if X has: // -- a variant member with a non-trivial corresponding constructor -union DeletedNTVariant { // expected-note{{here}} - NonTrivial NT; +union DeletedNTVariant { + NonTrivial NT; // expected-note{{copy constructor of union 'DeletedNTVariant' is implicitly deleted because field 'NT' has a non-trivial copy constructor}} DeletedNTVariant(); }; DeletedNTVariant DVa; DeletedNTVariant DVb(DVa); // expected-error{{call to implicitly-deleted copy constructor}} -struct DeletedNTVariant2 { // expected-note{{here}} +struct DeletedNTVariant2 { union { - NonTrivial NT; + NonTrivial NT; // expected-note{{copy constructor of union 'DeletedNTVariant2' is implicitly deleted because field 'NT' has a non-trivial copy constructor}} }; DeletedNTVariant2(); }; @@ -34,8 +34,8 @@ private: friend struct HasAccess; }; -struct HasNoAccess { // expected-note{{here}} - NoAccess NA; +struct HasNoAccess { + NoAccess NA; // expected-note{{copy constructor of 'HasNoAccess' is implicitly deleted because field 'NA' has an inaccessible copy constructor}} }; HasNoAccess HNAa; HasNoAccess HNAb(HNAa); // expected-error{{call to implicitly-deleted copy constructor}} @@ -55,16 +55,16 @@ struct Ambiguity { Ambiguity(volatile Ambiguity&); }; -struct IsAmbiguous { // expected-note{{here}} +struct IsAmbiguous { NonConst NC; - Ambiguity A; + Ambiguity A; // expected-note 2{{copy constructor of 'IsAmbiguous' is implicitly deleted because field 'A' has multiple copy constructors}} IsAmbiguous(); }; IsAmbiguous IAa; IsAmbiguous IAb(IAa); // expected-error{{call to implicitly-deleted copy constructor}} -struct Deleted { // expected-note{{here}} - IsAmbiguous IA; +struct Deleted { + IsAmbiguous IA; // expected-note{{copy constructor of 'Deleted' is implicitly deleted because field 'IA' has a deleted copy constructor}} }; Deleted Da; Deleted Db(Da); // expected-error{{call to implicitly-deleted copy constructor}} @@ -72,17 +72,17 @@ Deleted Db(Da); // expected-error{{call to implicitly-deleted copy constructor}} // -- a direct or virtual base class B that cannot be copied because overload // resolution results in an ambiguity or a function that is deleted or // inaccessible -struct AmbiguousCopyBase : Ambiguity { // expected-note {{here}} +struct AmbiguousCopyBase : Ambiguity { // expected-note 2{{copy constructor of 'AmbiguousCopyBase' is implicitly deleted because base class 'Ambiguity' has multiple copy constructors}} NonConst NC; }; extern AmbiguousCopyBase ACBa; AmbiguousCopyBase ACBb(ACBa); // expected-error {{deleted copy constructor}} -struct DeletedCopyBase : AmbiguousCopyBase {}; // expected-note {{here}} +struct DeletedCopyBase : AmbiguousCopyBase {}; // expected-note {{copy constructor of 'DeletedCopyBase' is implicitly deleted because base class 'AmbiguousCopyBase' has a deleted copy constructor}} extern DeletedCopyBase DCBa; DeletedCopyBase DCBb(DCBa); // expected-error {{deleted copy constructor}} -struct InaccessibleCopyBase : NoAccess {}; // expected-note {{here}} +struct InaccessibleCopyBase : NoAccess {}; // expected-note {{copy constructor of 'InaccessibleCopyBase' is implicitly deleted because base class 'NoAccess' has an inaccessible copy constructor}} extern InaccessibleCopyBase ICBa; InaccessibleCopyBase ICBb(ICBa); // expected-error {{deleted copy constructor}} @@ -94,8 +94,8 @@ private: friend struct HasAccessDtor; }; -struct HasNoAccessDtor { // expected-note{{here}} - NoAccessDtor NAD; +struct HasNoAccessDtor { + NoAccessDtor NAD; // expected-note{{copy constructor of 'HasNoAccessDtor' is implicitly deleted because field 'NAD' has an inaccessible destructor}} HasNoAccessDtor(); ~HasNoAccessDtor(); }; @@ -108,14 +108,14 @@ struct HasAccessDtor { HasAccessDtor HADa; HasAccessDtor HADb(HADa); -struct HasNoAccessDtorBase : NoAccessDtor { // expected-note{{here}} +struct HasNoAccessDtorBase : NoAccessDtor { // expected-note{{copy constructor of 'HasNoAccessDtorBase' is implicitly deleted because base class 'NoAccessDtor' has an inaccessible destructor}} }; extern HasNoAccessDtorBase HNADBa; HasNoAccessDtorBase HNADBb(HNADBa); // expected-error{{implicitly-deleted copy constructor}} // -- a non-static data member of rvalue reference type -struct RValue { // expected-note{{here}} - int && ri = 1; +struct RValue { + int && ri = 1; // expected-note{{copy constructor of 'RValue' is implicitly deleted because field 'ri' is of rvalue reference type 'int &&'}} }; RValue RVa; RValue RVb(RVa); // expected-error{{call to implicitly-deleted copy constructor}} diff --git a/clang/test/CXX/special/class.copy/p11.0x.move.cpp b/clang/test/CXX/special/class.copy/p11.0x.move.cpp index 5315b060a03..3e9cc6b6624 100644 --- a/clang/test/CXX/special/class.copy/p11.0x.move.cpp +++ b/clang/test/CXX/special/class.copy/p11.0x.move.cpp @@ -82,7 +82,7 @@ InaccessibleMoveBase::InaccessibleMoveBase(InaccessibleMoveBase&&) = default; // // -- any direct or virtual base class or non-static data member of a type with // a destructor that is deleted or inaccessible struct NoAccessDtor { - NoAccessDtor(NoAccessDtor&&); + NoAccessDtor(NoAccessDtor&&); // expected-note{{copy constructor is implicitly deleted because 'NoAccessDtor' has a user-declared move constructor}} private: ~NoAccessDtor(); friend struct HasAccessDtor; @@ -100,7 +100,7 @@ struct HasAccessDtor { }; HasAccessDtor::HasAccessDtor(HasAccessDtor&&) = default; -struct HasNoAccessDtorBase : NoAccessDtor { // expected-note{{here}} +struct HasNoAccessDtorBase : NoAccessDtor { // expected-note{{copy constructor of 'HasNoAccessDtorBase' is implicitly deleted because base class 'NoAccessDtor' has a deleted copy constructor}} }; extern HasNoAccessDtorBase HNADBa; HasNoAccessDtorBase HNADBb(HNADBa); // expected-error{{implicitly-deleted copy constructor}} diff --git a/clang/test/CXX/special/class.ctor/p5-0x.cpp b/clang/test/CXX/special/class.ctor/p5-0x.cpp index 6f434466746..ceb47d8f3ba 100644 --- a/clang/test/CXX/special/class.ctor/p5-0x.cpp +++ b/clang/test/CXX/special/class.ctor/p5-0x.cpp @@ -2,9 +2,9 @@ struct DefaultedDefCtor1 {}; struct DefaultedDefCtor2 { DefaultedDefCtor2() = default; }; -struct DeletedDefCtor { DeletedDefCtor() = delete; DeletedDefCtor(int); }; +struct DeletedDefCtor { DeletedDefCtor() = delete; DeletedDefCtor(int); }; // expected-note {{explicitly marked deleted here}} class PrivateDefCtor { PrivateDefCtor() = default; public: PrivateDefCtor(int); }; -struct DeletedDtor { ~DeletedDtor() = delete; }; +struct DeletedDtor { ~DeletedDtor() = delete; }; // expected-note 4{{explicitly marked deleted here}} class PrivateDtor { ~PrivateDtor() = default; }; class Friend { Friend() = default; ~Friend() = default; @@ -21,7 +21,7 @@ int n; // - X is a union-like class that has a variant member with a non-trivial // default constructor, -union Deleted1a { UserProvidedDefCtor u; }; // expected-note {{defined here}} +union Deleted1a { UserProvidedDefCtor u; }; // expected-note {{default constructor of union 'Deleted1a' is implicitly deleted because field 'u' has a non-trivial default constructor}} Deleted1a d1a; // expected-error {{implicitly-deleted default constructor}} union NotDeleted1a { DefaultedDefCtor1 nu; }; NotDeleted1a nd1a; @@ -30,13 +30,15 @@ NotDeleted1b nd1b; // - any non-static data member with no brace-or-equal-initializer is of // reference type, -class Deleted2a { // expected-note {{defined here}} - Deleted2a() = default; // expected-note {{declared here}} +class Deleted2a { + // FIXME: We should explain that the function was implicitly deleted as a + // result of being defaulted, and why. + Deleted2a() = default; // expected-note 4{{explicitly marked deleted here}} int &a; }; Deleted2a d2a; // expected-error {{implicitly-deleted default constructor}} -struct Deleted2b { // expected-note {{here}} - int &&b; +struct Deleted2b { + int &&b; // expected-note {{default constructor of 'Deleted2b' is implicitly deleted because field 'b' of reference type 'int &&' would not be initialized}} }; Deleted2b d2b; // expected-error {{deleted default constructor}} class NotDeleted2a { int &a = n; }; @@ -49,13 +51,13 @@ NotDeleted2c nd2c; // - 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, -class Deleted3a { const int a; }; // expected-note {{here}} \ +class Deleted3a { const int a; }; // expected-note {{because field 'a' of const-qualified type 'const int' would not be initialized}} \ expected-warning {{does not declare any constructor}} \ expected-note {{will never be initialized}} Deleted3a d3a; // expected-error {{implicitly-deleted default constructor}} -class Deleted3b { const DefaultedDefCtor1 a[42]; }; // expected-note {{here}} +class Deleted3b { const DefaultedDefCtor1 a[42]; }; // expected-note {{because field 'a' of const-qualified type 'const DefaultedDefCtor1' would not be initialized}} Deleted3b d3b; // expected-error {{implicitly-deleted default constructor}} -class Deleted3c { const DefaultedDefCtor2 a; }; // expected-note {{defined here}} +class Deleted3c { const DefaultedDefCtor2 a; }; // expected-note {{because field 'a' of const-qualified type 'const DefaultedDefCtor2' would not be initialized}} Deleted3c d3c; // expected-error {{implicitly-deleted default constructor}} class NotDeleted3a { const int a = 0; }; NotDeleted3a nd3a; @@ -74,14 +76,21 @@ NotDeleted3g nd3g; // - X is a union and all of its variant members are of const-qualified type (or // array thereof), -union Deleted4a { const int a; const int b; const UserProvidedDefCtor c; }; // expected-note {{here}} +union Deleted4a { + const int a; + const int b; + const UserProvidedDefCtor c; // expected-note {{because field 'c' has a non-trivial default constructor}} +}; Deleted4a d4a; // expected-error {{implicitly-deleted default constructor}} union NotDeleted4a { const int a; int b; }; NotDeleted4a nd4a; // - X is a non-union class and all members of any anonymous union member are of // const-qualified type (or array thereof), -struct Deleted5a { union { const int a; }; union { int b; }; }; // expected-note {{here}} +struct Deleted5a { + union { const int a; }; // expected-note {{because all data members of an anonymous union member are const-qualified}} + union { int b; }; +}; Deleted5a d5a; // expected-error {{implicitly-deleted default constructor}} struct NotDeleted5a { union { const int a; int b; }; union { const int c; int d; }; }; NotDeleted5a nd5a; @@ -91,17 +100,17 @@ NotDeleted5a nd5a; // M has no default constructor or overload resolution as applied to M's default // constructor results in an ambiguity or in a function that is deleted or // inaccessible from the defaulted default constructor, or -struct Deleted6a : Deleted2a {}; // expected-note {{here}} +struct Deleted6a : Deleted2a {}; // expected-note {{because base class 'Deleted2a' has a deleted default constructor}} Deleted6a d6a; // expected-error {{implicitly-deleted default constructor}} -struct Deleted6b : virtual Deleted2a {}; // expected-note {{here}} +struct Deleted6b : virtual Deleted2a {}; // expected-note {{because base class 'Deleted2a' has a deleted default constructor}} Deleted6b d6b; // expected-error {{implicitly-deleted default constructor}} -struct Deleted6c { Deleted2a a; }; // expected-note {{here}} +struct Deleted6c { Deleted2a a; }; // expected-note {{because field 'a' has a deleted default constructor}} Deleted6c d6c; // expected-error {{implicitly-deleted default constructor}} -struct Deleted6d { DeletedDefCtor a; }; // expected-note {{here}} +struct Deleted6d { DeletedDefCtor a; }; // expected-note {{because field 'a' has a deleted default constructor}} Deleted6d d6d; // expected-error {{implicitly-deleted default constructor}} struct NotDeleted6a { DeletedDefCtor a = 0; }; NotDeleted6a nd6a; -struct Deleted6e { PrivateDefCtor a; }; // expected-note {{here}} +struct Deleted6e { PrivateDefCtor a; }; // expected-note {{because field 'a' has an inaccessible default constructor}} Deleted6e d6e; // expected-error {{implicitly-deleted default constructor}} struct NotDeleted6b { PrivateDefCtor a = 0; }; NotDeleted6b nd6b; @@ -111,21 +120,21 @@ NotDeleted6c nd6c; // - any direct or virtual base class or non-static data member has a type with // a destructor that is deleted or inaccessible from the defaulted default // constructor. -struct Deleted7a : DeletedDtor {}; // expected-note {{here}} +struct Deleted7a : DeletedDtor {}; // expected-note {{because base class 'DeletedDtor' has a deleted destructor}} Deleted7a d7a; // expected-error {{implicitly-deleted default constructor}} -struct Deleted7b : virtual DeletedDtor {}; // expected-note {{here}} +struct Deleted7b : virtual DeletedDtor {}; // expected-note {{because base class 'DeletedDtor' has a deleted destructor}} Deleted7b d7b; // expected-error {{implicitly-deleted default constructor}} -struct Deleted7c { DeletedDtor a; }; // expected-note {{here}} +struct Deleted7c { DeletedDtor a; }; // expected-note {{because field 'a' has a deleted destructor}} Deleted7c d7c; // expected-error {{implicitly-deleted default constructor}} -struct Deleted7d { DeletedDtor a = {}; }; // expected-note {{here}} +struct Deleted7d { DeletedDtor a = {}; }; // expected-note {{because field 'a' has a deleted destructor}} Deleted7d d7d; // expected-error {{implicitly-deleted default constructor}} -struct Deleted7e : PrivateDtor {}; // expected-note {{here}} +struct Deleted7e : PrivateDtor {}; // expected-note {{base class 'PrivateDtor' has an inaccessible destructor}} Deleted7e d7e; // expected-error {{implicitly-deleted default constructor}} -struct Deleted7f : virtual PrivateDtor {}; // expected-note {{here}} +struct Deleted7f : virtual PrivateDtor {}; // expected-note {{base class 'PrivateDtor' has an inaccessible destructor}} Deleted7f d7f; // expected-error {{implicitly-deleted default constructor}} -struct Deleted7g { PrivateDtor a; }; // expected-note {{here}} +struct Deleted7g { PrivateDtor a; }; // expected-note {{field 'a' has an inaccessible destructor}} Deleted7g d7g; // expected-error {{implicitly-deleted default constructor}} -struct Deleted7h { PrivateDtor a = {}; }; // expected-note {{here}} +struct Deleted7h { PrivateDtor a = {}; }; // expected-note {{field 'a' has an inaccessible destructor}} Deleted7h d7h; // expected-error {{implicitly-deleted default constructor}} struct NotDeleted7i : Friend {}; NotDeleted7i d7i; diff --git a/clang/test/CXX/special/class.dtor/p5-0x.cpp b/clang/test/CXX/special/class.dtor/p5-0x.cpp index cb7038aa9c4..19aa1190647 100644 --- a/clang/test/CXX/special/class.dtor/p5-0x.cpp +++ b/clang/test/CXX/special/class.dtor/p5-0x.cpp @@ -4,7 +4,7 @@ struct NonTrivDtor { ~NonTrivDtor(); }; struct DeletedDtor { - ~DeletedDtor() = delete; + ~DeletedDtor() = delete; // expected-note 5 {{deleted here}} }; class InaccessibleDtor { ~InaccessibleDtor() = default; @@ -14,73 +14,74 @@ class InaccessibleDtor { // -- X is a union-like class that has a variant member with a non-trivial // destructor. -union A1 { // expected-note {{here}} +union A1 { A1(); - NonTrivDtor n; + NonTrivDtor n; // expected-note {{destructor of union 'A1' is implicitly deleted because field 'n' has a non-trivial destructor}} }; A1 a1; // expected-error {{deleted function}} -struct A2 { // expected-note {{here}} +struct A2 { A2(); union { - NonTrivDtor n; + NonTrivDtor n; // expected-note {{because field 'n' has a non-trivial destructor}} }; }; A2 a2; // expected-error {{deleted function}} -union A3 { // expected-note {{here}} +union A3 { A3(); - NonTrivDtor n[3]; + NonTrivDtor n[3]; // expected-note {{because field 'n' has a non-trivial destructor}} }; A3 a3; // expected-error {{deleted function}} -struct A4 { // expected-note {{here}} +struct A4 { A4(); union { - NonTrivDtor n[3]; + NonTrivDtor n[3]; // expected-note {{because field 'n' has a non-trivial destructor}} }; }; A4 a4; // expected-error {{deleted function}} // -- any of the non-static data members has class type M (or array thereof) and // M has a deleted or inaccessible destructor. -struct B1 { // expected-note {{here}} +struct B1 { B1(); - DeletedDtor a; + DeletedDtor a; // expected-note {{because field 'a' has a deleted destructor}} }; B1 b1; // expected-error {{deleted function}} -struct B2 { // expected-note {{here}} +struct B2 { B2(); - InaccessibleDtor a; + InaccessibleDtor a; // expected-note {{because field 'a' has an inaccessible destructor}} }; B2 b2; // expected-error {{deleted function}} -struct B3 { // expected-note {{here}} +struct B3 { B3(); - DeletedDtor a[4]; + DeletedDtor a[4]; // expected-note {{because field 'a' has a deleted destructor}} }; B3 b3; // expected-error {{deleted function}} -struct B4 { // expected-note {{here}} +struct B4 { B4(); - InaccessibleDtor a[4]; + InaccessibleDtor a[4]; // expected-note {{because field 'a' has an inaccessible destructor}} }; B4 b4; // expected-error {{deleted function}} -union B5 { // expected-note {{here}} +union B5 { B5(); - union { - DeletedDtor a; + // FIXME: Describe the anonymous union member better than ''. + union { // expected-note {{because field '' has a deleted destructor}} + DeletedDtor a; // expected-note {{because field 'a' has a deleted destructor}} }; }; B5 b5; // expected-error {{deleted function}} -union B6 { // expected-note {{here}} +union B6 { B6(); - union { - InaccessibleDtor a; + union { // expected-note {{because field '' has a deleted destructor}} + InaccessibleDtor a; // expected-note {{because field 'a' has an inaccessible destructor}} }; }; B6 b6; // expected-error {{deleted function}} // -- any direct or virtual base class has a deleted or inaccessible destructor. -struct C1 : DeletedDtor { C1(); } c1; // expected-error {{deleted function}} expected-note {{here}} -struct C2 : InaccessibleDtor { C2(); } c2; // expected-error {{deleted function}} expected-note {{here}} -struct C3 : virtual DeletedDtor { C3(); } c3; // expected-error {{deleted function}} expected-note {{here}} -struct C4 : virtual InaccessibleDtor { C4(); } c4; // expected-error {{deleted function}} expected-note {{here}} +struct C1 : DeletedDtor { C1(); } c1; // expected-error {{deleted function}} expected-note {{base class 'DeletedDtor' has a deleted destructor}} +struct C2 : InaccessibleDtor { C2(); } c2; // expected-error {{deleted function}} expected-note {{base class 'InaccessibleDtor' has an inaccessible destructor}} +struct C3 : virtual DeletedDtor { C3(); } c3; // expected-error {{deleted function}} expected-note {{base class 'DeletedDtor' has a deleted destructor}} +struct C4 : virtual InaccessibleDtor { C4(); } c4; // expected-error {{deleted function}} expected-note {{base class 'InaccessibleDtor' has an inaccessible destructor}} // -- for a virtual destructor, lookup of the non-array deallocation function // results in an ambiguity or a function that is deleted or inaccessible. diff --git a/clang/test/SemaCXX/cxx0x-deleted-default-ctor.cpp b/clang/test/SemaCXX/cxx0x-deleted-default-ctor.cpp index f6e5593d850..a5eaa352e4f 100644 --- a/clang/test/SemaCXX/cxx0x-deleted-default-ctor.cpp +++ b/clang/test/SemaCXX/cxx0x-deleted-default-ctor.cpp @@ -7,23 +7,23 @@ struct non_trivial { ~non_trivial(); }; -union bad_union { // expected-note {{defined here}} - non_trivial nt; +union bad_union { + non_trivial nt; // expected-note {{non-trivial default constructor}} }; bad_union u; // expected-error {{call to implicitly-deleted default constructor}} -union bad_union2 { // expected-note {{defined here}} +union bad_union2 { // expected-note {{all data members are const-qualified}} const int i; }; bad_union2 u2; // expected-error {{call to implicitly-deleted default constructor}} -struct bad_anon { // expected-note {{defined here}} +struct bad_anon { union { - non_trivial nt; + non_trivial nt; // expected-note {{non-trivial default constructor}} }; }; bad_anon a; // expected-error {{call to implicitly-deleted default constructor}} -struct bad_anon2 { // expected-note {{defined here}} - union { +struct bad_anon2 { + union { // expected-note {{all data members of an anonymous union member are const-qualified}} const int i; }; }; @@ -48,8 +48,8 @@ struct good : non_trivial { }; good g; -struct bad_const { // expected-note {{defined here}} - const good g; +struct bad_const { + const good g; // expected-note {{field 'g' of const-qualified type 'const good' would not be initialized}} }; bad_const bc; // expected-error {{call to implicitly-deleted default constructor}} @@ -59,25 +59,25 @@ struct good_const { good_const gc; struct no_default { - no_default() = delete; + no_default() = delete; // expected-note 2{{deleted here}} }; struct no_dtor { - ~no_dtor() = delete; + ~no_dtor() = delete; // expected-note 2{{deleted here}} }; -struct bad_field_default { // expected-note {{defined here}} - no_default nd; +struct bad_field_default { + no_default nd; // expected-note {{field 'nd' has a deleted default constructor}} }; bad_field_default bfd; // expected-error {{call to implicitly-deleted default constructor}} -struct bad_base_default : no_default { // expected-note {{defined here}} +struct bad_base_default : no_default { // expected-note {{base class 'no_default' has a deleted default constructor}} }; bad_base_default bbd; // expected-error {{call to implicitly-deleted default constructor}} -struct bad_field_dtor { // expected-note {{defined here}} - no_dtor nd; +struct bad_field_dtor { + no_dtor nd; // expected-note {{field 'nd' has a deleted destructor}} }; bad_field_dtor bfx; // expected-error {{call to implicitly-deleted default constructor}} -struct bad_base_dtor : no_dtor { // expected-note {{defined here}} +struct bad_base_dtor : no_dtor { // expected-note {{base class 'no_dtor' has a deleted destructor}} }; bad_base_dtor bbx; // expected-error {{call to implicitly-deleted default constructor}} @@ -85,16 +85,16 @@ struct ambiguous_default { ambiguous_default(); ambiguous_default(int = 2); }; -struct has_amb_field { // expected-note {{defined here}} - ambiguous_default ad; +struct has_amb_field { + ambiguous_default ad; // expected-note {{field 'ad' has multiple default constructors}} }; has_amb_field haf; // expected-error {{call to implicitly-deleted default constructor}} class inaccessible_default { inaccessible_default(); }; -struct has_inacc_field { // expected-note {{defined here}} - inaccessible_default id; +struct has_inacc_field { + inaccessible_default id; // expected-note {{field 'id' has an inaccessible default constructor}} }; has_inacc_field hif; // expected-error {{call to implicitly-deleted default constructor}} @@ -107,9 +107,9 @@ struct has_friend { }; has_friend hf; -struct defaulted_delete { // expected-note {{defined here}} +struct defaulted_delete { no_default nd; - defaulted_delete() = default; // expected-note{{declared here}} + defaulted_delete() = default; // expected-note{{deleted here}} }; defaulted_delete dd; // expected-error {{call to implicitly-deleted default constructor}} diff --git a/clang/test/SemaCXX/cxx98-compat-flags.cpp b/clang/test/SemaCXX/cxx98-compat-flags.cpp index fcc048a36d2..6dc24be6bbf 100644 --- a/clang/test/SemaCXX/cxx98-compat-flags.cpp +++ b/clang/test/SemaCXX/cxx98-compat-flags.cpp @@ -24,10 +24,8 @@ namespace CopyCtorIssues { Ambiguous(const Ambiguous &, int = 0); // expected-note {{candidate}} Ambiguous(const Ambiguous &, double = 0); // expected-note {{candidate}} }; - struct Deleted { // expected-note {{here}} - // Copy ctor implicitly defined as deleted because Private's copy ctor is - // inaccessible. - Private p; + struct Deleted { + Private p; // expected-note {{copy constructor of 'Deleted' is implicitly deleted because field 'p' has an inaccessible copy constructor}} }; const Private &a = Private(); // expected-warning {{copying variable of type 'CopyCtorIssues::Private' when binding a reference to a temporary would invoke an inaccessible constructor in C++98}} diff --git a/clang/test/SemaCXX/cxx98-compat.cpp b/clang/test/SemaCXX/cxx98-compat.cpp index fd70875fc81..70cac8d54ec 100644 --- a/clang/test/SemaCXX/cxx98-compat.cpp +++ b/clang/test/SemaCXX/cxx98-compat.cpp @@ -214,10 +214,8 @@ namespace CopyCtorIssues { Ambiguous(const Ambiguous &, int = 0); // expected-note {{candidate}} Ambiguous(const Ambiguous &, double = 0); // expected-note {{candidate}} }; - struct Deleted { // expected-note {{here}} - // Copy ctor implicitly defined as deleted because Private's copy ctor is - // inaccessible. - Private p; + struct Deleted { + Private p; // expected-note {{implicitly deleted}} }; const Private &a = Private(); // expected-warning {{copying variable of type 'CopyCtorIssues::Private' when binding a reference to a temporary would invoke an inaccessible constructor in C++98}} diff --git a/clang/test/SemaCXX/defaulted-private-dtor.cpp b/clang/test/SemaCXX/defaulted-private-dtor.cpp index 600dc3ca617..e6f955501a3 100644 --- a/clang/test/SemaCXX/defaulted-private-dtor.cpp +++ b/clang/test/SemaCXX/defaulted-private-dtor.cpp @@ -12,12 +12,12 @@ void f() { BadDtor dd; // expected-error {{private destructor}} throw dd; // expected-error {{private destructor}} } -struct V { // expected-note {{here}} +struct V { V(); - BadDtor bd; + BadDtor bd; // expected-note {{inaccessible destructor}} }; V v; // expected-error {{deleted function}} -struct W : BadDtor { // expected-note {{here}} +struct W : BadDtor { // expected-note {{inaccessible destructor}} W(); }; W w; // expected-error {{deleted function}} diff --git a/clang/test/SemaCXX/dr1301.cpp b/clang/test/SemaCXX/dr1301.cpp index a348977f50e..c92ff9b714e 100644 --- a/clang/test/SemaCXX/dr1301.cpp +++ b/clang/test/SemaCXX/dr1301.cpp @@ -6,18 +6,18 @@ struct A { // expected-note 2{{candidate}} int a = A().n; // expected-error {{no matching constructor}} struct B { - B() = delete; // expected-note {{here}} + B() = delete; // expected-note 2{{here}} int n; }; int b = B().n; // expected-error {{call to deleted}} -struct C { // expected-note {{here}} - B b; +struct C { + B b; // expected-note {{deleted default constructor}} }; int c = C().b.n; // expected-error {{call to implicitly-deleted default}} -struct D { // expected-note {{defined here}} - D() = default; // expected-note {{declared here}} +struct D { + D() = default; // expected-note {{here}} B b; }; int d = D().b.n; // expected-error {{call to implicitly-deleted default}} @@ -34,8 +34,8 @@ struct F { }; int f = F().n; // ok -union G { // expected-note {{here}} - F f; +union G { + F f; // expected-note {{non-trivial default constructor}} }; int g = G().f.n; // expected-error {{call to implicitly-deleted default}} @@ -46,8 +46,8 @@ private: }; int h = H().n; // expected-error {{private constructor}} -struct I { // expected-note {{here}} - H h; +struct I { + H h; // expected-note {{inaccessible default constructor}} }; int i = I().h.n; // expected-error {{call to implicitly-deleted default}} @@ -59,8 +59,8 @@ struct J { int j1 = J().n; // ok int j2 = J().f(); // ok -union K { // expected-note 2{{here}} - J j; +union K { + J j; // expected-note 2{{non-trivial default constructor}} int m; }; int k1 = K().j.n; // expected-error {{call to implicitly-deleted default}} diff --git a/clang/test/SemaCXX/implicit-exception-spec.cpp b/clang/test/SemaCXX/implicit-exception-spec.cpp index f8ee76727e5..786e8f4a148 100644 --- a/clang/test/SemaCXX/implicit-exception-spec.cpp +++ b/clang/test/SemaCXX/implicit-exception-spec.cpp @@ -54,9 +54,9 @@ namespace ExceptionSpecification { // The same problem arises in delayed parsing of default arguments, // which clang does not yet support. namespace DefaultArgument { - struct Default { // expected-note {{defined here}} + struct Default { struct T { T(int = ExceptionIf<noexcept(Default())::f()); // expected-error {{call to implicitly-deleted default constructor}} - } t; + } t; // expected-note {{has no default constructor}} }; } diff --git a/clang/test/SemaCXX/value-initialization.cpp b/clang/test/SemaCXX/value-initialization.cpp index 3b552e2a428..4e3acbb767c 100644 --- a/clang/test/SemaCXX/value-initialization.cpp +++ b/clang/test/SemaCXX/value-initialization.cpp @@ -1,8 +1,7 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11 -struct A { //expected-note {{defined here}} \ - // expected-warning {{does not declare any constructor to initialize}} - const int i; // expected-note{{const member 'i' will never be initialized}} +struct A { // expected-warning {{does not declare any constructor to initialize}} + const int i; // expected-note{{const member 'i' will never be initialized}} expected-note {{implicitly deleted}} virtual void f() { } }; |