Clean up diagnostics for inheriting constructors.

No new diagnostics, just better wording and notes pointing at more
relevant locations.

llvm-svn: 186629
This commit is contained in:
Eli Friedman 2013-07-18 23:29:14 +00:00
parent b946407cb7
commit ebea0f29e2
5 changed files with 37 additions and 20 deletions

View File

@ -3398,6 +3398,10 @@ def note_unavailable_here : Note<
"%select{unavailable|deleted|deprecated}1 here">; "%select{unavailable|deleted|deprecated}1 here">;
def note_implicitly_deleted : Note< def note_implicitly_deleted : Note<
"explicitly defaulted function was implicitly deleted here">; "explicitly defaulted function was implicitly deleted here">;
def note_inherited_deleted_here : Note<
"deleted constructor was inherited here">;
def note_cannot_inherit : Note<
"constructor cannot be inherited">;
def warn_not_enough_argument : Warning< def warn_not_enough_argument : Warning<
"not enough variable arguments in %0 declaration to fit a sentinel">, "not enough variable arguments in %0 declaration to fit a sentinel">,
InGroup<Sentinel>; InGroup<Sentinel>;

View File

@ -9991,9 +9991,7 @@ void Sema::DefineImplicitMoveConstructor(SourceLocation CurrentLocation,
} }
bool Sema::isImplicitlyDeleted(FunctionDecl *FD) { bool Sema::isImplicitlyDeleted(FunctionDecl *FD) {
return FD->isDeleted() && return FD->isDeleted() && FD->isDefaulted() && isa<CXXMethodDecl>(FD);
(FD->isDefaulted() || FD->isImplicit()) &&
isa<CXXMethodDecl>(FD);
} }
/// \brief Mark the call operator of the given lambda closure type as "used". /// \brief Mark the call operator of the given lambda closure type as "used".

View File

@ -140,11 +140,13 @@ static AvailabilityResult DiagnoseAvailabilityOfDecl(Sema &S,
return Result; return Result;
} }
/// \brief Emit a note explaining that this function is deleted or unavailable. /// \brief Emit a note explaining that this function is deleted.
void Sema::NoteDeletedFunction(FunctionDecl *Decl) { void Sema::NoteDeletedFunction(FunctionDecl *Decl) {
assert(Decl->isDeleted());
CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Decl); CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Decl);
if (Method && Method->isDeleted() && !Method->isDeletedAsWritten()) { if (Method && Method->isDeleted() && Method->isDefaulted()) {
// If the method was explicitly defaulted, point at that declaration. // If the method was explicitly defaulted, point at that declaration.
if (!Method->isImplicit()) if (!Method->isImplicit())
Diag(Decl->getLocation(), diag::note_implicitly_deleted); Diag(Decl->getLocation(), diag::note_implicitly_deleted);
@ -158,8 +160,23 @@ void Sema::NoteDeletedFunction(FunctionDecl *Decl) {
return; return;
} }
if (CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(Decl)) {
if (CXXConstructorDecl *BaseCD =
const_cast<CXXConstructorDecl*>(CD->getInheritedConstructor())) {
Diag(Decl->getLocation(), diag::note_inherited_deleted_here);
if (BaseCD->isDeleted()) {
NoteDeletedFunction(BaseCD);
} else {
// FIXME: An explanation of why exactly it can't be inherited
// would be nice.
Diag(BaseCD->getLocation(), diag::note_cannot_inherit);
}
return;
}
}
Diag(Decl->getLocation(), diag::note_unavailable_here) Diag(Decl->getLocation(), diag::note_unavailable_here)
<< 1 << Decl->isDeleted(); << 1 << true;
} }
/// \brief Determine whether a FunctionDecl was ever declared with an /// \brief Determine whether a FunctionDecl was ever declared with an

View File

