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 <zyn7...@gmail.com> Date: Wed, 19 Jun 2024 23:25:13 +0800 Subject: [PATCH 1/9] [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@-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@Inputs/template_name_lookup/foo.cppm:3 {{candidate template ignored: couldn't infer template argument 'T'}} + // expected-note@Inputs/template_name_lookup/foo.cppm:3 {{implicit deduction guide declared as 'template <typename T> X(X<T>) -> X<T>'}} // expected-note@Inputs/template_name_lookup/foo.cppm:3 {{candidate function template not viable: requires 1 argument, but 0 were provided}} + // expected-note@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@-8 {{candidate template ignored}} +//expected-note@-8 {{candidate template ignored}} expected-note@-8 {{implicit deduction guide declared as 'template <bool b> A(A<b>) -> A<b>'}} //expected-note@-8 {{explicit constructor declared here}} //expected-note@-15+ {{candidate constructor}} //expected-note@-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@-1{{candidate template ignored: couldn't infer template argument ''}} -// expected-note@-2{{candidate function template not viable: requires 1 argument, but 0 were provided}} +// expected-note@-2{{implicit deduction guide declared as 'template <typename> templated_struct() -> templated_struct<type-parameter-0-0>'}} +// expected-note@-3{{candidate function template not viable: requires 1 argument, but 0 were provided}} +// expected-note@-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@-1 {{candidate template ignored: could not match}} +// expected-note@-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@-1+ {{candidate function}} + // expected-note@-2+ {{implicit deduction guide}} explicit(false) A(typename nondeduced<T1>::type, typename nondeduced<T2>::type, typename nondeduced<B<b>>::type) {} // expected-note@-1+ {{candidate template ignored}} @@ -678,6 +679,7 @@ namespace deduction_guide2 { template<typename T1 = int, typename T2 = int> struct A { // expected-note@-1+ {{candidate template ignored}} + // expected-note@-2+ {{implicit deduction guide}} explicit(!is_same<T1, T2>::value) A(T1 = 0, T2 = 0) {} // expected-note@-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@-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@-1 {{non-type template parameter has incomplete type 'struct U1'}} // expected-note@-2 {{forward declaration of 'PR51872_part1::U1'}} + // expected-note@-3 {{implicit deduction guide declared as 'template <int> T1(T1<>) -> T1<>'}} T1 t1 = 0; // expected-error@-1 {{no viable constructor or deduction guide for deduction of template arguments of 'T1'}} - // expected-note@-6 {{candidate template ignored: could not match 'T1<>' against 'int'}} + // expected-note@-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@+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 <zyn7...@gmail.com> Date: Fri, 21 Jun 2024 11:25:47 +0800 Subject: [PATCH 2/9] Apply suggestions from Sirraide Co-authored-by: Sirraide <aeternalm...@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 <zyn7...@gmail.com> Date: Fri, 21 Jun 2024 11:28:12 +0800 Subject: [PATCH 3/9] 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 <zyn7...@gmail.com> Date: Tue, 25 Jun 2024 19:53:33 +0800 Subject: [PATCH 4/9] 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@-8 {{candidate template ignored}} expected-note@-8 {{implicit deduction guide declared as 'template <bool b> A(A<b>) -> A<b>'}} -//expected-note@-8 {{explicit constructor declared here}} +//expected-note@-8 {{explicit constructor declared here}} expected-note@-8 {{implicit deduction guide declared as 'template <bool b> explicit(b) A(B<b>) -> A<b>'}} //expected-note@-15+ {{candidate constructor}} //expected-note@-8+ {{explicit conversion function is not a candidate (explicit specifier}} //expected-note@-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@-1 {{candidate template ignored: could not match}} // expected-note@-2 {{implicit deduction guide declared as 'template <int K> Bar(Foo<double, K>) -> Foo<double, K>'}} +// expected-note@-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@-1+ {{candidate template ignored}} + // expected-note@-2+ {{implicit deduction guide}} }; template<typename T1, typename T2, bool b> @@ -684,6 +685,7 @@ struct A { A(T1 = 0, T2 = 0) {} // expected-note@-1 {{explicit constructor declared here}} // expected-note@-2 2{{explicit constructor is not a candidate}} + // expected-note@-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 <zyn7...@gmail.com> Date: Tue, 25 Jun 2024 20:17:52 +0800 Subject: [PATCH 5/9] 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 <zyn7...@gmail.com> Date: Wed, 26 Jun 2024 10:51:55 +0800 Subject: [PATCH 6/9] 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 <zyn7...@gmail.com> Date: Wed, 26 Jun 2024 10:54:02 +0800 Subject: [PATCH 7/9] 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 <zyn7...@gmail.com> Date: Wed, 26 Jun 2024 10:58:02 +0800 Subject: [PATCH 8/9] 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 <zyn7...@gmail.com> Date: Thu, 27 Jun 2024 19:41:31 +0800 Subject: [PATCH 9/9] 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@-1 {{candidate template ignored: could not match}} -// expected-note@-2 {{implicit deduction guide declared as 'template <int K> Bar(Foo<double, K>) -> Foo<double, K>'}} -// expected-note@-3 {{implicit deduction guide declared as 'template <int K> Bar(const double (&)[K]) -> Foo<double, K>'}} +// expected-note@-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@-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 {}; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits