https://github.com/zyn0217 updated https://github.com/llvm/llvm-project/pull/139066
>From a6ee1af04225063bab4d853611c7a57b1db37aa9 Mon Sep 17 00:00:00 2001 From: Younan Zhang <zyn7...@gmail.com> Date: Thu, 8 May 2025 19:42:51 +0800 Subject: [PATCH] [Clang] Do not eat SFINAE diagnostics for explicit template arguments --- clang/lib/Sema/SemaOverload.cpp | 19 ++++++++++++++++++- clang/test/AST/ByteCode/builtin-align-cxx.cpp | 3 ++- clang/test/AST/ByteCode/cxx20.cpp | 3 ++- .../basic.namespace/namespace.udecl/p12.cpp | 12 ++++++++---- clang/test/CXX/drs/cwg2xx.cpp | 4 ++++ clang/test/CXX/drs/cwg3xx.cpp | 2 ++ clang/test/CXX/expr/expr.const/p3-0x.cpp | 3 ++- clang/test/CXX/temp/temp.param/p8-cxx20.cpp | 3 ++- .../test/CXX/temp/temp.res/temp.local/p1.cpp | 6 ++++-- clang/test/Modules/cxx-templates.cpp | 2 ++ clang/test/SemaCXX/builtin-align-cxx.cpp | 3 ++- clang/test/SemaCXX/calling-conv-compat.cpp | 3 ++- .../constexpr-function-recovery-crash.cpp | 3 ++- clang/test/SemaCXX/cxx2a-template-lambdas.cpp | 6 ++++-- clang/test/SemaCXX/typo-correction.cpp | 3 ++- .../test/SemaTemplate/concepts-using-decl.cpp | 6 ++++-- .../test/SemaTemplate/overload-candidates.cpp | 10 ++++++---- .../SemaTemplate/temp_arg_nontype_cxx11.cpp | 5 +++-- 18 files changed, 71 insertions(+), 25 deletions(-) diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 5b224b6c08fef..9b7878434b9ad 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -749,8 +749,16 @@ clang::MakeDeductionFailureInfo(ASTContext &Context, break; case TemplateDeductionResult::Incomplete: + Result.Data = Info.Param.getOpaqueValue(); + break; case TemplateDeductionResult::InvalidExplicitArguments: Result.Data = Info.Param.getOpaqueValue(); + if (Info.hasSFINAEDiagnostic()) { + PartialDiagnosticAt *Diag = new (Result.Diagnostic) PartialDiagnosticAt( + SourceLocation(), PartialDiagnostic::NullDiagnostic()); + Info.takeSFINAEDiagnostic(*Diag); + Result.HasDiagnostic = true; + } break; case TemplateDeductionResult::DeducedMismatch: @@ -822,7 +830,6 @@ void DeductionFailureInfo::Destroy() { case TemplateDeductionResult::Incomplete: case TemplateDeductionResult::TooManyArguments: case TemplateDeductionResult::TooFewArguments: - case TemplateDeductionResult::InvalidExplicitArguments: case TemplateDeductionResult::CUDATargetMismatch: case TemplateDeductionResult::NonDependentConversionFailure: break; @@ -837,6 +844,7 @@ void DeductionFailureInfo::Destroy() { Data = nullptr; break; + case TemplateDeductionResult::InvalidExplicitArguments: case TemplateDeductionResult::SubstitutionFailure: // FIXME: Destroy the template argument list? Data = nullptr; @@ -12166,6 +12174,15 @@ static void DiagnoseBadDeduction(Sema &S, NamedDecl *Found, Decl *Templated, diag::note_ovl_candidate_explicit_arg_mismatch_unnamed) << (index + 1); } + + if (PartialDiagnosticAt *PDiag = DeductionFailure.getSFINAEDiagnostic()) { + unsigned DiagID = + S.getDiagnostics().getCustomDiagID(DiagnosticsEngine::Note, "%0"); + SmallString<128> SFINAEArgString; + PDiag->second.EmitToString(S.getDiagnostics(), SFINAEArgString); + S.Diag(Templated->getLocation(), DiagID) << SFINAEArgString; + } + MaybeEmitInheritedConstructorNote(S, Found); return; diff --git a/clang/test/AST/ByteCode/builtin-align-cxx.cpp b/clang/test/AST/ByteCode/builtin-align-cxx.cpp index a1edf307d6c47..973fd1b620525 100644 --- a/clang/test/AST/ByteCode/builtin-align-cxx.cpp +++ b/clang/test/AST/ByteCode/builtin-align-cxx.cpp @@ -4,7 +4,8 @@ // Check that we don't crash when using dependent types in __builtin_align: template <typename a, a b> -void *c(void *d) { // both-note{{candidate template ignored}} +void *c(void *d) { // both-note{{candidate template ignored}} \ +// both-note {{a non-type template parameter cannot have type 'struct x' before C++20}} return __builtin_align_down(d, b); } diff --git a/clang/test/AST/ByteCode/cxx20.cpp b/clang/test/AST/ByteCode/cxx20.cpp index 42e6ae33e92e4..1625f8eee8425 100644 --- a/clang/test/AST/ByteCode/cxx20.cpp +++ b/clang/test/AST/ByteCode/cxx20.cpp @@ -753,7 +753,8 @@ namespace FailingDestructor { } }; template<D d> - void f() {} // both-note {{invalid explicitly-specified argument}} + void f() {} // both-note {{invalid explicitly-specified argument}} \ + // both-note {{non-type template argument is not a constant expression}} void g() { f<D{0, false}>(); // both-error {{no matching function}} diff --git a/clang/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p12.cpp b/clang/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p12.cpp index f12e0083fb0c9..ee38418acfb32 100644 --- a/clang/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p12.cpp +++ b/clang/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p12.cpp @@ -113,21 +113,25 @@ namespace test3 { struct Derived1 : Base { using Base::foo; - template <int n> Opaque<2> foo() { return Opaque<2>(); } // expected-note {{invalid explicitly-specified argument for template parameter 'n'}} + template <int n> Opaque<2> foo() { return Opaque<2>(); } // expected-note {{invalid explicitly-specified argument for template parameter 'n'}} \ + // expected-note {{template argument for non-type template parameter must be an expression}} }; struct Derived2 : Base { - template <int n> Opaque<2> foo() { return Opaque<2>(); } // expected-note {{invalid explicitly-specified argument for template parameter 'n'}} + template <int n> Opaque<2> foo() { return Opaque<2>(); } // expected-note {{invalid explicitly-specified argument for template parameter 'n'}} \ + // expected-note {{template argument for non-type template parameter must be an expression}} using Base::foo; }; struct Derived3 : Base { using Base::foo; - template <class T> Opaque<3> foo() { return Opaque<3>(); } // expected-note {{invalid explicitly-specified argument for template parameter 'T'}} + template <class T> Opaque<3> foo() { return Opaque<3>(); } // expected-note {{invalid explicitly-specified argument for template parameter 'T'}} \ + // expected-note {{template argument for template type parameter must be a type}} }; struct Derived4 : Base { - template <class T> Opaque<3> foo() { return Opaque<3>(); } // expected-note {{invalid explicitly-specified argument for template parameter 'T'}} + template <class T> Opaque<3> foo() { return Opaque<3>(); } // expected-note {{invalid explicitly-specified argument for template parameter 'T'}} \ + // expected-note {{template argument for template type parameter must be a type}} using Base::foo; }; diff --git a/clang/test/CXX/drs/cwg2xx.cpp b/clang/test/CXX/drs/cwg2xx.cpp index b2ae8f88ead74..604a60c9fa0c9 100644 --- a/clang/test/CXX/drs/cwg2xx.cpp +++ b/clang/test/CXX/drs/cwg2xx.cpp @@ -650,14 +650,17 @@ namespace cwg241 { // cwg241: 9 C::f<3>(b); // expected-error@-1 {{no matching function for call to 'f'}} // expected-note@#cwg241-C-f {{candidate template ignored: invalid explicitly-specified argument for template parameter 'T'}} + // expected-note@#cwg241-C-f {{template argument for template type parameter must be a type}} C::g<3>(b); // expected-error@-1 {{no matching function for call to 'g'}} // expected-note@#cwg241-C-g {{candidate template ignored: invalid explicitly-specified argument for template parameter 'T'}} + // expected-note@#cwg241-C-g {{template argument for template type parameter must be a type}} using C::f; using C::g; f<3>(b); // expected-error@-1 {{no matching function for call to 'f'}} // expected-note@#cwg241-C-f {{candidate template ignored: invalid explicitly-specified argument for template parameter 'T'}} + // expected-note@#cwg241-C-f {{template argument for template type parameter must be a type}} // expected-note@#cwg241-A-f {{candidate function template not viable: requires 0 arguments, but 1 was provided}} g<3>(b); } @@ -952,6 +955,7 @@ namespace cwg258 { // cwg258: 2.8 int &x = b.g<int>(0); // expected-error@-1 {{no matching member function for call to 'g'}} // expected-note@#cwg258-B-g {{candidate template ignored: invalid explicitly-specified argument for 1st template parameter}} + // expected-note@#cwg258-B-g {{template argument for non-type template parameter must be an expression}} int &y = b.h(); float &z = const_cast<const B&>(b).h(); diff --git a/clang/test/CXX/drs/cwg3xx.cpp b/clang/test/CXX/drs/cwg3xx.cpp index 8b035cf6f2370..b1b8d20187dcb 100644 --- a/clang/test/CXX/drs/cwg3xx.cpp +++ b/clang/test/CXX/drs/cwg3xx.cpp @@ -985,7 +985,9 @@ namespace cwg354 { // cwg354: 3.1 c++11 int b1 = both<(int*)0>(); // cxx98-error@-1 {{no matching function for call to 'both'}} // cxx98-note@#cwg354-both-int-ptr {{candidate template ignored: invalid explicitly-specified argument for 1st template parameter}} + // cxx98-note@#cwg354-both-int-ptr {{non-type template argument does not refer to any declaration}} // cxx98-note@#cwg354-both-int {{candidate template ignored: invalid explicitly-specified argument for 1st template parameter}} + // cxx98-note@#cwg354-both-int {{non-type template argument of type 'int *' must have an integral or enumeration type}} template<int S::*> struct ptr_mem {}; // #cwg354-ptr_mem ptr_mem<0> m0; // #cwg354-m0 diff --git a/clang/test/CXX/expr/expr.const/p3-0x.cpp b/clang/test/CXX/expr/expr.const/p3-0x.cpp index 3eedef3cf7712..c7dafc59599dd 100644 --- a/clang/test/CXX/expr/expr.const/p3-0x.cpp +++ b/clang/test/CXX/expr/expr.const/p3-0x.cpp @@ -107,7 +107,8 @@ void c() { break; } } -template <bool B> int f() { return B; } // expected-note {{candidate template ignored: invalid explicitly-specified argument for template parameter 'B'}} +template <bool B> int f() { return B; } // expected-note {{candidate template ignored: invalid explicitly-specified argument for template parameter 'B'}} \ +// expected-note {{conversion from 'int (S::*)() const' to 'bool' is not allowed in a converted constant expression}} template int f<&S::operator int>(); // expected-error {{does not refer to a function template}} template int f<(bool)&S::operator int>(); diff --git a/clang/test/CXX/temp/temp.param/p8-cxx20.cpp b/clang/test/CXX/temp/temp.param/p8-cxx20.cpp index a3478c0669661..953b613eeef4a 100644 --- a/clang/test/CXX/temp/temp.param/p8-cxx20.cpp +++ b/clang/test/CXX/temp/temp.param/p8-cxx20.cpp @@ -40,7 +40,8 @@ namespace ConstDestruction { }; template<D d> - void f() {} // expected-note 2{{invalid explicitly-specified argument}} + void f() {} // expected-note 2{{invalid explicitly-specified argument}} \ + // expected-note 2{{non-type template argument is not a constant expression}} void g() { f<D{0, true}>(); diff --git a/clang/test/CXX/temp/temp.res/temp.local/p1.cpp b/clang/test/CXX/temp/temp.res/temp.local/p1.cpp index faa85cb5fce30..8a49fc39e2d2b 100644 --- a/clang/test/CXX/temp/temp.res/temp.local/p1.cpp +++ b/clang/test/CXX/temp/temp.res/temp.local/p1.cpp @@ -10,9 +10,11 @@ template<typename> char id; template<typename> struct TempType {}; template<template<typename> class> struct TempTemp {}; -template<typename> void use(int&); // expected-note {{invalid explicitly-specified argument}} expected-note {{no known conversion}} +template<typename> void use(int&); // expected-note {{invalid explicitly-specified argument}} expected-note {{no known conversion}} \ +// expected-note {{use of class template 'B::template C' requires template arguments}} template<template<typename> class> void use(float&); // expected-note 2{{no known conversion}} -template<int> void use(char&); // expected-note 2{{invalid explicitly-specified argument}} +template<int> void use(char&); // expected-note 2{{invalid explicitly-specified argument}} \ +// expected-note 2{{template argument for non-type template parameter must be an expression}} template<typename T> struct A { template<typename> struct C {}; diff --git a/clang/test/Modules/cxx-templates.cpp b/clang/test/Modules/cxx-templates.cpp index f587af4beb7ce..dce93f866b15c 100644 --- a/clang/test/Modules/cxx-templates.cpp +++ b/clang/test/Modules/cxx-templates.cpp @@ -43,11 +43,13 @@ void g() { template_param_kinds_2<Tmpl_T_C>(); // expected-error {{no matching function for call}} // expected-note@Inputs/cxx-templates-a.h:11 {{candidate}} + // expected-note@Inputs/cxx-templates-a.h:11 {{too many template arguments for class template 'Tmpl_T_C'}} // expected-note@Inputs/cxx-templates-b.h:11 {{candidate}} template_param_kinds_2<Tmpl_T_I_I>(); // expected-error {{ambiguous}} // expected-note@Inputs/cxx-templates-a.h:11 {{candidate}} // expected-note@Inputs/cxx-templates-b.h:11 {{candidate}} + // expected-note@Inputs/cxx-templates-b.h:11 {{non-type parameter of template template parameter cannot be narrowed from type 'int' to 'char'}} template_param_kinds_3<Tmpl_T_T_A>(); template_param_kinds_3<Tmpl_T_T_B>(); diff --git a/clang/test/SemaCXX/builtin-align-cxx.cpp b/clang/test/SemaCXX/builtin-align-cxx.cpp index d18bc2bf66551..a680ac2aaa763 100644 --- a/clang/test/SemaCXX/builtin-align-cxx.cpp +++ b/clang/test/SemaCXX/builtin-align-cxx.cpp @@ -3,7 +3,8 @@ // Check that we don't crash when using dependent types in __builtin_align: template <typename a, a b> -void *c(void *d) { // expected-note{{candidate template ignored}} +void *c(void *d) { // expected-note{{candidate template ignored}} \ +// expected-note {{a non-type template parameter cannot have type 'struct x' before C++20}} return __builtin_align_down(d, b); } diff --git a/clang/test/SemaCXX/calling-conv-compat.cpp b/clang/test/SemaCXX/calling-conv-compat.cpp index 9bb448ffef225..8e67528717c5b 100644 --- a/clang/test/SemaCXX/calling-conv-compat.cpp +++ b/clang/test/SemaCXX/calling-conv-compat.cpp @@ -425,6 +425,7 @@ namespace D50526 { void h() { g<void, h>(); } #if !_M_X64 // expected-error@-2 {{no matching function for call to}} - // expected-note@-4 {{invalid explicitly-specified argument}} + // expected-note@-4 {{invalid explicitly-specified argument}} \ + // expected-note@-4 {{non-type template argument of type 'void ()' cannot be converted to a value of type 'void (*)() __attribute__((stdcall))'}} #endif } diff --git a/clang/test/SemaCXX/constexpr-function-recovery-crash.cpp b/clang/test/SemaCXX/constexpr-function-recovery-crash.cpp index 90ee7892b2fc2..086bfa15fe0ea 100644 --- a/clang/test/SemaCXX/constexpr-function-recovery-crash.cpp +++ b/clang/test/SemaCXX/constexpr-function-recovery-crash.cpp @@ -60,7 +60,8 @@ constexpr void test8() { throw "bad"; } -template<int x> constexpr int f(int y) { // expected-note {{candidate template ignored}} +template<int x> constexpr int f(int y) { // expected-note {{candidate template ignored}} \ + // expected-note {{non-type template argument is not a constant expression}} return x * y; } constexpr int test9(int x) { diff --git a/clang/test/SemaCXX/cxx2a-template-lambdas.cpp b/clang/test/SemaCXX/cxx2a-template-lambdas.cpp index 00ba291fbd198..413bf7cd09667 100644 --- a/clang/test/SemaCXX/cxx2a-template-lambdas.cpp +++ b/clang/test/SemaCXX/cxx2a-template-lambdas.cpp @@ -1,8 +1,8 @@ // RUN: %clang_cc1 -std=c++03 -verify -Dstatic_assert=_Static_assert -Wno-c++11-extensions -Wno-c++14-extensions -Wno-c++17-extensions -Wno-c++20-extensions %s // RUN: %clang_cc1 -std=c++11 -verify=expected,cxx11,cxx11-cxx14 -Wno-c++20-extensions -Wno-c++17-extensions -Wno-c++14-extensions %s // RUN: %clang_cc1 -std=c++14 -verify=expected,cxx11-cxx14,cxx14 -Wno-c++20-extensions -Wno-c++17-extensions %s -// RUN: %clang_cc1 -std=c++17 -verify -Wno-c++20-extensions %s -// RUN: %clang_cc1 -std=c++20 -verify %s +// RUN: %clang_cc1 -std=c++17 -verify=expected,cxx17,cxx17-cxx20 -Wno-c++20-extensions %s +// RUN: %clang_cc1 -std=c++20 -verify=expected,cxx20,cxx17-cxx20 %s template<typename, typename> inline const bool is_same = false; @@ -47,6 +47,8 @@ constexpr T outer() { return []<T x>() { return x; }.template operator()<123>(); // expected-error {{no matching member function}} \ expected-note {{candidate template ignored}} \ cxx11-note {{non-literal type '<dependent type>' cannot be used in a constant expression}} \ + cxx11-cxx14-note {{non-type template argument does not refer to any declaration}} \ + cxx17-cxx20-note {{value of type 'int' is not implicitly convertible to 'int *'}} \ cxx14-note {{non-literal type}} } static_assert(outer<int>() == 123); // cxx11-cxx14-error {{not an integral constant expression}} cxx11-cxx14-note {{in call}} diff --git a/clang/test/SemaCXX/typo-correction.cpp b/clang/test/SemaCXX/typo-correction.cpp index 45f42c4260358..c25d01eade890 100644 --- a/clang/test/SemaCXX/typo-correction.cpp +++ b/clang/test/SemaCXX/typo-correction.cpp @@ -614,7 +614,8 @@ int bar() { namespace testIncludeTypeInTemplateArgument { template <typename T, typename U> -void foo(T t = {}, U = {}); // expected-note {{candidate template ignored}} +void foo(T t = {}, U = {}); // expected-note {{candidate template ignored}} \ + // expected-note {{template argument for template type parameter must be a type}} class AddObservation {}; // expected-note {{declared here}} int bar1() { diff --git a/clang/test/SemaTemplate/concepts-using-decl.cpp b/clang/test/SemaTemplate/concepts-using-decl.cpp index fca69dea5c88f..cad160fd585c0 100644 --- a/clang/test/SemaTemplate/concepts-using-decl.cpp +++ b/clang/test/SemaTemplate/concepts-using-decl.cpp @@ -165,8 +165,10 @@ struct base { struct bar : public base { using base::foo; - template <int N> - int foo() { return 2; }; // expected-note {{candidate template ignored: substitution failure: too many template arguments for function template 'foo'}} + template <int N> + int foo() { return 2; }; + // expected-note@-1 {{candidate template ignored: invalid explicitly-specified argument for template parameter 'N'}} \ + // expected-note@-1 {{too many template arguments for function template 'foo'}} }; void func() { diff --git a/clang/test/SemaTemplate/overload-candidates.cpp b/clang/test/SemaTemplate/overload-candidates.cpp index de998d74f9af6..25f0492a71729 100644 --- a/clang/test/SemaTemplate/overload-candidates.cpp +++ b/clang/test/SemaTemplate/overload-candidates.cpp @@ -16,10 +16,12 @@ void test_dyn_cast(int* ptr) { (void)dyn_cast(ptr); // expected-error{{no matching function for call to 'dyn_cast'}} } -template<int I, typename T> - void get(const T&); // expected-note{{candidate template ignored: invalid explicitly-specified argument for template parameter 'I'}} -template<template<class T> class, typename T> - void get(const T&); // expected-note{{candidate template ignored: invalid explicitly-specified argument for 1st template parameter}} +template<int I, typename T> + void get(const T&); // expected-note{{candidate template ignored: invalid explicitly-specified argument for template parameter 'I'}} \ + // expected-note {{template argument for non-type template parameter must be an expression}} +template<template<class T> class, typename T> + void get(const T&); // expected-note{{candidate template ignored: invalid explicitly-specified argument for 1st template parameter}} \ + // expected-note {{template argument for template template parameter must be a class template}} void test_get(void *ptr) { get<int>(ptr); // expected-error{{no matching function for call to 'get'}} diff --git a/clang/test/SemaTemplate/temp_arg_nontype_cxx11.cpp b/clang/test/SemaTemplate/temp_arg_nontype_cxx11.cpp index 5752cbac0291d..44bc5b7642f76 100644 --- a/clang/test/SemaTemplate/temp_arg_nontype_cxx11.cpp +++ b/clang/test/SemaTemplate/temp_arg_nontype_cxx11.cpp @@ -42,8 +42,9 @@ template <int a, unsigned b, int c> void TempFunc() {} void Useage() { - //expected-error@+2 {{no matching function}} - //expected-note@-4 {{candidate template ignored: invalid explicitly-specified argument for template parameter 'b'}} + //expected-error@+3 {{no matching function}} + //expected-note@-4 {{candidate template ignored: invalid explicitly-specified argument for template parameter 'b'}} \ + //expected-note@-4 {{non-type template argument evaluates to -1, which cannot be narrowed to type 'unsigned int'}} TempFunc<1, -1, 1>(); } } _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits