]> granicus.if.org Git - clang/commitdiff
Finish PR10217: Ensure we say that a special member was implicitly, not
authorRichard Smith <richard-llvm@metafoo.co.uk>
Mon, 2 Apr 2012 20:59:25 +0000 (20:59 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Mon, 2 Apr 2012 20:59:25 +0000 (20:59 +0000)
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

include/clang/Basic/DiagnosticSemaKinds.td
lib/Sema/SemaDeclCXX.cpp
lib/Sema/SemaExpr.cpp
lib/Sema/SemaOverload.cpp
test/CXX/special/class.copy/implicit-move.cpp
test/CXX/special/class.ctor/p5-0x.cpp
test/CXX/special/class.dtor/p5-0x.cpp
test/SemaCXX/cxx0x-deleted-default-ctor.cpp
test/SemaCXX/dr1301.cpp

index 10b3819396d5eae6017ab1d46cd9df08d6b6f96d..dc9eb4555d21bdb47835f09677103f4cbdb67cec 100644 (file)
@@ -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<Sentinel>;
index 856f921a78436103fa61eba091811f787a1bba95..216663607ca4557dff588be3e8ea988bc61324b1 100644 (file)
@@ -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(),
index 97cb647229c397816c3d8e9757c83c9529587a64..2478b03449b6a439e9be7806bef3fbaada8afe02 100644 (file)
@@ -112,15 +112,18 @@ static AvailabilityResult DiagnoseAvailabilityOfDecl(Sema &S,
 void Sema::NoteDeletedFunction(FunctionDecl *Decl) {
   CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(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)
index e1d32056ebda7d55c7327f091723acde46d4e6bb..27b04a74272789e49cf6cef351ed4d46c500aa95 100644 (file)
@@ -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 {
index 9cb4215cd0d69730f8943e8611a2fc231b22ea22..7c69dd8b87e4ace51c9cdbddf0f81c6f3d1a1b65 100644 (file)
@@ -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}}
index ceb47d8f3ba0536ee257196444fbf5f535548d03..694ab5b175357cb1e87c303648414dd1f5a6ae58 100644 (file)
@@ -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}}
index 19aa1190647216e715ed1b3cb3b78bf4faf95816..dbfa00444075533cfaa73c8d8745e955aacb763f 100644 (file)
@@ -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}}
index a5eaa352e4f44244a8397c142f9fca98a698fe82..0cebc10ade4034973d7e8ebb6876110c3ae25df6 100644 (file)
@@ -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}}
 
index c92ff9b714ec40fedac15e84665941cea1ac6cf6..ec0db74554a870fd4d6ff863e35ae741feb88b84 100644 (file)
@@ -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}}