@ -2,31 +2,30 @@
// Per a core issue (no number yet), an ellipsis is always dropped. // Per a core issue (no number yet), an ellipsis is always dropped.
struct A { struct A {
A(...); // expected-note {{here}} A(...); // expected-note {{here}}
A(int = 0, int = 0, int = 0, int = 0, ...); // expected-note 9{{here}} A(int = 0, int = 0, int = 0, int = 0, ...); // expected-note 9{{here}} expected-note 2{{constructor cannot be inherited}}
A(int = 0, int = 0, ...); // expected-note {{here}} A(int = 0, int = 0, ...); // expected-note {{here}}
template<typename T> A(T, int = 0, ...); // expected-note 5{{here}} template<typename T> A(T, int = 0, ...); // expected-note 5{{here}}
template<typename T, int N> A(const T (&)[N]); // expected-note 2{{here}} template<typename T, int N> A(const T (&)[N]); // expected-note 2{{here}} expected-note {{constructor cannot be inherited}}
template<typename T, int N> A(const T (&)[N], int = 0); // expected-note 2{{here}} template<typename T, int N> A(const T (&)[N], int = 0); // expected-note 2{{here}}
}; };
struct B : A { // expected-note 6{{candidate}} struct B : A { // expected-note 6{{candidate}}
using A::A; // expected-warning 4{{inheriting constructor does not inherit ellipsis}} expected-note 16{{candidate}} expected-note 3{{deleted}} using A::A; // expected-warning 4{{inheriting constructor does not inherit ellipsis}} expected-note 16{{candidate}} expected-note 3{{deleted constructor was inherited here}}
}; };
struct C {} c; struct C {} c;
B b0{}; B b0{};
// expected-error@-1 {{call to implicitly-deleted default constructor}} // expected-error@-1 {{call to implicitly-deleted default constructor of 'B'}}
// expected-note@-8 {{default constructor of 'B' is implicitly deleted because base class 'A' has multiple default constructors}} // expected-note@-8 {{default constructor of 'B' is implicitly deleted because base class 'A' has multiple default constructors}}
B b1{1}; B b1{1};
// FIXME: explain why the inheriting constructor was deleted // expected-error@-1 {{call to deleted constructor of 'B'}}
// expected-error@-2 {{call to implicitly-deleted function of 'B'}}
B b2{1,2}; B b2{1,2};
// expected-error@-1 {{call to implicitly-deleted function of 'B'}} // expected-error@-1 {{call to deleted constructor of 'B'}}
B b3{1,2,3}; B b3{1,2,3};
// ok // ok

View File

@ -43,13 +43,13 @@ FA fa2{X<2>{}}; // expected-error {{calling a private constructor}}
// It is deleted if the corresponding constructor [...] is deleted. // It is deleted if the corresponding constructor [...] is deleted.
struct G { struct G {
G(int) = delete; G(int) = delete; // expected-note {{function has been explicitly marked deleted here}}
template<typename T> G(T*) = delete; template<typename T> G(T*) = delete; // expected-note {{function has been explicitly marked deleted here}}
}; };
struct H : G { struct H : G {
using G::G; // expected-note 2{{marked deleted here}} using G::G; // expected-note 2{{deleted constructor was inherited here}}
}; };
H h1(5); // expected-error {{call to implicitly-deleted function of 'H'}} H h1(5); // expected-error {{call to deleted constructor of 'H'}}
H h2("foo"); // expected-error {{call to deleted constructor of 'H'}} H h2("foo"); // expected-error {{call to deleted constructor of 'H'}}
@ -58,15 +58,14 @@ H h2("foo"); // expected-error {{call to deleted constructor of 'H'}}
namespace DRnnnn { namespace DRnnnn {
struct A { struct A {
constexpr A(int, float = 0) {} constexpr A(int, float = 0) {}
explicit A(int, int = 0) {} explicit A(int, int = 0) {} // expected-note {{constructor cannot be inherited}}
A(int, int, int = 0) = delete; A(int, int, int = 0) = delete;
}; };
struct B : A { struct B : A {
// FIXME: produce notes indicating why it was deleted
using A::A; // expected-note {{here}} using A::A; // expected-note {{here}}
}; };
constexpr B b0(0, 0.0f); // ok, constexpr constexpr B b0(0, 0.0f); // ok, constexpr
B b1(0, 1); // expected-error {{call to implicitly-deleted}} B b1(0, 1); // expected-error {{call to deleted constructor of 'DRnnnn::B'}}
} }