Files
clang-p2996/clang/test/SemaTemplate/nested-implicit-deduction-guides.cpp
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

104 lines
3.0 KiB
C++

// RUN: %clang_cc1 -std=c++20 -verify %s
template<class T> struct S {
template<class U> struct N {
N(T) {}
N(T, U) {}
template<class V> N(V, U) {}
};
};
S<int>::N x{"a", 1};
using T = decltype(x);
using T = S<int>::N<int>;
template<class X> struct default_ftd_argument {
template<class Y> struct B {
template<class W = X, class Z = Y, class V = Z, int I = 0> B(Y);
};
};
default_ftd_argument<int>::B default_arg("a");
using DefaultArg = decltype(default_arg);
using DefaultArg = default_ftd_argument<int>::B<const char *>;
template<bool> struct test;
template<class X> struct non_type_param {
template<class Y> struct B {
B(Y);
template<class Z, test<Z::value> = 0> B(Z);
};
};
non_type_param<int>::B ntp = 5;
using NonTypeParam = decltype(ntp);
using NonTypeParam = non_type_param<int>::B<int>;
template<typename A, typename T>
concept True = true;
template<typename T>
concept False = false;
template<class X> struct concepts {
template<class Y> struct B {
template<class K = X, True<K> Z> B(Y, Z);
};
};
concepts<int>::B cc(1, 3);
using Concepts = decltype(cc);
using Concepts = concepts<int>::B<int>;
template<class X> struct requires_clause {
template<class Y> struct B {
template<class Z> requires true
B(Y, Z);
};
};
requires_clause<int>::B req(1, 2);
using RC = decltype(req);
using RC = requires_clause<int>::B<int>;
template<typename X> struct nested_init_list {
template<True<X> Y>
struct B {
X x;
Y y;
};
template<False F>
struct concept_fail { // #INIT_LIST_INNER_INVALID
X x;
F f;
};
};
nested_init_list<int>::B nil {1, 2};
using NIL = decltype(nil);
using NIL = nested_init_list<int>::B<int>;
// expected-error@+1 {{no viable constructor or deduction guide for deduction of template arguments of 'nested_init_list<int>::concept_fail'}}
nested_init_list<int>::concept_fail nil_invalid{1, ""};
// expected-note@#INIT_LIST_INNER_INVALID {{candidate template ignored: substitution failure [with F = const char *]: constraints not satisfied for class template 'concept_fail' [with F = const char *]}}
// expected-note@#INIT_LIST_INNER_INVALID {{implicit deduction guide declared as 'template <False F> concept_fail(int, F) -> concept_fail<F>'}}
// expected-note@#INIT_LIST_INNER_INVALID {{candidate function template not viable: requires 1 argument, but 2 were provided}}
// expected-note@#INIT_LIST_INNER_INVALID {{implicit deduction guide declared as 'template <False F> concept_fail(concept_fail<F>) -> concept_fail<F>'}}
// expected-note@#INIT_LIST_INNER_INVALID {{candidate function template not viable: requires 0 arguments, but 2 were provided}}
// expected-note@#INIT_LIST_INNER_INVALID {{implicit deduction guide declared as 'template <False F> concept_fail() -> concept_fail<F>'}}
namespace GH88142 {
template <typename, typename...> struct X {
template <typename> struct Y {
template <typename T> Y(T) {}
};
template <typename T> Y(T) -> Y<T>;
};
X<int>::Y y(42);
} // namespace PR88142