summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2012-04-02 20:59:25 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2012-04-02 20:59:25 +0000
commit5bdaac5454d93d1dcdc2319818497b685be56fcf (patch)
treefbf67c57fa5cdd443d079a9f6f149baf2535f57a
parent460ef136eb96b879f149c8703938a13c35b4bc68 (diff)
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
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td9
-rw-r--r--lib/Sema/SemaDeclCXX.cpp20
-rw-r--r--lib/Sema/SemaExpr.cpp19
-rw-r--r--lib/Sema/SemaOverload.cpp11
-rw-r--r--test/CXX/special/class.copy/implicit-move.cpp4
-rw-r--r--test/CXX/special/class.ctor/p5-0x.cpp8
-rw-r--r--test/CXX/special/class.dtor/p5-0x.cpp10
-rw-r--r--test/SemaCXX/cxx0x-deleted-default-ctor.cpp6
-rw-r--r--test/SemaCXX/dr1301.cpp4
9 files changed, 49 insertions, 42 deletions
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<Sentinel>;
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<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)
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}}