From: Richard Smith Date: Mon, 2 Apr 2012 20:59:25 +0000 (+0000) Subject: Finish PR10217: Ensure we say that a special member was implicitly, not X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=5bdaac5454d93d1dcdc2319818497b685be56fcf;p=clang Finish PR10217: Ensure we say that a special member was implicitly, not explicitly, deleted in all relevant cases, and explain why. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@153894 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 10b3819396..dc9eb4555d 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -1989,8 +1989,9 @@ def note_ovl_candidate_deleted : Note< "constructor (the implicit move constructor)|" "function (the implicit copy assignment operator)|" "function (the implicit move assignment operator)|" - "constructor (inherited)}0%1 " - "has been explicitly %select{made unavailable|deleted}2">; + "constructor (inherited)}0%1 has been " + "%select{explicitly made unavailable|explicitly deleted|" + "implicitly deleted}2">; // Giving the index of the bad argument really clutters this message, and // it's relatively unimportant because 1) it's generally obvious which @@ -2508,7 +2509,7 @@ def err_function_template_spec_no_match : Error< "no function template matches function template specialization %0">; def err_function_template_spec_ambiguous : Error< "function template specialization %0 ambiguously refers to more than one " - "function template; explicitly specify%select{|additional }1 template " + "function template; explicitly specify%select{| additional}1 template " "arguments to identify a particular function template">; def note_function_template_spec_matched : Note< "function template matches specialization %0">; @@ -2798,6 +2799,8 @@ def warn_unavailable_fwdclass_message : Warning< def note_unavailable_here : Note< "%select{declaration|function}0 has been explicitly marked " "%select{unavailable|deleted|deprecated}1 here">; +def note_implicitly_deleted : Note< + "explicitly defaulted function was implicitly deleted here">; def warn_not_enough_argument : Warning< "not enough variable arguments in %0 declaration to fit a sentinel">, InGroup; diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 856f921a78..216663607c 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -4636,6 +4636,13 @@ bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM, return true; } + // For an anonymous struct or union, the copy and assignment special members + // will never be used, so skip the check. For an anonymous union declared at + // namespace scope, the constructor and destructor are used. + if (CSM != CXXDefaultConstructor && CSM != CXXDestructor && + RD->isAnonymousStructOrUnion()) + return false; + // 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 @@ -4667,6 +4674,9 @@ bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM, } } + // Do access control from the special member function + ContextRAII MethodContext(*this, MD); + // 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 @@ -4682,16 +4692,6 @@ bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM, } } - // For an anonymous struct or union, the copy and assignment special members - // will never be used, so skip the check. For an anonymous union declared at - // namespace scope, the constructor and destructor are used. - if (CSM != CXXDefaultConstructor && CSM != CXXDestructor && - RD->isAnonymousStructOrUnion()) - return false; - - // Do access control from the special member function - ContextRAII MethodContext(*this, MD); - SpecialMemberDeletionInfo SMI(*this, MD, CSM, Diagnose); for (CXXRecordDecl::base_class_iterator BI = RD->bases_begin(), diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 97cb647229..2478b03449 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -112,15 +112,18 @@ static AvailabilityResult DiagnoseAvailabilityOfDecl(Sema &S, void Sema::NoteDeletedFunction(FunctionDecl *Decl) { CXXMethodDecl *Method = dyn_cast(Decl); - if (Method && Method->isImplicit()) { + if (Method && Method->isDeleted() && !Method->isDeletedAsWritten()) { + // If the method was explicitly defaulted, point at that declaration. + if (!Method->isImplicit()) + Diag(Decl->getLocation(), diag::note_implicitly_deleted); + + // Try to diagnose why this special member function was implicitly + // deleted. This might fail, if that reason no longer applies. 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; + if (CSM != CXXInvalid) + ShouldDeleteSpecialMember(Method, CSM, /*Diagnose=*/true); + + return; } Diag(Decl->getLocation(), diag::note_unavailable_here) diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index e1d32056eb..27b04a7427 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -8237,7 +8237,8 @@ void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand, OverloadCandidateKind FnKind = ClassifyOverloadCandidate(S, Fn, FnDesc); S.Diag(Fn->getLocation(), diag::note_ovl_candidate_deleted) - << FnKind << FnDesc << Fn->isDeleted(); + << FnKind << FnDesc + << (Fn->isDeleted() ? (Fn->isDeletedAsWritten() ? 1 : 2) : 0); MaybeEmitInheritedConstructorNote(S, Fn); return; } @@ -10086,9 +10087,11 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, << getSpecialMember(Method) << BinaryOperator::getOpcodeStr(Opc) << getDeletedOrUnavailableSuffix(Best->Function); - - if (Method->getParent()->isLambda()) { - Diag(Method->getParent()->getLocation(), diag::note_lambda_decl); + + if (getSpecialMember(Method) != CXXInvalid) { + // The user probably meant to call this special member. Just + // explain why it's deleted. + NoteDeletedFunction(Method); return ExprError(); } } else { diff --git a/test/CXX/special/class.copy/implicit-move.cpp b/test/CXX/special/class.copy/implicit-move.cpp index 9cb4215cd0..7c69dd8b87 100644 --- a/test/CXX/special/class.copy/implicit-move.cpp +++ b/test/CXX/special/class.copy/implicit-move.cpp @@ -25,10 +25,10 @@ struct HasCopyAssignment { HasCopyAssignment & operator =(const HasCopyAssignment &) noexcept(false); }; -struct HasMoveConstructor { // expected-note {{implicit copy assignment}} +struct HasMoveConstructor { ThrowingCopy tc; HasMoveConstructor() noexcept; - HasMoveConstructor(HasMoveConstructor &&) noexcept; + HasMoveConstructor(HasMoveConstructor &&) noexcept; // expected-note {{deleted because 'HasMoveConstructor' has a user-declared move constructor}} }; struct HasMoveAssignment { // expected-note {{implicit copy constructor}} diff --git a/test/CXX/special/class.ctor/p5-0x.cpp b/test/CXX/special/class.ctor/p5-0x.cpp index ceb47d8f3b..694ab5b175 100644 --- a/test/CXX/special/class.ctor/p5-0x.cpp +++ b/test/CXX/special/class.ctor/p5-0x.cpp @@ -31,11 +31,9 @@ NotDeleted1b nd1b; // - any non-static data member with no brace-or-equal-initializer is of // reference type, 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() = default; // expected-note 4{{implicitly deleted here}} + int &a; // expected-note 4{{because field 'a' of reference type 'int &' would not be initialized}} +}; Deleted2a d2a; // expected-error {{implicitly-deleted default constructor}} struct Deleted2b { int &&b; // expected-note {{default constructor of 'Deleted2b' is implicitly deleted because field 'b' of reference type 'int &&' would not be initialized}} diff --git a/test/CXX/special/class.dtor/p5-0x.cpp b/test/CXX/special/class.dtor/p5-0x.cpp index 19aa119064..dbfa004440 100644 --- a/test/CXX/special/class.dtor/p5-0x.cpp +++ b/test/CXX/special/class.dtor/p5-0x.cpp @@ -90,15 +90,15 @@ class D1 { public: virtual ~D1() = default; } d1; // ok -struct D2 : D1 { // expected-note {{deleted here}} +struct D2 : D1 { // expected-note {{virtual destructor requires an unambiguous, accessible 'operator delete'}} // implicitly-virtual destructor } d2; // expected-error {{deleted function}} -struct D3 { - virtual ~D3() = default; // expected-note {{deleted here}} +struct D3 { // expected-note {{virtual destructor requires an unambiguous, accessible 'operator delete'}} + virtual ~D3() = default; // expected-note {{explicitly defaulted function was implicitly deleted here}} void operator delete(void*, double = 0.0); void operator delete(void*, char = 0); } d3; // expected-error {{deleted function}} -struct D4 { - virtual ~D4() = default; // expected-note {{deleted here}} +struct D4 { // expected-note {{virtual destructor requires an unambiguous, accessible 'operator delete'}} + virtual ~D4() = default; // expected-note {{implicitly deleted here}} void operator delete(void*) = delete; } d4; // expected-error {{deleted function}} diff --git a/test/SemaCXX/cxx0x-deleted-default-ctor.cpp b/test/SemaCXX/cxx0x-deleted-default-ctor.cpp index a5eaa352e4..0cebc10ade 100644 --- a/test/SemaCXX/cxx0x-deleted-default-ctor.cpp +++ b/test/SemaCXX/cxx0x-deleted-default-ctor.cpp @@ -59,7 +59,7 @@ struct good_const { good_const gc; struct no_default { - no_default() = delete; // expected-note 2{{deleted here}} + no_default() = delete; // expected-note 3{{deleted here}} }; struct no_dtor { ~no_dtor() = delete; // expected-note 2{{deleted here}} @@ -108,8 +108,8 @@ struct has_friend { has_friend hf; struct defaulted_delete { - no_default nd; - defaulted_delete() = default; // expected-note{{deleted here}} + no_default nd; // expected-note {{because field 'nd' has a deleted default constructor}} + defaulted_delete() = default; // expected-note{{implicitly deleted here}} }; defaulted_delete dd; // expected-error {{call to implicitly-deleted default constructor}} diff --git a/test/SemaCXX/dr1301.cpp b/test/SemaCXX/dr1301.cpp index c92ff9b714..ec0db74554 100644 --- a/test/SemaCXX/dr1301.cpp +++ b/test/SemaCXX/dr1301.cpp @@ -6,7 +6,7 @@ struct A { // expected-note 2{{candidate}} int a = A().n; // expected-error {{no matching constructor}} struct B { - B() = delete; // expected-note 2{{here}} + B() = delete; // expected-note 3{{here}} int n; }; int b = B().n; // expected-error {{call to deleted}} @@ -18,7 +18,7 @@ int c = C().b.n; // expected-error {{call to implicitly-deleted default}} struct D { D() = default; // expected-note {{here}} - B b; + B b; // expected-note {{'b' has a deleted default constructor}} }; int d = D().b.n; // expected-error {{call to implicitly-deleted default}}