Younan Zhang 3b639d7d1d
[Clang] Clarify diagnostic notes for implicitly generated deduction guides (#96084)
Given the following invalid code,
```cpp
template <class T>
struct S {
  T *a;
};
S s = {1};
```
we produce such diagnostics currently:
```
<source>:2:8: note: candidate template ignored: could not match 'S<T>' against 'int'
    2 | struct S {
      |        ^
<source>:2:8: note: candidate template ignored: could not match 'T *' against 'int'
```
Which I think is confusing because there's no `S<T>` nor `T *` at the
location it points to. This is because we're deducing the initializer
against implicitly generated deduction guides, and their source
locations just point to the corresponding `RecordDecl`. Hence the
misleading notes.

This patch alleviates the issue by adding extra notes demonstrating
which implicit deduction guide we're deducing against. In other words,
in addition to the note of `could not match 'T *' against 'int'`, we
would also say the implicit deduction guide we're trying to use:
`template <class T> S(T *) -> S<T>`, which looks clearer IMO.

---------

Co-authored-by: Sirraide <aeternalmail@gmail.com>
2024-07-02 19:34:48 +08:00

76 lines
2.1 KiB
C++

// RUN: %clang_cc1 -std=c++17 -verify %s
namespace pr41427 {
template <typename T> class A {
public:
A(void (*)(T)) {}
};
void D(int) {}
void f() {
A a(&D);
using T = decltype(a);
using T = A<int>;
}
}
namespace Access {
struct B {
protected:
struct type {};
};
template<typename T> struct D : B { // expected-note {{not viable}} \
expected-note {{implicit deduction guide declared as 'template <typename T> D(D<T>) -> D<T>'}}
D(T, typename T::type); // expected-note {{private member}} \
// expected-note {{implicit deduction guide declared as 'template <typename T> D(T, typename T::type) -> D<T>'}}
};
D b = {B(), {}};
class X {
using type = int;
};
D x = {X(), {}}; // expected-error {{no viable constructor or deduction guide}}
// Once we implement proper support for dependent nested name specifiers in
// friends, this should still work.
class Y {
template <typename T> friend D<T>::D(T, typename T::type); // expected-warning {{dependent nested name specifier}}
struct type {};
};
D y = {Y(), {}};
class Z {
template <typename T> friend class D;
struct type {};
};
D z = {Z(), {}};
}
namespace GH69987 {
template<class> struct X {};
template<class = void> struct X;
X x;
template<class T, class B> struct Y { Y(T); };
template<class T, class B=void> struct Y ;
Y y(1);
}
namespace NoCrashOnGettingDefaultArgLoc {
template <typename>
class A {
A(int = 1); // expected-note {{candidate template ignored: couldn't infer template argumen}} \
// expected-note {{implicit deduction guide declared as 'template <typename> D(int = <null expr>) -> D<type-parameter-0-0>'}}
};
class C : A<int> {
using A::A;
};
template <typename>
class D : C { // expected-note {{candidate function template not viable: requires 1 argument}} \
expected-note {{implicit deduction guide declared as 'template <typename> D(D<type-parameter-0-0>) -> D<type-parameter-0-0>'}}
using C::C;
};
D abc; // expected-error {{no viable constructor or deduction guide}}
}