From ebea0f29e28a9b17bdf3beb525e1253284620da6 Mon Sep 17 00:00:00 2001 From: Eli Friedman Date: Thu, 18 Jul 2013 23:29:14 +0000 Subject: [PATCH] Clean up diagnostics for inheriting constructors. No new diagnostics, just better wording and notes pointing at more relevant locations. llvm-svn: 186629 --- .../clang/Basic/DiagnosticSemaKinds.td | 4 ++++ clang/lib/Sema/SemaDeclCXX.cpp | 4 +--- clang/lib/Sema/SemaExpr.cpp | 23 ++++++++++++++++--- clang/test/CXX/special/class.inhctor/p1.cpp | 13 +++++------ clang/test/CXX/special/class.inhctor/p4.cpp | 13 +++++------ 5 files changed, 37 insertions(+), 20 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 003930c7bd7a..bdcccac34c34 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -3398,6 +3398,10 @@ def note_unavailable_here : Note< "%select{unavailable|deleted|deprecated}1 here">; def note_implicitly_deleted : Note< "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< "not enough variable arguments in %0 declaration to fit a sentinel">, InGroup; diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index d0a80bd346f8..e331afd4d0ea 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -9991,9 +9991,7 @@ void Sema::DefineImplicitMoveConstructor(SourceLocation CurrentLocation, } bool Sema::isImplicitlyDeleted(FunctionDecl *FD) { - return FD->isDeleted() && - (FD->isDefaulted() || FD->isImplicit()) && - isa(FD); + return FD->isDeleted() && FD->isDefaulted() && isa(FD); } /// \brief Mark the call operator of the given lambda closure type as "used". diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 0106232bbbc4..f397c5bb2ef7 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -140,11 +140,13 @@ static AvailabilityResult DiagnoseAvailabilityOfDecl(Sema &S, 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) { + assert(Decl->isDeleted()); + CXXMethodDecl *Method = dyn_cast(Decl); - if (Method && Method->isDeleted() && !Method->isDeletedAsWritten()) { + if (Method && Method->isDeleted() && Method->isDefaulted()) { // If the method was explicitly defaulted, point at that declaration. if (!Method->isImplicit()) Diag(Decl->getLocation(), diag::note_implicitly_deleted); @@ -158,8 +160,23 @@ void Sema::NoteDeletedFunction(FunctionDecl *Decl) { return; } + if (CXXConstructorDecl *CD = dyn_cast(Decl)) { + if (CXXConstructorDecl *BaseCD = + const_cast(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) - << 1 << Decl->isDeleted(); + << 1 << true; } /// \brief Determine whether a FunctionDecl was ever declared with an diff --git a/clang/test/CXX/special/class.inhctor/p1.cpp b/clang/test/CXX/special/class.inhctor/p1.cpp index 8721dec1b405..fa0416e11765 100644 --- a/clang/test/CXX/special/class.inhctor/p1.cpp +++ b/clang/test/CXX/special/class.inhctor/p1.cpp @@ -2,31 +2,30 @@ // Per a core issue (no number yet), an ellipsis is always dropped. struct A { 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}} template A(T, int = 0, ...); // expected-note 5{{here}} - template A(const T (&)[N]); // expected-note 2{{here}} + template A(const T (&)[N]); // expected-note 2{{here}} expected-note {{constructor cannot be inherited}} template A(const T (&)[N], int = 0); // expected-note 2{{here}} }; 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; 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}} B b1{1}; -// FIXME: explain why the inheriting constructor was deleted -// expected-error@-2 {{call to implicitly-deleted function of 'B'}} +// expected-error@-1 {{call to deleted constructor of 'B'}} 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}; // ok diff --git a/clang/test/CXX/special/class.inhctor/p4.cpp b/clang/test/CXX/special/class.inhctor/p4.cpp index 512705e4dd94..356cdef687fb 100644 --- a/clang/test/CXX/special/class.inhctor/p4.cpp +++ b/clang/test/CXX/special/class.inhctor/p4.cpp @@ -43,13 +43,13 @@ FA fa2{X<2>{}}; // expected-error {{calling a private constructor}} // It is deleted if the corresponding constructor [...] is deleted. struct G { - G(int) = delete; - template G(T*) = delete; + G(int) = delete; // expected-note {{function has been explicitly marked deleted here}} + template G(T*) = delete; // expected-note {{function has been explicitly marked deleted here}} }; 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'}} @@ -58,15 +58,14 @@ H h2("foo"); // expected-error {{call to deleted constructor of 'H'}} namespace DRnnnn { struct A { 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; }; struct B : A { - // FIXME: produce notes indicating why it was deleted using A::A; // expected-note {{here}} }; 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'}} }