[clang] [Clang] Clarify diagnostic notes for implicitly generated deduction guides (PR #96084)
Younan Zhang via cfe-commits
cfe-commits at lists.llvm.org
Fri Jun 28 02:33:26 PDT 2024
https://github.com/zyn0217 updated https://github.com/llvm/llvm-project/pull/96084
>From 23844cd8b8fad07bce0c34f58430322090c5a793 Mon Sep 17 00:00:00 2001
From: Younan Zhang <zyn7109 at gmail.com>
Date: Wed, 19 Jun 2024 23:25:13 +0800
Subject: [PATCH 01/11] [Clang] Add diagnostic notes for implcitly generated
deduction guides
---
clang/docs/ReleaseNotes.rst | 3 ++
.../clang/Basic/DiagnosticSemaKinds.td | 1 +
clang/lib/Sema/SemaOverload.cpp | 30 +++++++++++++++++++
clang/test/CXX/drs/cwg26xx.cpp | 3 ++
.../CXX/expr/expr.post/expr.type.conv/p1.cpp | 2 +-
.../over.match.class.deduct/p2.cpp | 2 +-
.../temp.deduct/temp.deduct.call/p3-0x.cpp | 4 +--
clang/test/Modules/template_name_lookup.cpp | 2 ++
clang/test/PCH/cxx-explicit-specifier.cpp | 2 +-
clang/test/Sema/tls_alignment.cpp | 4 ++-
...xx1z-class-template-argument-deduction.cpp | 6 ++--
clang/test/SemaCXX/cxx20-ctad-type-alias.cpp | 17 +++++++++--
clang/test/SemaCXX/cxx2a-explicit-bool.cpp | 2 ++
clang/test/SemaCXX/gh65522.cpp | 3 +-
...deduction-guide-as-template-candidates.cpp | 4 ++-
.../lookup-template-name-extern-CXX.cpp | 6 ++--
.../aggregate-deduction-candidate.cpp | 24 ++++++++-------
clang/test/SemaTemplate/class-template-id.cpp | 2 ++
clang/test/SemaTemplate/ctad.cpp | 6 ++--
clang/test/SemaTemplate/deduction-crash.cpp | 3 +-
clang/test/SemaTemplate/deduction-guide.cpp | 6 ++--
.../nested-implicit-deduction-guides.cpp | 3 ++
clang/test/SemaTemplate/temp_arg.cpp | 4 ++-
23 files changed, 108 insertions(+), 31 deletions(-)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 69aea6c21ad39..423f1e9198948 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -580,6 +580,9 @@ Improvements to Clang's diagnostics
- Clang no longer emits a "declared here" note for a builtin function that has no declaration in source.
Fixes #GH93369.
+- Clang now emits implicit deduction guides corresponding to non-user-defined constructors while at a failure
+ of overload resolution.
+
Improvements to Clang's time-trace
----------------------------------
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index ab223f2b806d5..a65491b0c4399 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -2405,6 +2405,7 @@ def err_selected_explicit_constructor : Error<
"chosen constructor is explicit in copy-initialization">;
def note_explicit_ctor_deduction_guide_here : Note<
"explicit %select{constructor|deduction guide}0 declared here">;
+def note_implicit_deduction_guide : Note<"implicit deduction guide declared as '%0'">;
// C++11 auto
def warn_cxx98_compat_auto_type_specifier : Warning<
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index fb4ff72e42eb5..31b908eb3cc3c 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -40,6 +40,7 @@
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/STLForwardCompat.h"
+#include "llvm/ADT/ScopeExit.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
@@ -12114,6 +12115,35 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
return;
}
+ // If this is an implicit deduction guide against a non-user-defined
+ // constructor, add a note for it. These deduction guides nor their
+ // corresponding constructors are not explicitly spelled in the source code,
+ // and simply producing a deduction failure note around the heading of the
+ // enclosing RecordDecl is confusing.
+ //
+ // We prefer adding such notes at the end of the last deduction failure
+ // reason because duplicate code snippets appearing in the diagnostic
+ // are likely becoming noisy.
+ auto _ = llvm::make_scope_exit([&] {
+ auto *DG = dyn_cast<CXXDeductionGuideDecl>(Fn);
+ if (!DG || !DG->isImplicit() || DG->getCorrespondingConstructor())
+ return;
+ std::string FunctionProto;
+ llvm::raw_string_ostream OS(FunctionProto);
+ FunctionTemplateDecl *Template = DG->getDescribedFunctionTemplate();
+ // This also could be an instantiation. Find out the primary template.
+ if (!Template) {
+ FunctionDecl *Pattern = DG->getTemplateInstantiationPattern();
+ assert(Pattern && Pattern->getDescribedFunctionTemplate() &&
+ "Cannot find the associated function template of "
+ "CXXDeductionGuideDecl?");
+ Template = Pattern->getDescribedFunctionTemplate();
+ }
+ Template->print(OS);
+ S.Diag(DG->getLocation(), diag::note_implicit_deduction_guide)
+ << FunctionProto;
+ });
+
switch (Cand->FailureKind) {
case ovl_fail_too_many_arguments:
case ovl_fail_too_few_arguments:
diff --git a/clang/test/CXX/drs/cwg26xx.cpp b/clang/test/CXX/drs/cwg26xx.cpp
index 2b17c8101438d..95dfa229530fb 100644
--- a/clang/test/CXX/drs/cwg26xx.cpp
+++ b/clang/test/CXX/drs/cwg26xx.cpp
@@ -194,8 +194,11 @@ static_assert(__is_same(decltype(i), I<char, 4>));
J j = { "ghi" };
// since-cxx20-error at -1 {{no viable constructor or deduction guide}}
// since-cxx20-note@#cwg2681-J {{candidate template ignored: could not match 'J<N>' against 'const char *'}}
+// since-cxx20-note@#cwg2681-J {{implicit deduction guide declared as 'template <size_t N> J(J<N>) -> J<N>'}}
// since-cxx20-note@#cwg2681-J {{candidate template ignored: could not match 'const unsigned char' against 'const char'}}
+// since-cxx20-note@#cwg2681-J {{implicit deduction guide declared as 'template <size_t N> J(const unsigned char (&)[N]) -> J<N>'}}
// since-cxx20-note@#cwg2681-J {{candidate function template not viable: requires 0 arguments, but 1 was provided}}
+// since-cxx20-note@#cwg2681-J {{implicit deduction guide declared as 'template <size_t N> J() -> J<N>'}}
#endif
}
diff --git a/clang/test/CXX/expr/expr.post/expr.type.conv/p1.cpp b/clang/test/CXX/expr/expr.post/expr.type.conv/p1.cpp
index f3608bc378bc7..aa3c022e9b134 100644
--- a/clang/test/CXX/expr/expr.post/expr.type.conv/p1.cpp
+++ b/clang/test/CXX/expr/expr.post/expr.type.conv/p1.cpp
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -std=c++1z -verify %s
-template<typename T> struct A { // expected-note 2{{candidate}}
+template<typename T> struct A { // expected-note 2{{candidate}} {{implicit deduction guide}}
T t, u;
};
template<typename T> A(T, T) -> A<T>; // expected-note {{deduced conflicting types for parameter 'T'}}
diff --git a/clang/test/CXX/over/over.match/over.match.funcs/over.match.class.deduct/p2.cpp b/clang/test/CXX/over/over.match/over.match.funcs/over.match.class.deduct/p2.cpp
index 49fde292f6a36..4bcf4ee2e3fe7 100644
--- a/clang/test/CXX/over/over.match/over.match.funcs/over.match.class.deduct/p2.cpp
+++ b/clang/test/CXX/over/over.match/over.match.funcs/over.match.class.deduct/p2.cpp
@@ -35,7 +35,7 @@ namespace std {
}
namespace p0702r1 {
- template<typename T> struct X { // expected-note {{candidate}}
+ template<typename T> struct X { // expected-note {{candidate}} expected-note {{implicit deduction guide}}
X(std::initializer_list<T>); // expected-note {{candidate template ignored: could not match 'std::initializer_list<T>' against 'Z'}}
};
diff --git a/clang/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p3-0x.cpp b/clang/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p3-0x.cpp
index 8592626269eed..2e39697a1f07f 100644
--- a/clang/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p3-0x.cpp
+++ b/clang/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p3-0x.cpp
@@ -6,7 +6,7 @@
#if __cplusplus > 201402L
namespace ClassTemplateParamNotForwardingRef {
// This is not a forwarding reference.
- template<typename T> struct A { // expected-note {{candidate}}
+ template<typename T> struct A { // expected-note {{candidate}} expected-note {{implicit deduction guide}}
A(T&&); // expected-note {{expects an rvalue}}
};
int n;
@@ -75,7 +75,7 @@ namespace std_example {
int n3 = g(i); // expected-error{{no matching function for call to 'g'}}
#if __cplusplus > 201402L
- template<class T> struct A { // expected-note {{candidate}}
+ template<class T> struct A { // expected-note {{candidate}} expected-note {{implicit deduction guide}}
template<class U>
A(T &&, U &&, int *); // expected-note {{[with T = int, U = int] not viable: expects an rvalue}}
A(T &&, int *); // expected-note {{requires 2}}
diff --git a/clang/test/Modules/template_name_lookup.cpp b/clang/test/Modules/template_name_lookup.cpp
index 29375e514025f..82b06e83afce3 100644
--- a/clang/test/Modules/template_name_lookup.cpp
+++ b/clang/test/Modules/template_name_lookup.cpp
@@ -7,5 +7,7 @@ import foo;
void use() {
X x; // expected-error {{no viable constructor or deduction guide for deduction of template arguments of 'X'}}
// expected-note at Inputs/template_name_lookup/foo.cppm:3 {{candidate template ignored: couldn't infer template argument 'T'}}
+ // expected-note at Inputs/template_name_lookup/foo.cppm:3 {{implicit deduction guide declared as 'template <typename T> X(X<T>) -> X<T>'}}
// expected-note at Inputs/template_name_lookup/foo.cppm:3 {{candidate function template not viable: requires 1 argument, but 0 were provided}}
+ // expected-note at Inputs/template_name_lookup/foo.cppm:3 {{implicit deduction guide declared as 'template <typename T> X() -> X<T>'}}
}
diff --git a/clang/test/PCH/cxx-explicit-specifier.cpp b/clang/test/PCH/cxx-explicit-specifier.cpp
index 94ca9f7b080db..68dfc911164c5 100644
--- a/clang/test/PCH/cxx-explicit-specifier.cpp
+++ b/clang/test/PCH/cxx-explicit-specifier.cpp
@@ -79,7 +79,7 @@ struct A {
B<true> b_true;
B<false> b_false;
#else
-//expected-note at -8 {{candidate template ignored}}
+//expected-note at -8 {{candidate template ignored}} expected-note at -8 {{implicit deduction guide declared as 'template <bool b> A(A<b>) -> A<b>'}}
//expected-note at -8 {{explicit constructor declared here}}
//expected-note at -15+ {{candidate constructor}}
//expected-note at -8+ {{explicit conversion function is not a candidate (explicit specifier}}
diff --git a/clang/test/Sema/tls_alignment.cpp b/clang/test/Sema/tls_alignment.cpp
index c5c79aafa9ead..65b6b035e7917 100644
--- a/clang/test/Sema/tls_alignment.cpp
+++ b/clang/test/Sema/tls_alignment.cpp
@@ -22,7 +22,9 @@ struct struct_with_aligned_field {
template <typename>
struct templated_struct {};
// expected-note at -1{{candidate template ignored: couldn't infer template argument ''}}
-// expected-note at -2{{candidate function template not viable: requires 1 argument, but 0 were provided}}
+// expected-note at -2{{implicit deduction guide declared as 'template <typename> templated_struct() -> templated_struct<type-parameter-0-0>'}}
+// expected-note at -3{{candidate function template not viable: requires 1 argument, but 0 were provided}}
+// expected-note at -4{{implicit deduction guide declared as 'template <typename> templated_struct(templated_struct<type-parameter-0-0>) -> templated_struct<type-parameter-0-0>'}}
// A typedef of the aligned struct.
typedef aligned_struct another_aligned_struct;
diff --git a/clang/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp b/clang/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp
index 90404f115c75f..0a296b32cfb6f 100644
--- a/clang/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp
+++ b/clang/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp
@@ -139,7 +139,8 @@ namespace look_into_current_instantiation {
// templates, and members of the current instantiation
A<float> &r = a;
- template<typename T> struct B { // expected-note {{could not match 'B<T>' against 'int'}}
+ template<typename T> struct B { // expected-note {{could not match 'B<T>' against 'int'}} \
+ expected-note {{implicit deduction guide declared as 'template <typename T> B(B<T>) -> B<T>'}}
struct X {
typedef T type;
};
@@ -564,7 +565,8 @@ namespace PR47175 {
// Ensure we don't crash when CTAD fails.
template <typename T1, typename T2>
-struct Foo { // expected-note{{candidate function template not viable}}
+struct Foo { // expected-note{{candidate function template not viable}} \
+ expected-note{{implicit deduction guide declared as 'template <typename T1, typename T2> Foo(Foo<T1, T2>) -> Foo<T1, T2>'}}
Foo(T1, T2); // expected-note{{candidate function template not viable}}
};
diff --git a/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp b/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
index b71dfc6ccaf4f..901f64434bbee 100644
--- a/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
+++ b/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
@@ -108,8 +108,11 @@ struct Foo {
Foo(T const (&)[N]);
};
+// FIXME: Clarify that __is_deducible constraints are unsatisfied. For example, GCC currently prints the code snippet around constructors
+// FIXME: Prefer non-canonical template arguments in the deduction guide?
template <typename X, int Y>
using Bar = Foo<X, sizeof(X)>; // expected-note {{candidate template ignored: couldn't infer template argument 'X'}} \
+ // expected-note {{implicit deduction guide declared as 'template <typename X> Bar(Foo<type-parameter-0-0, sizeof(type-parameter-0-0)>) -> Foo<type-parameter-0-0, sizeof(type-parameter-0-0)>'}} \
// expected-note {{candidate template ignored: constraints not satisfied [with X = int]}} \
// expected-note {{cannot deduce template arguments for 'Bar' from 'Foo<int, 4UL>'}}
@@ -137,9 +140,12 @@ struct A {};
template<class T> struct Foo { T c; };
template<class X, class Y=A>
using AFoo = Foo<Y>; // expected-note {{candidate template ignored: could not match 'Foo<type-parameter-0-0>' against 'int'}} \
+ // expected-note {{implicit deduction guide declared as 'template <class Y = A> AFoo(Foo<type-parameter-0-0>) -> Foo<type-parameter-0-0>'}} \
// expected-note {{candidate template ignored: constraints not satisfied [with Y = int]}} \
// expected-note {{cannot deduce template arguments for 'AFoo' from 'Foo<int>'}} \
- // expected-note {{candidate function template not viable: requires 0 arguments, but 1 was provided}}
+ // expected-note {{implicit deduction guide declared as 'template <class Y = A> AFoo(type-parameter-0-0) -> Foo<type-parameter-0-0>'}} \
+ // expected-note {{candidate function template not viable: requires 0 arguments, but 1 was provided}} \
+ // expected-note {{implicit deduction guide declared as 'template <class Y = A> AFoo() -> Foo<type-parameter-0-0>'}}
AFoo s = {1}; // expected-error {{no viable constructor or deduction guide for deduction of template arguments of 'AFoo'}}
} // namespace test11
@@ -192,6 +198,7 @@ struct Foo {
template <int K>
using Bar = Foo<double, K>; // expected-note {{constraints not satisfied for class template 'Foo'}}
// expected-note at -1 {{candidate template ignored: could not match}}
+// expected-note at -2 {{implicit deduction guide declared as 'template <int K> Bar(Foo<double, K>) -> Foo<double, K>'}}
double abc[3];
Bar s2 = {abc}; // expected-error {{no viable constructor or deduction guide for deduction }}
} // namespace test14
@@ -204,6 +211,7 @@ template<typename> concept False = false;
template<False W>
using BFoo = AFoo<W>; // expected-note {{candidate template ignored: constraints not satisfied [with V = int]}} \
// expected-note {{cannot deduce template arguments for 'BFoo' from 'Foo<int *>'}} \
+ // expected-note {{implicit deduction guide declared as 'template <class V> BFoo(Foo<type-parameter-0-0 *>) -> Foo<type-parameter-0-0 *>'}} \
// expected-note {{candidate template ignored: could not match 'Foo<type-parameter-0-0 *>' against 'int *'}}
int i = 0;
AFoo a1(&i); // OK, deduce Foo<int *>
@@ -256,7 +264,9 @@ Foo(T) -> Foo<int>;
template <typename U>
using Bar = Foo<U>; // expected-note {{could not match 'Foo<type-parameter-0-0>' against 'int'}} \
// expected-note {{candidate template ignored: constraints not satisfied}} \
- // expected-note {{candidate function template not viable}}
+ // expected-note {{candidate function template not viable}} \
+ // expected-note {{implicit deduction guide declared as 'template <typename U> Bar() -> Foo<type-parameter-0-0>'}} \
+ // expected-note {{implicit deduction guide declared as 'template <typename U> Bar(Foo<type-parameter-0-0>) -> Foo<type-parameter-0-0>'}}
Bar s = {1}; // expected-error {{no viable constructor or deduction guide for deduction of template arguments}}
} // namespace test18
@@ -284,7 +294,8 @@ class Foo {};
// Verify that template template type parameter TTP is referenced/used in the
// template arguments of the RHS.
template <template<typename> typename TTP>
-using Bar = Foo<K<TTP>>; // expected-note {{candidate template ignored: could not match 'Foo<K<template-parameter-0-0>>' against 'int'}}
+using Bar = Foo<K<TTP>>; // expected-note {{candidate template ignored: could not match 'Foo<K<template-parameter-0-0>>' against 'int'}} \
+ // expected-note {{implicit deduction guide declared as 'template <template <typename> typename TTP> Bar(Foo<K<template-parameter-0-0>>) -> Foo<K<template-parameter-0-0>>'}}
template <class T>
class Container {};
diff --git a/clang/test/SemaCXX/cxx2a-explicit-bool.cpp b/clang/test/SemaCXX/cxx2a-explicit-bool.cpp
index 9fdc059493aac..13b5ff1d59b31 100644
--- a/clang/test/SemaCXX/cxx2a-explicit-bool.cpp
+++ b/clang/test/SemaCXX/cxx2a-explicit-bool.cpp
@@ -394,6 +394,7 @@ using type = T;
template<typename T1, typename T2, bool b>
struct A {
// expected-note at -1+ {{candidate function}}
+ // expected-note at -2+ {{implicit deduction guide}}
explicit(false)
A(typename nondeduced<T1>::type, typename nondeduced<T2>::type, typename nondeduced<B<b>>::type) {}
// expected-note at -1+ {{candidate template ignored}}
@@ -678,6 +679,7 @@ namespace deduction_guide2 {
template<typename T1 = int, typename T2 = int>
struct A {
// expected-note at -1+ {{candidate template ignored}}
+ // expected-note at -2+ {{implicit deduction guide}}
explicit(!is_same<T1, T2>::value)
A(T1 = 0, T2 = 0) {}
// expected-note at -1 {{explicit constructor declared here}}
diff --git a/clang/test/SemaCXX/gh65522.cpp b/clang/test/SemaCXX/gh65522.cpp
index 2d6331b0372a3..bfc3a1e12fe76 100644
--- a/clang/test/SemaCXX/gh65522.cpp
+++ b/clang/test/SemaCXX/gh65522.cpp
@@ -3,7 +3,8 @@
class X {};
template<typename T>
-class B3 { // expected-note {{candidate template ignored: could not match 'B3<T>' against 'int'}}
+class B3 { // expected-note {{candidate template ignored: could not match 'B3<T>' against 'int'}} \
+ // expected-note {{implicit deduction guide declared as 'template <typename T> B3(B3<T>) -> B3<T>'}}
template<X x> B3(T); // expected-warning 2{{non-type template parameter of type 'X' is incompatible with C++ standards before C++20}} \
// expected-note {{candidate template ignored: couldn't infer template argument 'x'}}
};
diff --git a/clang/test/SemaCXX/invalid-deduction-guide-as-template-candidates.cpp b/clang/test/SemaCXX/invalid-deduction-guide-as-template-candidates.cpp
index e9b362d67cd23..ad7441ff48477 100644
--- a/clang/test/SemaCXX/invalid-deduction-guide-as-template-candidates.cpp
+++ b/clang/test/SemaCXX/invalid-deduction-guide-as-template-candidates.cpp
@@ -1,6 +1,8 @@
// RUN: %clang_cc1 -std=c++17 -fsyntax-only -verify %s
template <class T> class Foo {}; // expected-note {{candidate template ignored: couldn't infer template argument 'T'}} \
- // expected-note {{candidate function template not viable: requires 1 argument, but 0 were provided}}
+ // expected-note {{implicit deduction guide declared as 'template <class T> Foo(Foo<T>) -> Foo<T>'}} \
+ // expected-note {{candidate function template not viable: requires 1 argument, but 0 were provided}} \
+ // expected-note {{implicit deduction guide declared as 'template <class T> Foo() -> Foo<T>'}}
Foo(); // expected-error {{deduction guide declaration without trailing return type}}
Foo vs; // expected-error {{no viable constructor or deduction guide for deduction of template arguments of 'Foo'}}
diff --git a/clang/test/SemaCXX/lookup-template-name-extern-CXX.cpp b/clang/test/SemaCXX/lookup-template-name-extern-CXX.cpp
index 93e7fb6199354..f851af7ecec26 100644
--- a/clang/test/SemaCXX/lookup-template-name-extern-CXX.cpp
+++ b/clang/test/SemaCXX/lookup-template-name-extern-CXX.cpp
@@ -3,8 +3,10 @@
// RUN: %clang_cc1 -std=c++20 %s -fsyntax-only -verify
extern "C++" {
template <class T>
-class X {}; // expected-note {{candidate template ignored: couldn't infer template argument 'T'}}
- // expected-note at -1 {{candidate function template not viable: requires 1 argument, but 0 were provided}}
+class X {}; // expected-note {{candidate template ignored: couldn't infer template argument 'T'}} \
+ // expected-note {{implicit deduction guide declared as 'template <class T> X(X<T>) -> X<T>'}} \
+ // expected-note {{candidate function template not viable: requires 1 argument, but 0 were provided}} \
+ // expected-note {{implicit deduction guide declared as 'template <class T> X() -> X<T>'}}
}
void foo() {
diff --git a/clang/test/SemaTemplate/aggregate-deduction-candidate.cpp b/clang/test/SemaTemplate/aggregate-deduction-candidate.cpp
index 5a50332d73307..49afb6b860620 100644
--- a/clang/test/SemaTemplate/aggregate-deduction-candidate.cpp
+++ b/clang/test/SemaTemplate/aggregate-deduction-candidate.cpp
@@ -2,7 +2,7 @@
// RUN: %clang_cc1 -std=c++20 -verify=expected,cxx20 -ast-dump -ast-dump-decl-types -ast-dump-filter "deduction guide" %s | FileCheck %s --strict-whitespace
namespace Basic {
- template<class T> struct A { // cxx17-note 6 {{candidate}}
+ template<class T> struct A { // cxx17-note 6 {{candidate}} cxx17-note 6 {{implicit deduction guide}}
T x;
T y;
};
@@ -36,12 +36,14 @@ namespace Basic {
T y;
};
- template <typename T> struct C { // cxx20-note 10 {{candidate}} cxx17-note 12 {{candidate}}
+ template <typename T> struct C { // cxx20-note 10 {{candidate}} cxx17-note 12 {{candidate}} \
+ cxx20-note 10 {{implicit deduction guide}} cxx17-note 12 {{implicit deduction guide}}
S<T> s;
T t;
};
- template <typename T> struct D { // cxx20-note 6 {{candidate}} cxx17-note 8 {{candidate}}
+ template <typename T> struct D { // cxx20-note 6 {{candidate}} cxx17-note 8 {{candidate}} \
+ cxx20-note 6 {{implicit deduction guide}} cxx17-note 8 {{implicit deduction guide}}
S<int> s;
T t;
};
@@ -99,7 +101,7 @@ namespace Basic {
// CHECK: |-ClassTemplateSpecialization {{.*}} 'S'
// CHECK: `-BuiltinType {{.*}} 'int'
- template <typename T> struct E { // cxx17-note 4 {{candidate}}
+ template <typename T> struct E { // cxx17-note 4 {{candidate}} cxx17-note 4 {{implicit deduction guide}}
T t;
decltype(t) t2;
};
@@ -133,7 +135,7 @@ namespace Basic {
};
template <typename T>
- struct F { // cxx17-note 2 {{candidate}}
+ struct F { // cxx17-note 2 {{candidate}} cxx17-note 2 {{implicit deduction guide}}
typename I<T>::type i;
T t;
};
@@ -161,7 +163,8 @@ namespace Basic {
namespace Array {
typedef unsigned long size_t;
- template <typename T, size_t N> struct A { // cxx20-note 2 {{candidate}} cxx17-note 14 {{candidate}}
+ template <typename T, size_t N> struct A { // cxx20-note 2 {{candidate}} cxx17-note 14 {{candidate}} \
+ cxx20-note 2 {{implicit deduction guide}} cxx17-note 14 {{implicit deduction guide}}
T array[N];
};
@@ -217,7 +220,7 @@ namespace Array {
}
namespace BraceElision {
- template <typename T> struct A { // cxx17-note 4 {{candidate}}
+ template <typename T> struct A { // cxx17-note 4 {{candidate}} cxx17-note 4 {{implicit deduction guide}}
T array[2];
};
@@ -247,7 +250,7 @@ namespace BraceElision {
}
namespace TrailingPack {
- template<typename... T> struct A : T... { // cxx17-note 4 {{candidate}}
+ template<typename... T> struct A : T... { // cxx17-note 4 {{candidate}} cxx17-note 4 {{implicit deduction guide}}
};
A a1 = { // cxx17-error {{no viable}}
@@ -286,7 +289,7 @@ namespace TrailingPack {
}
namespace NonTrailingPack {
- template<typename... T> struct A : T... { // expected-note 4 {{candidate}}
+ template<typename... T> struct A : T... { // expected-note 4 {{candidate}} expected-note 4 {{implicit deduction guide}}
int a;
};
@@ -303,7 +306,8 @@ namespace NonTrailingPack {
namespace DeduceArity {
template <typename... T> struct Types {};
- template <typename... T> struct F : Types<T...>, T... {}; // cxx20-note 12 {{candidate}} cxx17-note 16 {{candidate}}
+ template <typename... T> struct F : Types<T...>, T... {}; // cxx20-note 12 {{candidate}} cxx17-note 16 {{candidate}} \
+ cxx20-note 12 {{implicit deduction guide}} cxx17-note 16 {{implicit deduction guide}}
struct X {};
struct Y {};
diff --git a/clang/test/SemaTemplate/class-template-id.cpp b/clang/test/SemaTemplate/class-template-id.cpp
index eade4f6290424..96696f62b78a2 100644
--- a/clang/test/SemaTemplate/class-template-id.cpp
+++ b/clang/test/SemaTemplate/class-template-id.cpp
@@ -45,6 +45,8 @@ typedef N::C<float> c2;
// PR5655
template<typename T> struct Foo { }; // precxx17-note {{template is declared here}} \
cxx17-note {{candidate template ignored: couldn't infer template argument 'T'}} \
+ cxx17-note {{implicit deduction guide declared as 'template <typename T> Foo() -> Foo<T>'}} \
+ cxx17-note {{implicit deduction guide declared as 'template <typename T> Foo(Foo<T>) -> Foo<T>'}} \
cxx17-note {{candidate function template not viable: requires 1 argument, but 0 were provided}}
void f(void) { Foo bar; } // precxx17-error {{use of class template 'Foo' requires template arguments}} \
diff --git a/clang/test/SemaTemplate/ctad.cpp b/clang/test/SemaTemplate/ctad.cpp
index e981ea8d5ecfb..c5e467a8d7724 100644
--- a/clang/test/SemaTemplate/ctad.cpp
+++ b/clang/test/SemaTemplate/ctad.cpp
@@ -20,7 +20,8 @@ namespace Access {
protected:
struct type {};
};
- template<typename T> struct D : B { // expected-note {{not viable}}
+ 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}}
};
D b = {B(), {}};
@@ -64,7 +65,8 @@ class C : A<int> {
using A::A;
};
template <typename>
-class D : C { // expected-note {{candidate function template not viable: requires 1 argument}}
+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}}
diff --git a/clang/test/SemaTemplate/deduction-crash.cpp b/clang/test/SemaTemplate/deduction-crash.cpp
index 86ec9f7980a7d..e3f97c594aa90 100644
--- a/clang/test/SemaTemplate/deduction-crash.cpp
+++ b/clang/test/SemaTemplate/deduction-crash.cpp
@@ -166,8 +166,9 @@ namespace PR51872_part1 {
template<int> class T1 { template <struct U1> T1(); };
// expected-error at -1 {{non-type template parameter has incomplete type 'struct U1'}}
// expected-note at -2 {{forward declaration of 'PR51872_part1::U1'}}
+ // expected-note at -3 {{implicit deduction guide declared as 'template <int> T1(T1<>) -> T1<>'}}
T1 t1 = 0;
// expected-error at -1 {{no viable constructor or deduction guide for deduction of template arguments of 'T1'}}
- // expected-note at -6 {{candidate template ignored: could not match 'T1<>' against 'int'}}
+ // expected-note at -7 {{candidate template ignored: could not match 'T1<>' against 'int'}}
}
diff --git a/clang/test/SemaTemplate/deduction-guide.cpp b/clang/test/SemaTemplate/deduction-guide.cpp
index 163b36519950f..54420be9ee969 100644
--- a/clang/test/SemaTemplate/deduction-guide.cpp
+++ b/clang/test/SemaTemplate/deduction-guide.cpp
@@ -123,7 +123,8 @@ using CT = C<int>;
// CHECK: | `-TemplateArgument template
// CHECK: `-TemplateTypeParmType {{.*}} 'type-parameter-0-2' dependent depth 0 index 2
-template<typename ...T> struct D { // expected-note {{candidate}}
+template<typename ...T> struct D { // expected-note {{candidate}} \
+ expected-note {{implicit deduction guide declared as 'template <typename ...T> D(D<T...>) -> D<T...>'}}
template<typename... U> using B = int(int (*...p)(T, U));
template<typename U1, typename U2> D(B<U1, U2>*); // expected-note {{candidate}}
};
@@ -166,7 +167,8 @@ using DT = D<int, int>;
// CHECK-NOT: Subst
// CHECK: `-TemplateTypeParmType
-template<int ...N> struct E { // expected-note {{candidate}}
+template<int ...N> struct E { // expected-note {{candidate}} \
+ expected-note {{implicit deduction guide declared as 'template <int ...N> E(E<N...>) -> E<N...>'}}
template<int ...M> using B = Z<X<N, M>...>;
template<int M1, int M2> E(B<M1, M2>); // expected-note {{candidate}}
};
diff --git a/clang/test/SemaTemplate/nested-implicit-deduction-guides.cpp b/clang/test/SemaTemplate/nested-implicit-deduction-guides.cpp
index a4ae046ac5274..af3e3358f6138 100644
--- a/clang/test/SemaTemplate/nested-implicit-deduction-guides.cpp
+++ b/clang/test/SemaTemplate/nested-implicit-deduction-guides.cpp
@@ -82,8 +82,11 @@ using NIL = nested_init_list<int>::B<int>;
// expected-error at +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 {
diff --git a/clang/test/SemaTemplate/temp_arg.cpp b/clang/test/SemaTemplate/temp_arg.cpp
index 2db4a51d6cccb..538056a4e44c7 100644
--- a/clang/test/SemaTemplate/temp_arg.cpp
+++ b/clang/test/SemaTemplate/temp_arg.cpp
@@ -6,7 +6,9 @@ template<typename T,
class A; // precxx17-note 3 {{template is declared here}} \
cxx17-note 2 {{template is declared here}} \
cxx17-note {{candidate template ignored: couldn't infer template argument 'T'}} \
- cxx17-note {{candidate function template not viable: requires 1 argument, but 0 were provided}}
+ cxx17-note {{implicit deduction guide declared as 'template <typename T, int I, template <typename> class TT> A(A<T, I, TT>) -> A<T, I, TT>'}} \
+ cxx17-note {{candidate function template not viable: requires 1 argument, but 0 were provided}} \
+ cxx17-note {{implicit deduction guide declared as 'template <typename T, int I, template <typename> class TT> A() -> A<T, I, TT>'}} \
template<typename> class X;
>From 68a06465fc2385e8bd8a29eb5c353f1ae5cc916d Mon Sep 17 00:00:00 2001
From: Younan Zhang <zyn7109 at gmail.com>
Date: Fri, 21 Jun 2024 11:25:47 +0800
Subject: [PATCH 02/11] Apply suggestions from Sirraide
Co-authored-by: Sirraide <aeternalmail at gmail.com>
---
clang/docs/ReleaseNotes.rst | 4 ++--
clang/lib/Sema/SemaOverload.cpp | 10 +++++-----
2 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 423f1e9198948..558792fb82e7e 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -580,8 +580,8 @@ Improvements to Clang's diagnostics
- Clang no longer emits a "declared here" note for a builtin function that has no declaration in source.
Fixes #GH93369.
-- Clang now emits implicit deduction guides corresponding to non-user-defined constructors while at a failure
- of overload resolution.
+- Clang now shows implicit deduction guides corresponding to implcitly defined constructors when
+ diagnosing overload resolution failure.
Improvements to Clang's time-trace
----------------------------------
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 31b908eb3cc3c..38e52581ab5af 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -12115,15 +12115,15 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
return;
}
- // If this is an implicit deduction guide against a non-user-defined
- // constructor, add a note for it. These deduction guides nor their
- // corresponding constructors are not explicitly spelled in the source code,
+ // If this is an implicit deduction guide against an implicitly defined
+ // constructor, add a note for it. Neither these deduction guides nor their
+ // corresponding constructors are explicitly spelled in the source code,
// and simply producing a deduction failure note around the heading of the
- // enclosing RecordDecl is confusing.
+ // enclosing RecordDecl would be confusing.
//
// We prefer adding such notes at the end of the last deduction failure
// reason because duplicate code snippets appearing in the diagnostic
- // are likely becoming noisy.
+ // would likely become noisy.
auto _ = llvm::make_scope_exit([&] {
auto *DG = dyn_cast<CXXDeductionGuideDecl>(Fn);
if (!DG || !DG->isImplicit() || DG->getCorrespondingConstructor())
>From 616da22375b870090215e2318f1c98ffc3a23a5a Mon Sep 17 00:00:00 2001
From: Younan Zhang <zyn7109 at gmail.com>
Date: Fri, 21 Jun 2024 11:28:12 +0800
Subject: [PATCH 03/11] Fix tests
---
clang/test/CXX/expr/expr.post/expr.type.conv/p1.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/test/CXX/expr/expr.post/expr.type.conv/p1.cpp b/clang/test/CXX/expr/expr.post/expr.type.conv/p1.cpp
index aa3c022e9b134..f8d88e13fce31 100644
--- a/clang/test/CXX/expr/expr.post/expr.type.conv/p1.cpp
+++ b/clang/test/CXX/expr/expr.post/expr.type.conv/p1.cpp
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -std=c++1z -verify %s
-template<typename T> struct A { // expected-note 2{{candidate}} {{implicit deduction guide}}
+template<typename T> struct A { // expected-note 2{{candidate}} expected-note 2{{implicit deduction guide}}
T t, u;
};
template<typename T> A(T, T) -> A<T>; // expected-note {{deduced conflicting types for parameter 'T'}}
>From a468b7ccad1f70e9db3fc4c1f1c6f6478479bd93 Mon Sep 17 00:00:00 2001
From: Younan Zhang <zyn7109 at gmail.com>
Date: Tue, 25 Jun 2024 19:53:33 +0800
Subject: [PATCH 04/11] Address Hokein's feedback
---
clang/docs/ReleaseNotes.rst | 2 +-
clang/lib/Sema/SemaOverload.cpp | 25 ++++++++++++-------
.../over.match.class.deduct/p2.cpp | 3 ++-
.../temp.deduct/temp.deduct.call/p3-0x.cpp | 8 +++---
clang/test/PCH/cxx-explicit-specifier.cpp | 2 +-
...xx1z-class-template-argument-deduction.cpp | 12 +++++----
clang/test/SemaCXX/cxx20-ctad-type-alias.cpp | 6 ++++-
clang/test/SemaCXX/cxx2a-explicit-bool.cpp | 2 ++
clang/test/SemaCXX/gh65522.cpp | 3 ++-
clang/test/SemaTemplate/ctad.cpp | 6 +++--
clang/test/SemaTemplate/deduction-guide.cpp | 8 +++---
11 files changed, 50 insertions(+), 27 deletions(-)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 4c9f2b76a5e15..71ed84a9fff4a 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -610,7 +610,7 @@ Improvements to Clang's diagnostics
The check is now stricter to prevent crashes for some unsupported declarations (Fixes #GH95495).
- Clang now shows implicit deduction guides corresponding to implcitly defined constructors when
- diagnosing overload resolution failure.
+ diagnosing overload resolution failure. #GH92393.
Improvements to Clang's time-trace
----------------------------------
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 38e52581ab5af..4214c0041da56 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -12115,18 +12115,25 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
return;
}
- // If this is an implicit deduction guide against an implicitly defined
- // constructor, add a note for it. Neither these deduction guides nor their
- // corresponding constructors are explicitly spelled in the source code,
- // and simply producing a deduction failure note around the heading of the
- // enclosing RecordDecl would be confusing.
+ // If this is a synthesized deduction guide we're deducing against, add a note
+ // for it. These deduction guides are not explicitly spelled in the source
+ // code, so simply printing a deduction failure note mentioning synthesized
+ // template parameters or pointing to the header of the surrounding RecordDecl
+ // would be confusing.
//
- // We prefer adding such notes at the end of the last deduction failure
- // reason because duplicate code snippets appearing in the diagnostic
- // would likely become noisy.
+ // We prefer adding such notes at the end of the deduction failure because
+ // duplicate code snippets appearing in the diagnostic would likely become
+ // noisy.
auto _ = llvm::make_scope_exit([&] {
auto *DG = dyn_cast<CXXDeductionGuideDecl>(Fn);
- if (!DG || !DG->isImplicit() || DG->getCorrespondingConstructor())
+ if (!DG)
+ return;
+ // We want to always print synthesized deduction guides for type aliases.
+ // They would retain the explicit bit of the corresponding constructor.
+ if (TemplateDecl *OriginTemplate =
+ DG->getDeclName().getCXXDeductionGuideTemplate();
+ !DG->isImplicit() &&
+ (!OriginTemplate || !OriginTemplate->isTypeAlias()))
return;
std::string FunctionProto;
llvm::raw_string_ostream OS(FunctionProto);
diff --git a/clang/test/CXX/over/over.match/over.match.funcs/over.match.class.deduct/p2.cpp b/clang/test/CXX/over/over.match/over.match.funcs/over.match.class.deduct/p2.cpp
index 4bcf4ee2e3fe7..d192070132d78 100644
--- a/clang/test/CXX/over/over.match/over.match.funcs/over.match.class.deduct/p2.cpp
+++ b/clang/test/CXX/over/over.match/over.match.funcs/over.match.class.deduct/p2.cpp
@@ -36,7 +36,8 @@ namespace std {
namespace p0702r1 {
template<typename T> struct X { // expected-note {{candidate}} expected-note {{implicit deduction guide}}
- X(std::initializer_list<T>); // expected-note {{candidate template ignored: could not match 'std::initializer_list<T>' against 'Z'}}
+ X(std::initializer_list<T>); // expected-note {{candidate template ignored: could not match 'std::initializer_list<T>' against 'Z'}} \
+ // expected-note {{implicit deduction guide declared as 'template <typename T> X(std::initializer_list<T>) -> X<T>'}}
};
X xi = {0};
diff --git a/clang/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p3-0x.cpp b/clang/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p3-0x.cpp
index 2e39697a1f07f..ed445360c4fdd 100644
--- a/clang/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p3-0x.cpp
+++ b/clang/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p3-0x.cpp
@@ -7,7 +7,7 @@
namespace ClassTemplateParamNotForwardingRef {
// This is not a forwarding reference.
template<typename T> struct A { // expected-note {{candidate}} expected-note {{implicit deduction guide}}
- A(T&&); // expected-note {{expects an rvalue}}
+ A(T&&); // expected-note {{expects an rvalue}} expected-note {{implicit deduction guide}}
};
int n;
A a = n; // expected-error {{no viable constructor or deduction guide}}
@@ -77,8 +77,10 @@ namespace std_example {
#if __cplusplus > 201402L
template<class T> struct A { // expected-note {{candidate}} expected-note {{implicit deduction guide}}
template<class U>
- A(T &&, U &&, int *); // expected-note {{[with T = int, U = int] not viable: expects an rvalue}}
- A(T &&, int *); // expected-note {{requires 2}}
+ A(T &&, U &&, int *); // expected-note {{[with T = int, U = int] not viable: expects an rvalue}} \
+ // expected-note {{implicit deduction guide declared as 'template <class T, class U> A(T &&, type-parameter-0-1 &&, int *) -> A<T>'}}
+ A(T &&, int *); // expected-note {{requires 2}} \
+ // expected-note {{implicit deduction guide declared as 'template <class T> A(T &&, int *) -> A<T>'}}
};
template<class T> A(T &&, int *) -> A<T>; // expected-note {{requires 2}}
diff --git a/clang/test/PCH/cxx-explicit-specifier.cpp b/clang/test/PCH/cxx-explicit-specifier.cpp
index 68dfc911164c5..84548faf48810 100644
--- a/clang/test/PCH/cxx-explicit-specifier.cpp
+++ b/clang/test/PCH/cxx-explicit-specifier.cpp
@@ -80,7 +80,7 @@ B<true> b_true;
B<false> b_false;
#else
//expected-note at -8 {{candidate template ignored}} expected-note at -8 {{implicit deduction guide declared as 'template <bool b> A(A<b>) -> A<b>'}}
-//expected-note at -8 {{explicit constructor declared here}}
+//expected-note at -8 {{explicit constructor declared here}} expected-note at -8 {{implicit deduction guide declared as 'template <bool b> explicit(b) A(B<b>) -> A<b>'}}
//expected-note at -15+ {{candidate constructor}}
//expected-note at -8+ {{explicit conversion function is not a candidate (explicit specifier}}
//expected-note at -11 {{explicit constructor is not a candidate (explicit specifier}}
diff --git a/clang/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp b/clang/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp
index 0a296b32cfb6f..9ef5303a9c4df 100644
--- a/clang/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp
+++ b/clang/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp
@@ -140,11 +140,12 @@ namespace look_into_current_instantiation {
A<float> &r = a;
template<typename T> struct B { // expected-note {{could not match 'B<T>' against 'int'}} \
- expected-note {{implicit deduction guide declared as 'template <typename T> B(B<T>) -> B<T>'}}
+ // expected-note {{implicit deduction guide declared as 'template <typename T> B(B<T>) -> B<T>'}}
struct X {
typedef T type;
};
- B(typename X::type); // expected-note {{couldn't infer template argument 'T'}}
+ B(typename X::type); // expected-note {{couldn't infer template argument 'T'}} \
+ // expected-note {{implicit deduction guide declared as 'template <typename T> B(typename X::type) -> B<T>'}}
};
B b = 0; // expected-error {{no viable}}
@@ -565,9 +566,10 @@ namespace PR47175 {
// Ensure we don't crash when CTAD fails.
template <typename T1, typename T2>
-struct Foo { // expected-note{{candidate function template not viable}} \
- expected-note{{implicit deduction guide declared as 'template <typename T1, typename T2> Foo(Foo<T1, T2>) -> Foo<T1, T2>'}}
- Foo(T1, T2); // expected-note{{candidate function template not viable}}
+struct Foo { // expected-note {{candidate function template not viable}} \
+ // expected-note {{implicit deduction guide declared as 'template <typename T1, typename T2> Foo(Foo<T1, T2>) -> Foo<T1, T2>'}}
+ Foo(T1, T2); // expected-note {{candidate function template not viable}} \
+ // expected-note {{implicit deduction guide declared as 'template <typename T1, typename T2> Foo(T1, T2) -> Foo<T1, T2>'}}
};
template <typename... Args>
diff --git a/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp b/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
index 901f64434bbee..4cd53e10e74c5 100644
--- a/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
+++ b/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
@@ -113,6 +113,7 @@ struct Foo {
template <typename X, int Y>
using Bar = Foo<X, sizeof(X)>; // expected-note {{candidate template ignored: couldn't infer template argument 'X'}} \
// expected-note {{implicit deduction guide declared as 'template <typename X> Bar(Foo<type-parameter-0-0, sizeof(type-parameter-0-0)>) -> Foo<type-parameter-0-0, sizeof(type-parameter-0-0)>'}} \
+ // expected-note {{implicit deduction guide declared as 'template <typename X> Bar(const type-parameter-0-0 (&)[sizeof(type-parameter-0-0)]) -> Foo<type-parameter-0-0, sizeof(type-parameter-0-0)>'}} \
// expected-note {{candidate template ignored: constraints not satisfied [with X = int]}} \
// expected-note {{cannot deduce template arguments for 'Bar' from 'Foo<int, 4UL>'}}
@@ -199,6 +200,7 @@ template <int K>
using Bar = Foo<double, K>; // expected-note {{constraints not satisfied for class template 'Foo'}}
// expected-note at -1 {{candidate template ignored: could not match}}
// expected-note at -2 {{implicit deduction guide declared as 'template <int K> Bar(Foo<double, K>) -> Foo<double, K>'}}
+// expected-note at -3 {{implicit deduction guide declared as 'template <int K> Bar(const double (&)[K]) -> Foo<double, K>'}}
double abc[3];
Bar s2 = {abc}; // expected-error {{no viable constructor or deduction guide for deduction }}
} // namespace test14
@@ -211,6 +213,7 @@ template<typename> concept False = false;
template<False W>
using BFoo = AFoo<W>; // expected-note {{candidate template ignored: constraints not satisfied [with V = int]}} \
// expected-note {{cannot deduce template arguments for 'BFoo' from 'Foo<int *>'}} \
+ // expected-note {{implicit deduction guide declared as 'template <class V> BFoo(type-parameter-0-0 *) -> Foo<type-parameter-0-0 *>'}} \
// expected-note {{implicit deduction guide declared as 'template <class V> BFoo(Foo<type-parameter-0-0 *>) -> Foo<type-parameter-0-0 *>'}} \
// expected-note {{candidate template ignored: could not match 'Foo<type-parameter-0-0 *>' against 'int *'}}
int i = 0;
@@ -266,7 +269,8 @@ using Bar = Foo<U>; // expected-note {{could not match 'Foo<type-parameter-0-0>'
// expected-note {{candidate template ignored: constraints not satisfied}} \
// expected-note {{candidate function template not viable}} \
// expected-note {{implicit deduction guide declared as 'template <typename U> Bar() -> Foo<type-parameter-0-0>'}} \
- // expected-note {{implicit deduction guide declared as 'template <typename U> Bar(Foo<type-parameter-0-0>) -> Foo<type-parameter-0-0>'}}
+ // expected-note {{implicit deduction guide declared as 'template <typename U> Bar(Foo<type-parameter-0-0>) -> Foo<type-parameter-0-0>'}} \
+ // expected-note {{implicit deduction guide declared as 'template <typename T> Bar(type-parameter-0-0) -> Foo<int>'}}
Bar s = {1}; // expected-error {{no viable constructor or deduction guide for deduction of template arguments}}
} // namespace test18
diff --git a/clang/test/SemaCXX/cxx2a-explicit-bool.cpp b/clang/test/SemaCXX/cxx2a-explicit-bool.cpp
index 13b5ff1d59b31..03799c52654a5 100644
--- a/clang/test/SemaCXX/cxx2a-explicit-bool.cpp
+++ b/clang/test/SemaCXX/cxx2a-explicit-bool.cpp
@@ -398,6 +398,7 @@ struct A {
explicit(false)
A(typename nondeduced<T1>::type, typename nondeduced<T2>::type, typename nondeduced<B<b>>::type) {}
// expected-note at -1+ {{candidate template ignored}}
+ // expected-note at -2+ {{implicit deduction guide}}
};
template<typename T1, typename T2, bool b>
@@ -684,6 +685,7 @@ struct A {
A(T1 = 0, T2 = 0) {}
// expected-note at -1 {{explicit constructor declared here}}
// expected-note at -2 2{{explicit constructor is not a candidate}}
+ // expected-note at -3 2{{implicit deduction guide declared}}
};
A a0 = 0;
diff --git a/clang/test/SemaCXX/gh65522.cpp b/clang/test/SemaCXX/gh65522.cpp
index bfc3a1e12fe76..80281248c6d49 100644
--- a/clang/test/SemaCXX/gh65522.cpp
+++ b/clang/test/SemaCXX/gh65522.cpp
@@ -6,7 +6,8 @@ template<typename T>
class B3 { // expected-note {{candidate template ignored: could not match 'B3<T>' against 'int'}} \
// expected-note {{implicit deduction guide declared as 'template <typename T> B3(B3<T>) -> B3<T>'}}
template<X x> B3(T); // expected-warning 2{{non-type template parameter of type 'X' is incompatible with C++ standards before C++20}} \
- // expected-note {{candidate template ignored: couldn't infer template argument 'x'}}
+ // expected-note {{candidate template ignored: couldn't infer template argument 'x'}} \
+ // expected-note {{implicit deduction guide declared as 'template <typename T, X x> B3(T) -> B3<T>'}}
};
B3 b3 = 0; // expected-error {{no viable constructor or deduction guide for deduction of template arguments of 'B3'}} \
// expected-note {{while building implicit deduction guide first needed here}}
diff --git a/clang/test/SemaTemplate/ctad.cpp b/clang/test/SemaTemplate/ctad.cpp
index c5e467a8d7724..1bf605f823bbe 100644
--- a/clang/test/SemaTemplate/ctad.cpp
+++ b/clang/test/SemaTemplate/ctad.cpp
@@ -22,7 +22,8 @@ namespace Access {
};
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}}
+ 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(), {}};
@@ -59,7 +60,8 @@ Y y(1);
namespace NoCrashOnGettingDefaultArgLoc {
template <typename>
class A {
- A(int = 1); // expected-note {{candidate template ignored: couldn't infer template argumen}}
+ 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;
diff --git a/clang/test/SemaTemplate/deduction-guide.cpp b/clang/test/SemaTemplate/deduction-guide.cpp
index 54420be9ee969..7b9ca4d83b020 100644
--- a/clang/test/SemaTemplate/deduction-guide.cpp
+++ b/clang/test/SemaTemplate/deduction-guide.cpp
@@ -124,9 +124,10 @@ using CT = C<int>;
// CHECK: `-TemplateTypeParmType {{.*}} 'type-parameter-0-2' dependent depth 0 index 2
template<typename ...T> struct D { // expected-note {{candidate}} \
- expected-note {{implicit deduction guide declared as 'template <typename ...T> D(D<T...>) -> D<T...>'}}
+ // expected-note {{implicit deduction guide declared as 'template <typename ...T> D(D<T...>) -> D<T...>'}}
template<typename... U> using B = int(int (*...p)(T, U));
- template<typename U1, typename U2> D(B<U1, U2>*); // expected-note {{candidate}}
+ template<typename U1, typename U2> D(B<U1, U2>*); // expected-note {{candidate}} \
+ // expected-note {{implicit deduction guide declared as 'template <typename ...T, typename U1, typename U2> D(B<type-parameter-0-1, type-parameter-0-2> *) -> D<T...>'}}
};
int f(int(int, int), int(int, int));
// FIXME: We can't deduce this because we can't deduce through a
@@ -170,7 +171,8 @@ using DT = D<int, int>;
template<int ...N> struct E { // expected-note {{candidate}} \
expected-note {{implicit deduction guide declared as 'template <int ...N> E(E<N...>) -> E<N...>'}}
template<int ...M> using B = Z<X<N, M>...>;
- template<int M1, int M2> E(B<M1, M2>); // expected-note {{candidate}}
+ template<int M1, int M2> E(B<M1, M2>); // expected-note {{candidate}} \
+ // expected-note {{implicit deduction guide declared as 'template <int ...N, int M1, int M2> E(B<M1, M2>) -> E<N...>'}}}}
};
// FIXME: We can't deduce this because we can't deduce through a
// SubstNonTypeTemplateParmPackExpr.
>From 34b665e55ceded46da20c492a99179b9a41a15b6 Mon Sep 17 00:00:00 2001
From: Younan Zhang <zyn7109 at gmail.com>
Date: Tue, 25 Jun 2024 20:17:52 +0800
Subject: [PATCH 05/11] Remove an unnecessary FIXME
---
clang/test/SemaCXX/cxx20-ctad-type-alias.cpp | 1 -
1 file changed, 1 deletion(-)
diff --git a/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp b/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
index 4cd53e10e74c5..761648926f99b 100644
--- a/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
+++ b/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
@@ -108,7 +108,6 @@ struct Foo {
Foo(T const (&)[N]);
};
-// FIXME: Clarify that __is_deducible constraints are unsatisfied. For example, GCC currently prints the code snippet around constructors
// FIXME: Prefer non-canonical template arguments in the deduction guide?
template <typename X, int Y>
using Bar = Foo<X, sizeof(X)>; // expected-note {{candidate template ignored: couldn't infer template argument 'X'}} \
>From 8ef907675dc2448aca68182d6729dba4c53acbba Mon Sep 17 00:00:00 2001
From: Younan Zhang <zyn7109 at gmail.com>
Date: Wed, 26 Jun 2024 10:51:55 +0800
Subject: [PATCH 06/11] Move the function out-of-line and adapt to #96686
---
clang/lib/Sema/SemaOverload.cpp | 59 +++++++++++++++++++++------------
1 file changed, 38 insertions(+), 21 deletions(-)
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 4214c0041da56..8165ede26f1f4 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -12058,6 +12058,43 @@ static void DiagnoseFailedExplicitSpec(Sema &S, OverloadCandidate *Cand) {
<< (ES.getExpr() ? ES.getExpr()->getSourceRange() : SourceRange());
}
+static void maybeNoteImplicitDeductionGuide(Sema &S,
+ CXXDeductionGuideDecl *DG) {
+ // We want to always print synthesized deduction guides for type aliases.
+ // They would retain the explicit bit of the corresponding constructor.
+ TemplateDecl *OriginTemplate =
+ DG->getDeclName().getCXXDeductionGuideTemplate();
+ if (!DG->isImplicit() && (!OriginTemplate || !OriginTemplate->isTypeAlias()))
+ return;
+ std::string FunctionProto;
+ llvm::raw_string_ostream OS(FunctionProto);
+ FunctionTemplateDecl *Template = DG->getDescribedFunctionTemplate();
+ if (!Template) {
+ // This also could be an instantiation. Find out the primary template.
+ FunctionDecl *Pattern =
+ DG->getTemplateInstantiationPattern(/*ForDefinition=*/false);
+ if (!Pattern) {
+ // The implicit deduction guide is built on an explicit non-template
+ // deduction guide. Currently, this might be the case only for type
+ // aliases.
+ // FIXME: Add a test once https://github.com/llvm/llvm-project/pull/96686
+ // gets merged.
+ assert(OriginTemplate->isTypeAlias() &&
+ "Only deduction guides for type aliases can have no template Decls");
+ DG->print(OS);
+ S.Diag(DG->getLocation(), diag::note_implicit_deduction_guide)
+ << FunctionProto;
+ return;
+ }
+ Template = Pattern->getDescribedFunctionTemplate();
+ assert(Template && "Cannot find the associated function template of "
+ "CXXDeductionGuideDecl?");
+ }
+ Template->print(OS);
+ S.Diag(DG->getLocation(), diag::note_implicit_deduction_guide)
+ << FunctionProto;
+}
+
/// Generates a 'note' diagnostic for an overload candidate. We've
/// already generated a primary error at the call site.
///
@@ -12128,27 +12165,7 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
auto *DG = dyn_cast<CXXDeductionGuideDecl>(Fn);
if (!DG)
return;
- // We want to always print synthesized deduction guides for type aliases.
- // They would retain the explicit bit of the corresponding constructor.
- if (TemplateDecl *OriginTemplate =
- DG->getDeclName().getCXXDeductionGuideTemplate();
- !DG->isImplicit() &&
- (!OriginTemplate || !OriginTemplate->isTypeAlias()))
- return;
- std::string FunctionProto;
- llvm::raw_string_ostream OS(FunctionProto);
- FunctionTemplateDecl *Template = DG->getDescribedFunctionTemplate();
- // This also could be an instantiation. Find out the primary template.
- if (!Template) {
- FunctionDecl *Pattern = DG->getTemplateInstantiationPattern();
- assert(Pattern && Pattern->getDescribedFunctionTemplate() &&
- "Cannot find the associated function template of "
- "CXXDeductionGuideDecl?");
- Template = Pattern->getDescribedFunctionTemplate();
- }
- Template->print(OS);
- S.Diag(DG->getLocation(), diag::note_implicit_deduction_guide)
- << FunctionProto;
+ maybeNoteImplicitDeductionGuide(S, DG);
});
switch (Cand->FailureKind) {
>From bb0b8364228474d0a9734bdfc60f696c692f2d9e Mon Sep 17 00:00:00 2001
From: Younan Zhang <zyn7109 at gmail.com>
Date: Wed, 26 Jun 2024 10:54:02 +0800
Subject: [PATCH 07/11] Format
---
clang/lib/Sema/SemaOverload.cpp | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 8165ede26f1f4..64d7294a6bf29 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -12079,8 +12079,9 @@ static void maybeNoteImplicitDeductionGuide(Sema &S,
// aliases.
// FIXME: Add a test once https://github.com/llvm/llvm-project/pull/96686
// gets merged.
- assert(OriginTemplate->isTypeAlias() &&
- "Only deduction guides for type aliases can have no template Decls");
+ assert(
+ OriginTemplate->isTypeAlias() &&
+ "Only deduction guides for type aliases can have no template Decls");
DG->print(OS);
S.Diag(DG->getLocation(), diag::note_implicit_deduction_guide)
<< FunctionProto;
>From f8237bdde2559fba71103d5457c3404df887da80 Mon Sep 17 00:00:00 2001
From: Younan Zhang <zyn7109 at gmail.com>
Date: Wed, 26 Jun 2024 10:58:02 +0800
Subject: [PATCH 08/11] maybeNote -> Note
---
clang/lib/Sema/SemaOverload.cpp | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 64d7294a6bf29..129e83e8110b4 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -12058,8 +12058,7 @@ static void DiagnoseFailedExplicitSpec(Sema &S, OverloadCandidate *Cand) {
<< (ES.getExpr() ? ES.getExpr()->getSourceRange() : SourceRange());
}
-static void maybeNoteImplicitDeductionGuide(Sema &S,
- CXXDeductionGuideDecl *DG) {
+static void NoteImplicitDeductionGuide(Sema &S, CXXDeductionGuideDecl *DG) {
// We want to always print synthesized deduction guides for type aliases.
// They would retain the explicit bit of the corresponding constructor.
TemplateDecl *OriginTemplate =
@@ -12166,7 +12165,7 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
auto *DG = dyn_cast<CXXDeductionGuideDecl>(Fn);
if (!DG)
return;
- maybeNoteImplicitDeductionGuide(S, DG);
+ NoteImplicitDeductionGuide(S, DG);
});
switch (Cand->FailureKind) {
>From 02a1c0a8a69717c47aaf6c76cfbe66c8df03a32a Mon Sep 17 00:00:00 2001
From: Younan Zhang <zyn7109 at gmail.com>
Date: Thu, 27 Jun 2024 19:41:31 +0800
Subject: [PATCH 09/11] Adapt tests for the constraint printing
---
clang/test/SemaCXX/cxx20-ctad-type-alias.cpp | 28 ++++++++++----------
1 file changed, 14 insertions(+), 14 deletions(-)
diff --git a/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp b/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
index 761648926f99b..c4cd17d38e6ac 100644
--- a/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
+++ b/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
@@ -111,8 +111,8 @@ struct Foo {
// FIXME: Prefer non-canonical template arguments in the deduction guide?
template <typename X, int Y>
using Bar = Foo<X, sizeof(X)>; // expected-note {{candidate template ignored: couldn't infer template argument 'X'}} \
- // expected-note {{implicit deduction guide declared as 'template <typename X> Bar(Foo<type-parameter-0-0, sizeof(type-parameter-0-0)>) -> Foo<type-parameter-0-0, sizeof(type-parameter-0-0)>'}} \
- // expected-note {{implicit deduction guide declared as 'template <typename X> Bar(const type-parameter-0-0 (&)[sizeof(type-parameter-0-0)]) -> Foo<type-parameter-0-0, sizeof(type-parameter-0-0)>'}} \
+ // expected-note {{implicit deduction guide declared as 'template <typename X> requires __is_deducible(test9::Bar, Foo<type-parameter-0-0, sizeof(type-parameter-0-0)>) Bar(Foo<type-parameter-0-0, sizeof(type-parameter-0-0)>) -> Foo<type-parameter-0-0, sizeof(type-parameter-0-0)>'}} \
+ // expected-note {{implicit deduction guide declared as 'template <typename X> requires __is_deducible(test9::Bar, Foo<type-parameter-0-0, sizeof(type-parameter-0-0)>) Bar(const type-parameter-0-0 (&)[sizeof(type-parameter-0-0)]) -> Foo<type-parameter-0-0, sizeof(type-parameter-0-0)>'}} \
// expected-note {{candidate template ignored: constraints not satisfied [with X = int]}} \
// expected-note {{cannot deduce template arguments for 'Bar' from 'Foo<int, 4UL>'}}
@@ -140,12 +140,12 @@ struct A {};
template<class T> struct Foo { T c; };
template<class X, class Y=A>
using AFoo = Foo<Y>; // expected-note {{candidate template ignored: could not match 'Foo<type-parameter-0-0>' against 'int'}} \
- // expected-note {{implicit deduction guide declared as 'template <class Y = A> AFoo(Foo<type-parameter-0-0>) -> Foo<type-parameter-0-0>'}} \
+ // expected-note {{implicit deduction guide declared as 'template <class Y = A> requires __is_deducible(test11::AFoo, Foo<type-parameter-0-0>) AFoo(Foo<type-parameter-0-0>) -> Foo<type-parameter-0-0>'}} \
// expected-note {{candidate template ignored: constraints not satisfied [with Y = int]}} \
// expected-note {{cannot deduce template arguments for 'AFoo' from 'Foo<int>'}} \
- // expected-note {{implicit deduction guide declared as 'template <class Y = A> AFoo(type-parameter-0-0) -> Foo<type-parameter-0-0>'}} \
+ // expected-note {{implicit deduction guide declared as 'template <class Y = A> requires __is_deducible(test11::AFoo, Foo<type-parameter-0-0>) AFoo(type-parameter-0-0) -> Foo<type-parameter-0-0>'}} \
// expected-note {{candidate function template not viable: requires 0 arguments, but 1 was provided}} \
- // expected-note {{implicit deduction guide declared as 'template <class Y = A> AFoo() -> Foo<type-parameter-0-0>'}}
+ // expected-note {{implicit deduction guide declared as 'template <class Y = A> requires __is_deducible(test11::AFoo, Foo<type-parameter-0-0>) AFoo() -> Foo<type-parameter-0-0>'}}
AFoo s = {1}; // expected-error {{no viable constructor or deduction guide for deduction of template arguments of 'AFoo'}}
} // namespace test11
@@ -198,8 +198,8 @@ struct Foo {
template <int K>
using Bar = Foo<double, K>; // expected-note {{constraints not satisfied for class template 'Foo'}}
// expected-note at -1 {{candidate template ignored: could not match}}
-// expected-note at -2 {{implicit deduction guide declared as 'template <int K> Bar(Foo<double, K>) -> Foo<double, K>'}}
-// expected-note at -3 {{implicit deduction guide declared as 'template <int K> Bar(const double (&)[K]) -> Foo<double, K>'}}
+// expected-note at -2 {{implicit deduction guide declared as 'template <int K> requires __is_deducible(test14::Bar, Foo<double, K>) Bar(Foo<double, K>) -> Foo<double, K>'}}
+// expected-note at -3 {{implicit deduction guide declared as 'template <int K> requires __is_deducible(test14::Bar, Foo<double, K>) Bar(const double (&)[K]) -> Foo<double, K>'}}
double abc[3];
Bar s2 = {abc}; // expected-error {{no viable constructor or deduction guide for deduction }}
} // namespace test14
@@ -212,9 +212,9 @@ template<typename> concept False = false;
template<False W>
using BFoo = AFoo<W>; // expected-note {{candidate template ignored: constraints not satisfied [with V = int]}} \
// expected-note {{cannot deduce template arguments for 'BFoo' from 'Foo<int *>'}} \
- // expected-note {{implicit deduction guide declared as 'template <class V> BFoo(type-parameter-0-0 *) -> Foo<type-parameter-0-0 *>'}} \
- // expected-note {{implicit deduction guide declared as 'template <class V> BFoo(Foo<type-parameter-0-0 *>) -> Foo<type-parameter-0-0 *>'}} \
- // expected-note {{candidate template ignored: could not match 'Foo<type-parameter-0-0 *>' against 'int *'}}
+ // expected-note {{implicit deduction guide declared as 'template <class V> requires __is_deducible(AFoo, Foo<type-parameter-0-0 *>) && __is_deducible(test15::BFoo, Foo<type-parameter-0-0 *>) BFoo(type-parameter-0-0 *) -> Foo<type-parameter-0-0 *>}} \
+ // expected-note {{candidate template ignored: could not match 'Foo<type-parameter-0-0 *>' against 'int *'}} \
+ // expected-note {{template <class V> requires __is_deducible(AFoo, Foo<type-parameter-0-0 *>) && __is_deducible(test15::BFoo, Foo<type-parameter-0-0 *>) BFoo(Foo<type-parameter-0-0 *>) -> Foo<type-parameter-0-0 *>}}
int i = 0;
AFoo a1(&i); // OK, deduce Foo<int *>
@@ -265,11 +265,11 @@ Foo(T) -> Foo<int>;
template <typename U>
using Bar = Foo<U>; // expected-note {{could not match 'Foo<type-parameter-0-0>' against 'int'}} \
+ // expected-note {{implicit deduction guide declared as 'template <typename U> requires __is_deducible(test18::Bar, Foo<type-parameter-0-0>) Bar(Foo<type-parameter-0-0>) -> Foo<type-parameter-0-0>'}} \
// expected-note {{candidate template ignored: constraints not satisfied}} \
+ // expected-note {{implicit deduction guide declared as 'template <typename T> requires False<T> && __is_deducible(test18::Bar, Foo<int>) Bar(type-parameter-0-0) -> Foo<int>'}} \
// expected-note {{candidate function template not viable}} \
- // expected-note {{implicit deduction guide declared as 'template <typename U> Bar() -> Foo<type-parameter-0-0>'}} \
- // expected-note {{implicit deduction guide declared as 'template <typename U> Bar(Foo<type-parameter-0-0>) -> Foo<type-parameter-0-0>'}} \
- // expected-note {{implicit deduction guide declared as 'template <typename T> Bar(type-parameter-0-0) -> Foo<int>'}}
+ // expected-note {{implicit deduction guide declared as 'template <typename U> requires __is_deducible(test18::Bar, Foo<type-parameter-0-0>) Bar() -> Foo<type-parameter-0-0>'}}
Bar s = {1}; // expected-error {{no viable constructor or deduction guide for deduction of template arguments}}
} // namespace test18
@@ -298,7 +298,7 @@ class Foo {};
// template arguments of the RHS.
template <template<typename> typename TTP>
using Bar = Foo<K<TTP>>; // expected-note {{candidate template ignored: could not match 'Foo<K<template-parameter-0-0>>' against 'int'}} \
- // expected-note {{implicit deduction guide declared as 'template <template <typename> typename TTP> Bar(Foo<K<template-parameter-0-0>>) -> Foo<K<template-parameter-0-0>>'}}
+ // expected-note {{implicit deduction guide declared as 'template <template <typename> typename TTP> requires __is_deducible(test20::Bar, Foo<K<template-parameter-0-0>>) Bar(Foo<K<template-parameter-0-0>>) -> Foo<K<template-parameter-0-0>>'}}
template <class T>
class Container {};
>From c9e7309f55a52b3c02688e990ce7db3e5a4d676f Mon Sep 17 00:00:00 2001
From: Younan Zhang <zyn7109 at gmail.com>
Date: Thu, 27 Jun 2024 19:43:40 +0800
Subject: [PATCH 10/11] Remove FIXME
---
clang/test/SemaCXX/cxx20-ctad-type-alias.cpp | 1 -
1 file changed, 1 deletion(-)
diff --git a/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp b/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
index c4cd17d38e6ac..3dafe823fbbaa 100644
--- a/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
+++ b/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
@@ -108,7 +108,6 @@ struct Foo {
Foo(T const (&)[N]);
};
-// FIXME: Prefer non-canonical template arguments in the deduction guide?
template <typename X, int Y>
using Bar = Foo<X, sizeof(X)>; // expected-note {{candidate template ignored: couldn't infer template argument 'X'}} \
// expected-note {{implicit deduction guide declared as 'template <typename X> requires __is_deducible(test9::Bar, Foo<type-parameter-0-0, sizeof(type-parameter-0-0)>) Bar(Foo<type-parameter-0-0, sizeof(type-parameter-0-0)>) -> Foo<type-parameter-0-0, sizeof(type-parameter-0-0)>'}} \
>From a18b5e71f2f29b584477e36b20e48a18bfc2e8ff Mon Sep 17 00:00:00 2001
From: Younan Zhang <zyn7109 at gmail.com>
Date: Fri, 28 Jun 2024 17:32:47 +0800
Subject: [PATCH 11/11] Address nits
---
clang/docs/ReleaseNotes.rst | 3 +--
clang/lib/Sema/SemaOverload.cpp | 24 +++++++++++-------------
2 files changed, 12 insertions(+), 15 deletions(-)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index ab964232d0e55..5397ff5f99364 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -627,8 +627,7 @@ Improvements to Clang's diagnostics
used rather than when they are needed for constant evaluation or when code is generated for them.
The check is now stricter to prevent crashes for some unsupported declarations (Fixes #GH95495).
-- Clang now shows implicit deduction guides corresponding to implcitly defined constructors when
- diagnosing overload resolution failure. #GH92393.
+- Clang now shows implicit deduction guides when diagnosing overload resolution failure. #GH92393.
Improvements to Clang's time-trace
----------------------------------
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 20b695d70516a..bcfd5dba63b58 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -12079,12 +12079,15 @@ static void DiagnoseFailedExplicitSpec(Sema &S, OverloadCandidate *Cand) {
<< (ES.getExpr() ? ES.getExpr()->getSourceRange() : SourceRange());
}
-static void NoteImplicitDeductionGuide(Sema &S, CXXDeductionGuideDecl *DG) {
- // We want to always print synthesized deduction guides for type aliases.
- // They would retain the explicit bit of the corresponding constructor.
+static void NoteImplicitDeductionGuide(Sema &S, FunctionDecl *Fn) {
+ auto *DG = dyn_cast<CXXDeductionGuideDecl>(Fn);
+ if (!DG)
+ return;
TemplateDecl *OriginTemplate =
DG->getDeclName().getCXXDeductionGuideTemplate();
- if (!DG->isImplicit() && (!OriginTemplate || !OriginTemplate->isTypeAlias()))
+ // We want to always print synthesized deduction guides for type aliases.
+ // They would retain the explicit bit of the corresponding constructor.
+ if (!(DG->isImplicit() || (OriginTemplate && OriginTemplate->isTypeAlias())))
return;
std::string FunctionProto;
llvm::raw_string_ostream OS(FunctionProto);
@@ -12099,9 +12102,9 @@ static void NoteImplicitDeductionGuide(Sema &S, CXXDeductionGuideDecl *DG) {
// aliases.
// FIXME: Add a test once https://github.com/llvm/llvm-project/pull/96686
// gets merged.
- assert(
- OriginTemplate->isTypeAlias() &&
- "Only deduction guides for type aliases can have no template Decls");
+ assert(OriginTemplate->isTypeAlias() &&
+ "Non-template implicit deduction guides are only possible for "
+ "type aliases");
DG->print(OS);
S.Diag(DG->getLocation(), diag::note_implicit_deduction_guide)
<< FunctionProto;
@@ -12182,12 +12185,7 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
// We prefer adding such notes at the end of the deduction failure because
// duplicate code snippets appearing in the diagnostic would likely become
// noisy.
- auto _ = llvm::make_scope_exit([&] {
- auto *DG = dyn_cast<CXXDeductionGuideDecl>(Fn);
- if (!DG)
- return;
- NoteImplicitDeductionGuide(S, DG);
- });
+ auto _ = llvm::make_scope_exit([&] { NoteImplicitDeductionGuide(S, Fn); });
switch (Cand->FailureKind) {
case ovl_fail_too_many_arguments:
More information about the cfe-commits
mailing list