Skip to content

Commit 8282c58

Browse files
c8efEndilll
andauthored
[Clang] Emit a diagnostic note at the class declaration when the method definition does not match any declaration. (#110638)
Fixes #110558. In this patch, we will emit a diagnostic note pointing to the class declaration when a method definition does not match any declaration. This approach, similar to what GCC does, makes the diagnostic more user-friendly. --------- Co-authored-by: Vlad Serebrennikov <[email protected]>
1 parent 9c697b3 commit 8282c58

File tree

25 files changed

+92
-51
lines changed

25 files changed

+92
-51
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,8 @@ Improvements to Clang's diagnostics
376376

377377
- Clang now diagnoses when a ``requires`` expression has a local parameter of void type, aligning with the function parameter (#GH109831).
378378

379+
- Clang now emits a diagnostic note at the class declaration when the method definition does not match any declaration (#GH110638).
380+
379381
Improvements to Clang's time-trace
380382
----------------------------------
381383

clang/lib/Sema/SemaDecl.cpp

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9086,9 +9086,14 @@ static NamedDecl *DiagnoseInvalidRedeclaration(
90869086
SemaRef.Diag(NewFD->getLocation(), DiagMsg)
90879087
<< Name << NewDC << IsDefinition << NewFD->getLocation();
90889088

9089-
bool NewFDisConst = false;
9090-
if (CXXMethodDecl *NewMD = dyn_cast<CXXMethodDecl>(NewFD))
9091-
NewFDisConst = NewMD->isConst();
9089+
CXXMethodDecl *NewMD = dyn_cast<CXXMethodDecl>(NewFD);
9090+
if (NewMD && DiagMsg == diag::err_member_decl_does_not_match) {
9091+
CXXRecordDecl *RD = NewMD->getParent();
9092+
SemaRef.Diag(RD->getLocation(), diag::note_defined_here)
9093+
<< RD->getName() << RD->getLocation();
9094+
}
9095+
9096+
bool NewFDisConst = NewMD && NewMD->isConst();
90929097

90939098
for (SmallVectorImpl<std::pair<FunctionDecl *, unsigned> >::iterator
90949099
NearMatch = NearMatches.begin(), NearMatchEnd = NearMatches.end();

clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,11 +164,12 @@ namespace {
164164

165165
#if __cplusplus < 201402L
166166
namespace ImplicitConstexprDef {
167-
struct A {
167+
struct A { // #defined-here
168168
void f(); // expected-note {{member declaration does not match because it is not const qualified}}
169169
};
170170

171171
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}}
172172
// expected-error@-1 {{out-of-line definition of 'f' does not match any declaration in 'ImplicitConstexprDef::A'}}
173+
// expected-note@#defined-here {{defined here}}
173174
}
174175
#endif
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
// RUN: %clang_cc1 -fsyntax-only -verify %s
22

3-
struct A { };
3+
struct A { }; // #defined-here
44
A::A (enum { e1 }) {} // expected-error{{cannot be defined in a parameter}}
55
void A::f(enum { e2 }) {} // expected-error{{cannot be defined in a parameter}}
66

77
enum { e3 } A::g() { } // expected-error{{cannot be defined in the result type}} \
88
// expected-error{{out-of-line definition}}
9+
// expected-note@#defined-here{{defined here}}

clang/test/CXX/dcl/dcl.fct/p17.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ namespace unconstrained {
9696
// expected-error@-1{{no matching}}
9797

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

102102
template<typename U>
@@ -110,6 +110,7 @@ namespace unconstrained {
110110
template<typename U>
111111
constexpr auto S<T>::f2(auto x, U u, T t) -> decltype(x + u + t) { return x + u + t; }
112112
// expected-error@-1 {{out-of-line definition of 'f2' does not match any declaration in 'S<T>'}}
113+
// expected-note@#defined-here {{S defined here}}
113114

114115
template<typename T>
115116
template<typename U>

clang/test/CXX/drs/cwg22xx.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,12 +102,13 @@ namespace MultilevelSpecialization {
102102
// default argument -- how far back do we look when determining whether a
103103
// parameter was expanded from a pack?
104104
// -- zygoloid 2020-06-02
105-
template<typename ...T> struct B {
105+
template<typename ...T> struct B { // #cwg2233-B
106106
template <T... V> void f(int i = 0, int (&... arr)[V]);
107107
};
108108
template<> template<int a, int b>
109109
void B<int, int>::f(int i, int (&arr1)[a], int (&arr2)[b]) {}
110110
// since-cxx11-error@-1 {{out-of-line definition of 'f' does not match any declaration in 'cwg2233::MultilevelSpecialization::B<int, int>'}}
111+
// since-cxx11-note@#cwg2233-B {{defined here}}
111112
template<> template<>
112113
void B<int, int>::f<1, 1>(int i, int (&arr1a)[1], int (&arr2a)[1]) {}
113114
}

clang/test/CXX/drs/cwg3xx.cpp

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -597,9 +597,10 @@ namespace cwg336 { // cwg336: yes
597597
void mf2();
598598
};
599599
};
600-
template<> template<class X> class A<int>::B {};
600+
template<> template<class X> class A<int>::B {}; // #cwg336-B
601601
template<> template<> template<class T> void A<int>::B<double>::mf1(T t) {}
602602
// expected-error@-1 {{out-of-line definition of 'mf1' does not match any declaration in 'cwg336::Pre::A<int>::B<double>'}}
603+
// expected-note@#cwg336-B {{defined here}}
603604
template<class Y> template<> void A<Y>::B<double>::mf2() {}
604605
// 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}}
605606
}
@@ -758,16 +759,18 @@ namespace cwg347 { // cwg347: yes
758759
void g();
759760
};
760761

761-
struct derived : base {};
762+
struct derived : base {}; // #cwg347-derived
762763

763764
struct derived::nested {};
764765
// expected-error@-1 {{no struct named 'nested' in 'cwg347::derived'}}
765766
int derived::n;
766767
// expected-error@-1 {{no member named 'n' in 'cwg347::derived'}}
767768
void derived::f() {}
768769
// expected-error@-1 {{out-of-line definition of 'f' does not match any declaration in 'cwg347::derived'}}
770+
// expected-note@#cwg347-derived {{defined here}}
769771
void derived::g() {}
770772
// expected-error@-1 {{out-of-line definition of 'g' does not match any declaration in 'cwg347::derived'}}
773+
// expected-note@#cwg347-derived {{defined here}}
771774
}
772775

773776
// cwg348: na
@@ -1009,18 +1012,20 @@ namespace cwg355 { struct ::cwg355_S s; }
10091012
// cwg356: na
10101013

10111014
namespace cwg357 { // cwg357: yes
1012-
template<typename T> struct A {
1015+
template<typename T> struct A { // #cwg357-A
10131016
void f() const; // #cwg357-f
10141017
};
10151018
template<typename T> void A<T>::f() {}
10161019
// expected-error@-1 {{out-of-line definition of 'f' does not match any declaration in 'A<T>'}}
1020+
// expected-note@#cwg357-A {{defined here}}
10171021
// expected-note@#cwg357-f {{member declaration does not match because it is const qualified}}
10181022

1019-
struct B {
1023+
struct B { // #cwg357-B
10201024
template<typename T> void f();
10211025
};
10221026
template<typename T> void B::f() const {}
10231027
// expected-error@-1 {{out-of-line definition of 'f' does not match any declaration in 'cwg357::B'}}
1028+
// expected-note@#cwg357-B {{defined here}}
10241029
}
10251030

10261031
namespace cwg358 { // cwg358: yes

clang/test/CXX/special/class.inhctor/p8.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,10 @@ struct C {
2424
template<typename T> constexpr C(T t) : v(t) {}
2525
int v;
2626
};
27-
struct D : C {
27+
struct D : C { // #defined-here
2828
using C::C;
2929
};
3030
static_assert(D(123).v == 123, "");
3131

3232
template<typename T> constexpr D::D(T t) : C(t) {} // expected-error {{does not match any declaration in 'D'}}
33+
// expected-note@#defined-here {{defined here}}

clang/test/CXX/temp/temp.constr/temp.constr.decl/func-template-decl.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,13 +47,14 @@ int AA::A() { return sizeof(T); }
4747
namespace diag {
4848

4949
template <unsigned N>
50-
struct TA {
50+
struct TA { // #defined-here
5151
template <template <unsigned> class TT> requires TT<N>::happy
5252
int A();
5353
};
5454

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

5960
} // end namespace diag

clang/test/CXX/temp/temp.res/temp.local/p8.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ namespace SearchClassBetweenTemplateParameterLists {
6969

7070
template<typename T> struct A {
7171
using AA = void;
72-
template<typename U> struct B {
72+
template<typename U> struct B { // #defined-here
7373
using BB = void;
7474
void f(U);
7575
void g(U);
@@ -127,19 +127,19 @@ namespace SearchClassBetweenTemplateParameterLists {
127127
template<typename T> template<typename BB>
128128
void A<T>::B<BB>::g(BB) { // expected-error {{does not match}}
129129
BB bb; // expected-error {{incomplete type}}
130-
}
130+
} // expected-note@#defined-here {{defined here}}
131131

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

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

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

156156
int CC;
157157
template <typename> struct C;

clang/test/CXX/temp/temp.spec/temp.expl.spec/p12.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ constexpr void A::f1<long>(); // since-cxx14-error {{no function template matche
3131
// members of a class template explicitly specialized for an implicitly
3232
// instantiated specialization of that template.
3333
template<typename T>
34-
struct B {
34+
struct B { // #defined-here
3535
void g0(); // since-cxx14-note {{previous declaration is here}}
3636
// cxx11-note@-1 {{member declaration does not match because it is not const qualified}}
3737

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

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

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

clang/test/CXX/temp/temp.spec/temp.expl.spec/p14-23.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ namespace N0 {
88
concept D = I < 8;
99

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

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

6061
static_assert(A<5>::h() == 0);
6162
static_assert(A<4>::h() == 1);

clang/test/CXX/temp/temp.spec/temp.expl.spec/p18.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,14 @@ template<class T1> class A {
77
};
88

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

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

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

1819
// FIXME: This diagnostic could probably be better.
1920
template<class Y> template<>

clang/test/FixIt/member-mismatch.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
// RUN: %clang_cc1 -verify %s
22
// RUN: not %clang_cc1 -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
33

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

99
// CHECK: fix-it:"{{.*}}":{[[@LINE+1]]:15-[[@LINE+1]]:15}:" const"
1010
int Foo::get() {} // expected-error {{does not match any declaration}}
11+
// expected-note@#defined-here {{defined here}}
1112
// CHECK: fix-it:"{{.*}}":{[[@LINE+1]]:20-[[@LINE+1]]:26}:""
1213
void Foo::set(int) const {} // expected-error {{does not match any declaration}}
14+
// expected-note@#defined-here {{defined here}}

clang/test/Parser/cxx-class.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,9 +100,10 @@ class F {
100100
#endif
101101

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

107108
class Ctor { // expected-note{{not complete until the closing '}'}}
108109
Ctor(f)(int); // ok

clang/test/SemaCXX/attr-target-mv.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -180,14 +180,15 @@ void constexpr_test() {
180180
static_assert(foo() == 2, "Should call 'default' in a constexpr context");
181181
}
182182

183-
struct BadOutOfLine {
183+
struct BadOutOfLine { // #defined-here
184184
int __attribute__((target("sse4.2"))) foo(int);
185185
int __attribute__((target("default"))) foo(int);
186186
};
187187

188188
int __attribute__((target("sse4.2"))) BadOutOfLine::foo(int) { return 0; }
189189
int __attribute__((target("default"))) BadOutOfLine::foo(int) { return 1; }
190-
// expected-error@+3 {{out-of-line definition of 'foo' does not match any declaration in 'BadOutOfLine'}}
191-
// expected-note@-3 {{member declaration nearly matches}}
192-
// expected-note@-3 {{member declaration nearly matches}}
190+
// expected-error@+4 {{out-of-line definition of 'foo' does not match any declaration in 'BadOutOfLine'}}
191+
// expected-note@#defined-here {{defined here}}
192+
// expected-note@-4 {{member declaration nearly matches}}
193+
// expected-note@-4 {{member declaration nearly matches}}
193194
int __attribute__((target("arch=atom"))) BadOutOfLine::foo(int) { return 1; }

clang/test/SemaCXX/attr-target-version.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -97,13 +97,14 @@ using ::Decl;
9797
__attribute__((target_version("jscvt"))) void Decl();
9898
} // namespace Nms
9999

100-
class Out {
100+
class Out { // #defined-here
101101
int __attribute__((target_version("bti"))) func(void);
102102
int __attribute__((target_version("ssbs2"))) func(void);
103103
};
104104
int __attribute__((target_version("bti"))) Out::func(void) { return 1; }
105105
int __attribute__((target_version("ssbs2"))) Out::func(void) { return 2; }
106-
// expected-error@+3 {{out-of-line definition of 'func' does not match any declaration in 'Out'}}
107-
// expected-note@-3 {{member declaration nearly matches}}
108-
// expected-note@-3 {{member declaration nearly matches}}
106+
// expected-error@+4 {{out-of-line definition of 'func' does not match any declaration in 'Out'}}
107+
// expected-note@-2 {{member declaration nearly matches}}
108+
// expected-note@-4 {{member declaration nearly matches}}
109+
// expected-note@#defined-here {{defined here}}
109110
int __attribute__((target_version("rng"))) Out::func(void) { return 3; }

clang/test/SemaCXX/enable_if.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ int surrogate(int);
55
struct Incomplete; // expected-note{{forward declaration of 'Incomplete'}} \
66
// expected-note {{forward declaration of 'Incomplete'}}
77

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

0 commit comments

Comments
 (0)