https://github.com/AZero13 created https://github.com/llvm/llvm-project/pull/207626
This patch addresses a regression in C++17 relaxed template template parameter matching (P0522 / CWG2398). When partial ordering template template parameters, Clang attempts to match synthesized arguments from the parameter template against the argument template. When dealing with non-type template parameters, standard function deduction rules require strictly matching the parameter's type against the argument's type. If the argument template has a dependent non-type template parameter (e.g., `template<typename T, T v>`) and the parameter template expects a non-dependent type (e.g., `template<typename U, int v>`), Clang would match `T` against `int` and incorrectly deduce `T = int`. This spurious deduction conflicts with the prior deduction of `T = U` from the type parameter, resulting in a premature substitution failure (`conflicting deduction 'U' against 'int' for parameter T`). This patch fixes this by extending the `TDF_SkipNonDependent` relaxation check during template template partial ordering. By skipping deduction when *either* the parameter or argument type is non-dependent, we prevent this spurious conflict and allow `T` to remain deduced as `U`. The final validity of the substituted value is then correctly deferred to SFINAE evaluation in `CheckTemplateArgumentList`. Fixes #207395 >From 9e28a5c76baecc8bce3ac79ac8dc4b51ff255af8 Mon Sep 17 00:00:00 2001 From: AZero13 <[email protected]> Date: Sun, 5 Jul 2026 20:31:01 -0400 Subject: [PATCH] [clang] Fix template template parameter deduction for dependent non-type template parameters (CWG2398) This patch addresses a regression in C++17 relaxed template template parameter matching (P0522 / CWG2398), resolving issue #207395. When partial ordering template template parameters, Clang attempts to match synthesized arguments from the parameter template against the argument template. When dealing with non-type template parameters, standard function deduction rules require strictly matching the parameter's type against the argument's type. If the argument template has a dependent non-type template parameter (e.g., `template<typename T, T v>`) and the parameter template expects a non-dependent type (e.g., `template<typename U, int v>`), Clang would match `T` against `int` and incorrectly deduce `T = int`. This spurious deduction conflicts with the prior deduction of `T = U` from the type parameter, resulting in a premature substitution failure (`conflicting deduction 'U' against 'int' for parameter T`). This patch fixes this by extending the `TDF_SkipNonDependent` relaxation check during template template partial ordering. By skipping deduction when *either* the parameter or argument type is non-dependent, we prevent this spurious conflict and allow `T` to remain deduced as `U`. The final validity of the substituted value is then correctly deferred to SFINAE evaluation in `CheckTemplateArgumentList`. Fixes #207395 --- clang/lib/Sema/SemaTemplateDeduction.cpp | 14 ++++++++++++-- .../test/SemaTemplate/temp_arg_template_p0522.cpp | 10 ++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index d93b528facbcc..91f282e487179 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -1833,10 +1833,20 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( } } + // In the context of partial ordering (where TDF_SkipNonDependent is set), + // we may be matching a dependent parameter type (like `T` from `template<typename T, T V>`) + // against a non-dependent argument type (like `int` from `template<typename U, int>`). + // If we try to deduce `T` from `int`, we'll incorrectly deduce `T = int`, which + // conflicts with the deduction of `T = U` from the type parameter. By skipping + // deduction when either type is non-dependent, we prevent this spurious conflict + // and allow CheckTemplateArgumentList to perform the final validity check. + if (TDF & TDF_SkipNonDependent) { + if (!P->isDependentType() || !A->isDependentType()) + return TemplateDeductionResult::Success; + } + // If the parameter type is not dependent, there is nothing to deduce. if (!P->isDependentType()) { - if (TDF & TDF_SkipNonDependent) - return TemplateDeductionResult::Success; if ((TDF & TDF_IgnoreQualifiers) ? S.Context.hasSameUnqualifiedType(P, A) : S.Context.hasSameType(P, A)) return TemplateDeductionResult::Success; diff --git a/clang/test/SemaTemplate/temp_arg_template_p0522.cpp b/clang/test/SemaTemplate/temp_arg_template_p0522.cpp index bde811c3bf685..fe250e2ceeb69 100644 --- a/clang/test/SemaTemplate/temp_arg_template_p0522.cpp +++ b/clang/test/SemaTemplate/temp_arg_template_p0522.cpp @@ -175,3 +175,13 @@ namespace GH181166 { template <class ...Ts> struct B {}; using T = decltype(f<B>()); } // namespace GH181166 + +namespace CWG2398_DependentNonType { + template<typename T, T V> struct my_constant {}; + template <template<typename U, int> class Constant> void f(Constant<int, 1>); + using go = decltype(f(my_constant<int, 1>())); + + template<typename T, int V> struct my_constant2 {}; + template <template<typename U, U> class Constant> void f2(Constant<int, 1>); + using go2 = decltype(f2(my_constant2<int, 1>())); +} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
