Skip to content

[Clang] Emit a diagnostic note at the class declaration when the method definition does not match any declaration. #110638

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Oct 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,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
----------------------------------

Expand Down
11 changes: 8 additions & 3 deletions clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<CXXMethodDecl>(NewFD))
NewFDisConst = NewMD->isConst();
CXXMethodDecl *NewMD = dyn_cast<CXXMethodDecl>(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<std::pair<FunctionDecl *, unsigned> >::iterator
NearMatch = NearMatches.begin(), NearMatchEnd = NearMatches.end();
Expand Down
3 changes: 2 additions & 1 deletion clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
3 changes: 2 additions & 1 deletion clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p8.cpp
Original file line number Diff line number Diff line change
@@ -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}}
3 changes: 2 additions & 1 deletion clang/test/CXX/dcl/dcl.fct/p17.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ namespace unconstrained {
// expected-error@-1{{no matching}}

template<typename T>
struct S {
struct S { // #defined-here
constexpr auto f1(auto x, T t) -> decltype(x + t);

template<typename U>
Expand All @@ -110,6 +110,7 @@ namespace unconstrained {
template<typename U>
constexpr auto S<T>::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<T>'}}
// expected-note@#defined-here {{S defined here}}

template<typename T>
template<typename U>
Expand Down
3 changes: 2 additions & 1 deletion clang/test/CXX/drs/cwg22xx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<typename ...T> struct B {
template<typename ...T> struct B { // #cwg2233-B
template <T... V> void f(int i = 0, int (&... arr)[V]);
};
template<> template<int a, int b>
void B<int, int>::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<int, int>'}}
// since-cxx11-note@#cwg2233-B {{defined here}}
template<> template<>
void B<int, int>::f<1, 1>(int i, int (&arr1a)[1], int (&arr2a)[1]) {}
}
Expand Down
13 changes: 9 additions & 4 deletions clang/test/CXX/drs/cwg3xx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -597,9 +597,10 @@ namespace cwg336 { // cwg336: yes
void mf2();
};
};
template<> template<class X> class A<int>::B {};
template<> template<class X> class A<int>::B {}; // #cwg336-B
template<> template<> template<class T> void A<int>::B<double>::mf1(T t) {}
// expected-error@-1 {{out-of-line definition of 'mf1' does not match any declaration in 'cwg336::Pre::A<int>::B<double>'}}
// expected-note@#cwg336-B {{defined here}}
template<class Y> template<> void A<Y>::B<double>::mf2() {}
// expected-error@-1 {{nested name specifier 'A<Y>::B<double>::' for declaration does not refer into a class, class template or class template partial specialization}}
}
Expand Down Expand Up @@ -758,16 +759,18 @@ 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'}}
int derived::n;
// 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
Expand Down Expand Up @@ -1009,18 +1012,20 @@ namespace cwg355 { struct ::cwg355_S s; }
// cwg356: na

namespace cwg357 { // cwg357: yes
template<typename T> struct A {
template<typename T> struct A { // #cwg357-A
void f() const; // #cwg357-f
};
template<typename T> void A<T>::f() {}
// expected-error@-1 {{out-of-line definition of 'f' does not match any declaration in 'A<T>'}}
// 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<typename T> void f();
};
template<typename T> 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
Expand Down
3 changes: 2 additions & 1 deletion clang/test/CXX/special/class.inhctor/p8.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,10 @@ struct C {
template<typename T> 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<typename T> constexpr D::D(T t) : C(t) {} // expected-error {{does not match any declaration in 'D'}}
// expected-note@#defined-here {{defined here}}
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,14 @@ int AA::A() { return sizeof(T); }
namespace diag {

template <unsigned N>
struct TA {
struct TA { // #defined-here
template <template <unsigned> class TT> requires TT<N>::happy
int A();
};

template <unsigned N>
template <template <unsigned> class TT> int TA<N>::A() { return sizeof(TT<N>); }
// expected-error@-1{{out-of-line definition of 'A' does not match any declaration in 'TA<N>'}}
// expected-note@#defined-here{{defined here}}

} // end namespace diag
10 changes: 5 additions & 5 deletions clang/test/CXX/temp/temp.res/temp.local/p8.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ namespace SearchClassBetweenTemplateParameterLists {

template<typename T> struct A {
using AA = void;
template<typename U> struct B {
template<typename U> struct B { // #defined-here
using BB = void;
void f(U);
void g(U);
Expand Down Expand Up @@ -127,19 +127,19 @@ namespace SearchClassBetweenTemplateParameterLists {
template<typename T> template<typename BB>
void A<T>::B<BB>::g(BB) { // expected-error {{does not match}}
BB bb; // expected-error {{incomplete type}}
}
} // expected-note@#defined-here {{defined here}}

// error, 'AA' found in (4)
template<typename AA> template<typename U>
void A<AA>::B<U>::h(AA) { // expected-error {{does not match}}
AA aa; // expected-error {{incomplete type}}
}
} // expected-note@#defined-here {{defined here}}

// error, 'BB' found in (2)
template<typename BB> template<typename U>
void A<BB>::B<U>::i(BB) { // expected-error {{does not match}}
BB bb; // expected-error {{incomplete type}}
}
} // expected-note@#defined-here {{defined here}}

// OK, 'BB' found in (1)
template<typename T> template<typename U> template<typename BB>
Expand All @@ -151,7 +151,7 @@ namespace SearchClassBetweenTemplateParameterLists {
template<typename T> template<typename BB> template<typename V>
void A<T>::B<BB>::k(V) { // expected-error {{does not match}}
BB bb; // expected-error {{incomplete type}}
}
} // expected-note@#defined-here {{defined here}}

int CC;
template <typename> struct C;
Expand Down
6 changes: 3 additions & 3 deletions clang/test/CXX/temp/temp.spec/temp.expl.spec/p12.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ constexpr void A::f1<long>(); // since-cxx14-error {{no function template matche
// members of a class template explicitly specialized for an implicitly
// instantiated specialization of that template.
template<typename T>
struct B {
struct B { // #defined-here
void g0(); // since-cxx14-note {{previous declaration is here}}
// cxx11-note@-1 {{member declaration does not match because it is not const qualified}}

Expand All @@ -49,11 +49,13 @@ template<>
constexpr void B<short>::g0(); // since-cxx14-error {{constexpr declaration of 'g0' follows non-constexpr declaration}}
// cxx11-error@-1 {{out-of-line declaration of 'g0' does not match any declaration in 'B<short>'}}
// cxx11-warning@-2 {{'constexpr' non-static member function will not be implicitly 'const' in C++14; add 'const'}}
// expected-note@#defined-here {{defined here}}

template<>
constexpr void B<short>::g1(); // since-cxx14-error {{out-of-line declaration of 'g1' does not match any declaration in 'B<short>'}}
// cxx11-error@-1 {{constexpr declaration of 'g1' follows non-constexpr declaration}}
// cxx11-warning@-2 {{'constexpr' non-static member function will not be implicitly 'const' in C++14; add 'const'}}
// expected-note@#defined-here {{defined here}}

template<>
template<typename U>
Expand All @@ -66,5 +68,3 @@ template<typename U>
constexpr void B<long>::h1(); // since-cxx14-error {{out-of-line declaration of 'h1' does not match any declaration in 'B<long>'}}
// cxx11-error@-1 {{constexpr declaration of 'h1' follows non-constexpr declaration}}
// cxx11-warning@-2 {{'constexpr' non-static member function will not be implicitly 'const' in C++14; add 'const'}}


3 changes: 2 additions & 1 deletion clang/test/CXX/temp/temp.spec/temp.expl.spec/p14-23.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace N0 {
concept D = I < 8;

template<int I>
struct A {
struct A { // #defined-here
constexpr static int f() { return 0; }
constexpr static int f() requires C<I> && D<I> { return 1; }
constexpr static int f() requires C<I> { return 2; }
Expand Down Expand Up @@ -56,6 +56,7 @@ namespace N0 {

template<>
constexpr int A<0>::h() { return 2; } // expected-error {{out-of-line definition of 'h' does not match any declaration in 'N0::A<0>'}}
// expected-note@#defined-here {{defined here}}

static_assert(A<5>::h() == 0);
static_assert(A<4>::h() == 1);
Expand Down
3 changes: 2 additions & 1 deletion clang/test/CXX/temp/temp.spec/temp.expl.spec/p18.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,14 @@ template<class T1> class A {
};

template<> template<class X>
class A<long>::B { };
class A<long>::B { }; // #defined-here

template<> template<> template<class T>
void A<int>::B<double>::mf1(T t) { }

template<> template<> template<class T>
void A<long>::B<double>::mf1(T t) { } // expected-error{{does not match}}
// expected-note@#defined-here{{defined here}}

// FIXME: This diagnostic could probably be better.
template<class Y> template<>
Expand Down
4 changes: 3 additions & 1 deletion clang/test/FixIt/member-mismatch.cpp
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
// RUN: %clang_cc1 -verify %s
// RUN: not %clang_cc1 -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s

class Foo {
class Foo { // #defined-here
int get() const; // expected-note {{because it is const qualified}}
void set(int); // expected-note {{because it is not const qualified}}
};

// CHECK: fix-it:"{{.*}}":{[[@LINE+1]]:15-[[@LINE+1]]:15}:" const"
int Foo::get() {} // expected-error {{does not match any declaration}}
// expected-note@#defined-here {{defined here}}
// CHECK: fix-it:"{{.*}}":{[[@LINE+1]]:20-[[@LINE+1]]:26}:""
void Foo::set(int) const {} // expected-error {{does not match any declaration}}
// expected-note@#defined-here {{defined here}}
3 changes: 2 additions & 1 deletion clang/test/Parser/cxx-class.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,9 +100,10 @@ class F {
#endif

namespace ctor_error {
class Foo {};
class Foo {}; // #defined-here
// By [class.qual]p2, this is a constructor declaration.
Foo::Foo (F) = F(); // expected-error{{does not match any declaration in 'ctor_error::Foo'}}
// expected-note@#defined-here{{defined here}}

class Ctor { // expected-note{{not complete until the closing '}'}}
Ctor(f)(int); // ok
Expand Down
9 changes: 5 additions & 4 deletions clang/test/SemaCXX/attr-target-mv.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -180,14 +180,15 @@ void constexpr_test() {
static_assert(foo() == 2, "Should call 'default' in a constexpr context");
}

struct BadOutOfLine {
struct BadOutOfLine { // #defined-here
int __attribute__((target("sse4.2"))) foo(int);
int __attribute__((target("default"))) foo(int);
};

int __attribute__((target("sse4.2"))) BadOutOfLine::foo(int) { return 0; }
int __attribute__((target("default"))) BadOutOfLine::foo(int) { return 1; }
// expected-error@+3 {{out-of-line definition of 'foo' does not match any declaration in 'BadOutOfLine'}}
// expected-note@-3 {{member declaration nearly matches}}
// expected-note@-3 {{member declaration nearly matches}}
// expected-error@+4 {{out-of-line definition of 'foo' does not match any declaration in 'BadOutOfLine'}}
// expected-note@#defined-here {{defined here}}
// expected-note@-4 {{member declaration nearly matches}}
// expected-note@-4 {{member declaration nearly matches}}
int __attribute__((target("arch=atom"))) BadOutOfLine::foo(int) { return 1; }
9 changes: 5 additions & 4 deletions clang/test/SemaCXX/attr-target-version.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,13 +97,14 @@ using ::Decl;
__attribute__((target_version("jscvt"))) void Decl();
} // namespace Nms

class Out {
class Out { // #defined-here
int __attribute__((target_version("bti"))) func(void);
int __attribute__((target_version("ssbs2"))) func(void);
};
int __attribute__((target_version("bti"))) Out::func(void) { return 1; }
int __attribute__((target_version("ssbs2"))) Out::func(void) { return 2; }
// expected-error@+3 {{out-of-line definition of 'func' does not match any declaration in 'Out'}}
// expected-note@-3 {{member declaration nearly matches}}
// expected-note@-3 {{member declaration nearly matches}}
// expected-error@+4 {{out-of-line definition of 'func' does not match any declaration in 'Out'}}
// expected-note@-2 {{member declaration nearly matches}}
// expected-note@-4 {{member declaration nearly matches}}
// expected-note@#defined-here {{defined here}}
int __attribute__((target_version("rng"))) Out::func(void) { return 3; }
2 changes: 1 addition & 1 deletion clang/test/SemaCXX/enable_if.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ int surrogate(int);
struct Incomplete; // expected-note{{forward declaration of 'Incomplete'}} \
// expected-note {{forward declaration of 'Incomplete'}}

struct X {
struct X { // expected-note{{defined here}}
X() = default; // expected-note{{candidate constructor not viable: requires 0 arguments, but 1 was provided}}
X(const X&) = default; // expected-note{{candidate constructor not viable: no known conversion from 'bool' to 'const X' for 1st argument}}
X(bool b) __attribute__((enable_if(b, "chosen when 'b' is true"))); // expected-note{{candidate disabled: chosen when 'b' is true}}
Expand Down
Loading