diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 716761c4ba5b..1402304d7e00 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -376,6 +376,8 @@ Improvements to Clang's diagnostics - Clang now diagnoses when a ``requires`` expression has a local parameter of void type, aligning with the function parameter (#GH109831). +- Clang now emits a diagnostic note at the class declaration when the method definition does not match any declaration (#GH110638). + Improvements to Clang's time-trace ---------------------------------- diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 0e536f71a2f7..e4c45cbc09e0 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -9086,9 +9086,14 @@ static NamedDecl *DiagnoseInvalidRedeclaration( SemaRef.Diag(NewFD->getLocation(), DiagMsg) << Name << NewDC << IsDefinition << NewFD->getLocation(); - bool NewFDisConst = false; - if (CXXMethodDecl *NewMD = dyn_cast(NewFD)) - NewFDisConst = NewMD->isConst(); + CXXMethodDecl *NewMD = dyn_cast(NewFD); + if (NewMD && DiagMsg == diag::err_member_decl_does_not_match) { + CXXRecordDecl *RD = NewMD->getParent(); + SemaRef.Diag(RD->getLocation(), diag::note_defined_here) + << RD->getName() << RD->getLocation(); + } + + bool NewFDisConst = NewMD && NewMD->isConst(); for (SmallVectorImpl >::iterator NearMatch = NearMatches.begin(), NearMatchEnd = NearMatches.end(); diff --git a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp index 9e890204c78b..752451f3d974 100644 --- a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp +++ b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp @@ -164,11 +164,12 @@ namespace { #if __cplusplus < 201402L namespace ImplicitConstexprDef { - struct A { + struct A { // #defined-here void f(); // expected-note {{member declaration does not match because it is not const qualified}} }; constexpr void A::f() { } // expected-warning {{'constexpr' non-static member function will not be implicitly 'const' in C++14; add 'const' to avoid a change in behavior}} // expected-error@-1 {{out-of-line definition of 'f' does not match any declaration in 'ImplicitConstexprDef::A'}} + // expected-note@#defined-here {{defined here}} } #endif diff --git a/clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p8.cpp b/clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p8.cpp index 0454412229fa..32ad25e2b705 100644 --- a/clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p8.cpp +++ b/clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p8.cpp @@ -1,8 +1,9 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s -struct A { }; +struct A { }; // #defined-here A::A (enum { e1 }) {} // expected-error{{cannot be defined in a parameter}} void A::f(enum { e2 }) {} // expected-error{{cannot be defined in a parameter}} enum { e3 } A::g() { } // expected-error{{cannot be defined in the result type}} \ // expected-error{{out-of-line definition}} +// expected-note@#defined-here{{defined here}} diff --git a/clang/test/CXX/dcl/dcl.fct/p17.cpp b/clang/test/CXX/dcl/dcl.fct/p17.cpp index d7487233f5d5..4a81875cb4f8 100644 --- a/clang/test/CXX/dcl/dcl.fct/p17.cpp +++ b/clang/test/CXX/dcl/dcl.fct/p17.cpp @@ -96,7 +96,7 @@ namespace unconstrained { // expected-error@-1{{no matching}} template - struct S { + struct S { // #defined-here constexpr auto f1(auto x, T t) -> decltype(x + t); template @@ -110,6 +110,7 @@ namespace unconstrained { template constexpr auto S::f2(auto x, U u, T t) -> decltype(x + u + t) { return x + u + t; } // expected-error@-1 {{out-of-line definition of 'f2' does not match any declaration in 'S'}} + // expected-note@#defined-here {{S defined here}} template template diff --git a/clang/test/CXX/drs/cwg22xx.cpp b/clang/test/CXX/drs/cwg22xx.cpp index 797c3ed8546e..0614d4f34ad5 100644 --- a/clang/test/CXX/drs/cwg22xx.cpp +++ b/clang/test/CXX/drs/cwg22xx.cpp @@ -102,12 +102,13 @@ namespace MultilevelSpecialization { // default argument -- how far back do we look when determining whether a // parameter was expanded from a pack? // -- zygoloid 2020-06-02 - template struct B { + template struct B { // #cwg2233-B template void f(int i = 0, int (&... arr)[V]); }; template<> template void B::f(int i, int (&arr1)[a], int (&arr2)[b]) {} // since-cxx11-error@-1 {{out-of-line definition of 'f' does not match any declaration in 'cwg2233::MultilevelSpecialization::B'}} + // since-cxx11-note@#cwg2233-B {{defined here}} template<> template<> void B::f<1, 1>(int i, int (&arr1a)[1], int (&arr2a)[1]) {} } diff --git a/clang/test/CXX/drs/cwg3xx.cpp b/clang/test/CXX/drs/cwg3xx.cpp index 7157feed3f76..f20054c3701b 100644 --- a/clang/test/CXX/drs/cwg3xx.cpp +++ b/clang/test/CXX/drs/cwg3xx.cpp @@ -597,9 +597,10 @@ namespace cwg336 { // cwg336: yes void mf2(); }; }; - template<> template class A::B {}; + template<> template class A::B {}; // #cwg336-B template<> template<> template void A::B::mf1(T t) {} // expected-error@-1 {{out-of-line definition of 'mf1' does not match any declaration in 'cwg336::Pre::A::B'}} + // expected-note@#cwg336-B {{defined here}} template template<> void A::B::mf2() {} // expected-error@-1 {{nested name specifier 'A::B::' for declaration does not refer into a class, class template or class template partial specialization}} } @@ -758,7 +759,7 @@ namespace cwg347 { // cwg347: yes void g(); }; - struct derived : base {}; + struct derived : base {}; // #cwg347-derived struct derived::nested {}; // expected-error@-1 {{no struct named 'nested' in 'cwg347::derived'}} @@ -766,8 +767,10 @@ namespace cwg347 { // cwg347: yes // expected-error@-1 {{no member named 'n' in 'cwg347::derived'}} void derived::f() {} // expected-error@-1 {{out-of-line definition of 'f' does not match any declaration in 'cwg347::derived'}} + // expected-note@#cwg347-derived {{defined here}} void derived::g() {} // expected-error@-1 {{out-of-line definition of 'g' does not match any declaration in 'cwg347::derived'}} + // expected-note@#cwg347-derived {{defined here}} } // cwg348: na @@ -1009,18 +1012,20 @@ namespace cwg355 { struct ::cwg355_S s; } // cwg356: na namespace cwg357 { // cwg357: yes - template struct A { + template struct A { // #cwg357-A void f() const; // #cwg357-f }; template void A::f() {} // expected-error@-1 {{out-of-line definition of 'f' does not match any declaration in 'A'}} + // expected-note@#cwg357-A {{defined here}} // expected-note@#cwg357-f {{member declaration does not match because it is const qualified}} - struct B { + struct B { // #cwg357-B template void f(); }; template void B::f() const {} // expected-error@-1 {{out-of-line definition of 'f' does not match any declaration in 'cwg357::B'}} + // expected-note@#cwg357-B {{defined here}} } namespace cwg358 { // cwg358: yes diff --git a/clang/test/CXX/special/class.inhctor/p8.cpp b/clang/test/CXX/special/class.inhctor/p8.cpp index 58c01d2b912d..dbc357c1a8d4 100644 --- a/clang/test/CXX/special/class.inhctor/p8.cpp +++ b/clang/test/CXX/special/class.inhctor/p8.cpp @@ -24,9 +24,10 @@ struct C { template constexpr C(T t) : v(t) {} int v; }; -struct D : C { +struct D : C { // #defined-here using C::C; }; static_assert(D(123).v == 123, ""); template constexpr D::D(T t) : C(t) {} // expected-error {{does not match any declaration in 'D'}} + // expected-note@#defined-here {{defined here}} diff --git a/clang/test/CXX/temp/temp.constr/temp.constr.decl/func-template-decl.cpp b/clang/test/CXX/temp/temp.constr/temp.constr.decl/func-template-decl.cpp index 30fbec64eea7..9a8148bdf625 100644 --- a/clang/test/CXX/temp/temp.constr/temp.constr.decl/func-template-decl.cpp +++ b/clang/test/CXX/temp/temp.constr/temp.constr.decl/func-template-decl.cpp @@ -47,7 +47,7 @@ int AA::A() { return sizeof(T); } namespace diag { template -struct TA { +struct TA { // #defined-here template