https://github.com/wx257osn2 updated https://github.com/llvm/llvm-project/pull/196791
>From 437a92eb22f392fa6b724dcdfcb2e4e8cf5922b3 Mon Sep 17 00:00:00 2001 From: "A. Jiang" <[email protected]> Date: Sun, 10 May 2026 18:12:15 +0900 Subject: [PATCH 01/15] add test https://github.com/llvm/llvm-project/issues/175831#issuecomment-3753235470 --- clang/test/SemaTemplate/concepts.cpp | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/clang/test/SemaTemplate/concepts.cpp b/clang/test/SemaTemplate/concepts.cpp index b427e6a4d2fa5..4275f63989607 100644 --- a/clang/test/SemaTemplate/concepts.cpp +++ b/clang/test/SemaTemplate/concepts.cpp @@ -1851,7 +1851,6 @@ namespace GH191016 { void test(){ S<int> s; } } - namespace GH188640 { namespace Ex1 { @@ -2002,3 +2001,21 @@ namespace GH196375 { static_assert(f<4>()); // expected-error@-1 {{no matching function for call to 'f'}} } // namespace GHGH196375 + +namespace GH175831 { + +template<class> +struct reference {}; +template<class Q> +consteval Q get_spec(reference<Q>) { return {}; } + +template<class T> +concept repr_impl = sizeof(T) > 0; +template<class, auto V> +concept representation_of = repr_impl<decltype(V)>; +template<auto V, representation_of<get_spec(V)>> +struct quantity {}; + +auto x = quantity<reference<int>{}, int>{}; + +} // namespace GH175831 >From 744696100cb96cc5b7c4cddde7cb99511778a447 Mon Sep 17 00:00:00 2001 From: I <[email protected]> Date: Sun, 10 May 2026 18:21:56 +0900 Subject: [PATCH 02/15] stop replacement on unevaluated context --- clang/lib/Sema/TreeTransform.h | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 70cdc47e42d5d..34b0ac9e86be5 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -16727,13 +16727,23 @@ ExprResult TreeTransform<Derived>::TransformSubstNonTypeTemplateParmExpr( // specific annotations, such as implicit casts, are discarded. Calling the // corresponding sema action is necessary to recover those. Otherwise, // equivalency of the result would be lost. + // + // In unevaluated contexts (e.g. inside decltype), CheckTemplateArgument + // forces constant evaluation that is inappropriate and may fail for + // valid expressions (e.g. function calls with by-value class parameters). + // Since we only need the type in such contexts, we can tolerate the + // failure and proceed with the transformed replacement as-is. TemplateArgument SugaredConverted, CanonicalConverted; - Replacement = SemaRef.CheckTemplateArgument( + ExprResult Checked = SemaRef.CheckTemplateArgument( Param, ParamType, Replacement.get(), SugaredConverted, CanonicalConverted, /*StrictCheck=*/false, Sema::CTAK_Specified); - if (Replacement.isInvalid()) - return true; + if (Checked.isInvalid()) { + if (!SemaRef.isUnevaluatedContext()) + return true; + } else { + Replacement = Checked; + } } else { // Otherwise, the same expression would have been produced. Replacement = E->getReplacement(); >From 773d1db889a91bf9c76ba4077e636be3a8bd7c95 Mon Sep 17 00:00:00 2001 From: I <[email protected]> Date: Sun, 10 May 2026 18:47:44 +0900 Subject: [PATCH 03/15] add release note --- clang/docs/ReleaseNotes.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 9e4a47a5b18fc..a654a94adceb4 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -655,6 +655,7 @@ Bug Fixes in This Version - Fixed a crash when ``#embed`` is used with C++ modules (#GH195350) - Fixed an issue where ``__typeof_unqual`` and ``__typeof_unqual__`` were rejected as a declaration specifier in block scope in C++. - Fixed crash when checking for overflow for unary operator that can't overflow (#GH170072) +- Fixed a regression where calling a function that takes a class-type parameter by value inside ``decltype`` of a concept could be incorrectly rejected when used as a non-type template argument. (#GH175831) Bug Fixes to Compiler Builtins ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ >From 1ffdb2bab511789c86fb1250a8afed0bfc402276 Mon Sep 17 00:00:00 2001 From: I <[email protected]> Date: Mon, 11 May 2026 20:49:25 +0900 Subject: [PATCH 04/15] add test --- clang/test/SemaTemplate/concepts.cpp | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/clang/test/SemaTemplate/concepts.cpp b/clang/test/SemaTemplate/concepts.cpp index 4275f63989607..794229cf0b1db 100644 --- a/clang/test/SemaTemplate/concepts.cpp +++ b/clang/test/SemaTemplate/concepts.cpp @@ -2004,6 +2004,8 @@ namespace GH196375 { namespace GH175831 { +namespace ShuoldResolve { + template<class> struct reference {}; template<class Q> @@ -2018,4 +2020,28 @@ struct quantity {}; auto x = quantity<reference<int>{}, int>{}; +} // namespace ShouldResolve + +namespace CannotResolve { + +template<class> +struct reference {}; +template<class Q> +consteval auto get_spec(reference<Q>) { return Q{}; } + +template<class T> +concept repr_impl = sizeof(T) > sizeof(char); +template<class, auto V> +concept representation_of = repr_impl<decltype(V)>; +template<auto V, representation_of<get_spec(V)>> +struct quantity {}; + +auto x = quantity<reference<char>{}, char>{}; +// expected-error@-1 {{constraints not satisfied for class template 'quantity' [with V = reference<char>{}, $1 = char]}} +// expected-note@-5 {{because 'representation_of<char, get_spec(reference<char>{})>' evaluated to false}} +// expected-note-re@-7 {{because 'decltype({{.*}})' (aka 'char') does not satisfy 'repr_impl'}} +// expected-note@-10 {{because 'sizeof(char) > sizeof(char)' (1 > 1) evaluated to false}} + +} // namespace CannotResolve + } // namespace GH175831 >From 27a39f00495b8ffa07bc1797df7ac4aa8a760de2 Mon Sep 17 00:00:00 2001 From: I <[email protected]> Date: Mon, 11 May 2026 20:57:21 +0900 Subject: [PATCH 05/15] check evaluated context or not before calling CheckTemplateArgument --- clang/lib/Sema/TreeTransform.h | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 34b0ac9e86be5..8c661ce27fc4c 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -16727,22 +16727,14 @@ ExprResult TreeTransform<Derived>::TransformSubstNonTypeTemplateParmExpr( // specific annotations, such as implicit casts, are discarded. Calling the // corresponding sema action is necessary to recover those. Otherwise, // equivalency of the result would be lost. - // - // In unevaluated contexts (e.g. inside decltype), CheckTemplateArgument - // forces constant evaluation that is inappropriate and may fail for - // valid expressions (e.g. function calls with by-value class parameters). - // Since we only need the type in such contexts, we can tolerate the - // failure and proceed with the transformed replacement as-is. - TemplateArgument SugaredConverted, CanonicalConverted; - ExprResult Checked = SemaRef.CheckTemplateArgument( - Param, ParamType, Replacement.get(), SugaredConverted, - CanonicalConverted, - /*StrictCheck=*/false, Sema::CTAK_Specified); - if (Checked.isInvalid()) { - if (!SemaRef.isUnevaluatedContext()) + if (!SemaRef.isUnevaluatedContext()) { + TemplateArgument SugaredConverted, CanonicalConverted; + Replacement = SemaRef.CheckTemplateArgument( + Param, ParamType, Replacement.get(), SugaredConverted, + CanonicalConverted, + /*StrictCheck=*/false, Sema::CTAK_Specified); + if (Replacement.isInvalid()) return true; - } else { - Replacement = Checked; } } else { // Otherwise, the same expression would have been produced. >From e216ae235080d9d0ae1e2374774d913faf8ab8ff Mon Sep 17 00:00:00 2001 From: I <[email protected]> Date: Wed, 3 Jun 2026 19:39:36 +0900 Subject: [PATCH 06/15] Revert "check evaluated context or not before calling CheckTemplateArgument" This reverts commit 27a39f00495b8ffa07bc1797df7ac4aa8a760de2. --- clang/lib/Sema/TreeTransform.h | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 8c661ce27fc4c..34b0ac9e86be5 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -16727,14 +16727,22 @@ ExprResult TreeTransform<Derived>::TransformSubstNonTypeTemplateParmExpr( // specific annotations, such as implicit casts, are discarded. Calling the // corresponding sema action is necessary to recover those. Otherwise, // equivalency of the result would be lost. - if (!SemaRef.isUnevaluatedContext()) { - TemplateArgument SugaredConverted, CanonicalConverted; - Replacement = SemaRef.CheckTemplateArgument( - Param, ParamType, Replacement.get(), SugaredConverted, - CanonicalConverted, - /*StrictCheck=*/false, Sema::CTAK_Specified); - if (Replacement.isInvalid()) + // + // In unevaluated contexts (e.g. inside decltype), CheckTemplateArgument + // forces constant evaluation that is inappropriate and may fail for + // valid expressions (e.g. function calls with by-value class parameters). + // Since we only need the type in such contexts, we can tolerate the + // failure and proceed with the transformed replacement as-is. + TemplateArgument SugaredConverted, CanonicalConverted; + ExprResult Checked = SemaRef.CheckTemplateArgument( + Param, ParamType, Replacement.get(), SugaredConverted, + CanonicalConverted, + /*StrictCheck=*/false, Sema::CTAK_Specified); + if (Checked.isInvalid()) { + if (!SemaRef.isUnevaluatedContext()) return true; + } else { + Replacement = Checked; } } else { // Otherwise, the same expression would have been produced. >From 4fe38a26d7247761331aefdb29f46525fa22d239 Mon Sep 17 00:00:00 2001 From: I <[email protected]> Date: Wed, 3 Jun 2026 19:39:42 +0900 Subject: [PATCH 07/15] Revert "stop replacement on unevaluated context" This reverts commit 744696100cb96cc5b7c4cddde7cb99511778a447. --- clang/lib/Sema/TreeTransform.h | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 34b0ac9e86be5..70cdc47e42d5d 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -16727,23 +16727,13 @@ ExprResult TreeTransform<Derived>::TransformSubstNonTypeTemplateParmExpr( // specific annotations, such as implicit casts, are discarded. Calling the // corresponding sema action is necessary to recover those. Otherwise, // equivalency of the result would be lost. - // - // In unevaluated contexts (e.g. inside decltype), CheckTemplateArgument - // forces constant evaluation that is inappropriate and may fail for - // valid expressions (e.g. function calls with by-value class parameters). - // Since we only need the type in such contexts, we can tolerate the - // failure and proceed with the transformed replacement as-is. TemplateArgument SugaredConverted, CanonicalConverted; - ExprResult Checked = SemaRef.CheckTemplateArgument( + Replacement = SemaRef.CheckTemplateArgument( Param, ParamType, Replacement.get(), SugaredConverted, CanonicalConverted, /*StrictCheck=*/false, Sema::CTAK_Specified); - if (Checked.isInvalid()) { - if (!SemaRef.isUnevaluatedContext()) - return true; - } else { - Replacement = Checked; - } + if (Replacement.isInvalid()) + return true; } else { // Otherwise, the same expression would have been produced. Replacement = E->getReplacement(); >From 76664d4ecc4c13050b4ee6c53820e814a208767f Mon Sep 17 00:00:00 2001 From: I <[email protected]> Date: Wed, 3 Jun 2026 19:45:54 +0900 Subject: [PATCH 08/15] fix typo --- clang/test/SemaTemplate/concepts.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/test/SemaTemplate/concepts.cpp b/clang/test/SemaTemplate/concepts.cpp index 794229cf0b1db..f735bfc1251c2 100644 --- a/clang/test/SemaTemplate/concepts.cpp +++ b/clang/test/SemaTemplate/concepts.cpp @@ -2004,7 +2004,7 @@ namespace GH196375 { namespace GH175831 { -namespace ShuoldResolve { +namespace ShouldResolve { template<class> struct reference {}; >From 512b3cc3d63f7e75d51a459d247ae458c9b42d9c Mon Sep 17 00:00:00 2001 From: I <[email protected]> Date: Wed, 3 Jun 2026 19:42:55 +0900 Subject: [PATCH 09/15] add SkipConstantEvaluation option for CheckTemplateArgument --- clang/include/clang/Sema/Sema.h | 11 ++++++++++- clang/lib/Sema/SemaTemplate.cpp | 8 +++++--- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index b8d760e7e0975..d3eef97811cbd 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -12198,12 +12198,21 @@ class Sema final : public SemaBase { /// If an error occurred, it returns ExprError(); otherwise, it /// returns the converted template argument. \p ParamType is the /// type of the non-type template parameter after it has been instantiated. + /// + /// If \p SkipConstantEvaluation is true, the argument is converted to the + /// parameter type, but is not required to be constant-evaluable, similarly + /// to a value-dependent argument. This is used when only the converted form + /// of the argument is needed, e.g. when re-checking the replacement of a + /// SubstNonTypeTemplateParmExpr in an unevaluated context, where constant + /// evaluation may fail for otherwise valid arguments because the entities + /// they refer to are not odr-used. ExprResult CheckTemplateArgument(NamedDecl *Param, QualType InstantiatedParamType, Expr *Arg, TemplateArgument &SugaredConverted, TemplateArgument &CanonicalConverted, bool StrictCheck, - CheckTemplateArgumentKind CTAK); + CheckTemplateArgumentKind CTAK, + bool SkipConstantEvaluation = false); /// Check a template argument against its corresponding /// template template parameter. diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 8c94a1ad39208..9c53d1501fea1 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -7140,7 +7140,8 @@ ExprResult Sema::CheckTemplateArgument(NamedDecl *Param, QualType ParamType, TemplateArgument &SugaredConverted, TemplateArgument &CanonicalConverted, bool StrictCheck, - CheckTemplateArgumentKind CTAK) { + CheckTemplateArgumentKind CTAK, + bool SkipConstantEvaluation) { SourceLocation StartLoc = Arg->getBeginLoc(); auto *ArgPE = dyn_cast<PackExpansionExpr>(Arg); Expr *DeductionArg = ArgPE ? ArgPE->getPattern() : Arg; @@ -7344,8 +7345,9 @@ ExprResult Sema::CheckTemplateArgument(NamedDecl *Param, QualType ParamType, } // For a value-dependent argument, CheckConvertedConstantExpression is - // permitted (and expected) to be unable to determine a value. - if (ArgResult.get()->isValueDependent()) { + // permitted (and expected) to be unable to determine a value. Treat the + // argument the same way when the caller does not need the value. + if (ArgResult.get()->isValueDependent() || SkipConstantEvaluation) { setDeductionArg(ArgResult.get()); SugaredConverted = TemplateArgument(Arg, /*IsCanonical=*/false); CanonicalConverted = >From bf8a90e40c66b1100f6f19a846ef82eb6ffbc390 Mon Sep 17 00:00:00 2001 From: I <[email protected]> Date: Wed, 3 Jun 2026 19:43:20 +0900 Subject: [PATCH 10/15] skip constant evaluation if unevaluated context --- clang/lib/Sema/TreeTransform.h | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 70cdc47e42d5d..c3e3bdcad14fe 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -16727,11 +16727,19 @@ ExprResult TreeTransform<Derived>::TransformSubstNonTypeTemplateParmExpr( // specific annotations, such as implicit casts, are discarded. Calling the // corresponding sema action is necessary to recover those. Otherwise, // equivalency of the result would be lost. + // + // In an unevaluated context, skip the constant evaluation of the + // replacement: only its converted form matters there, and the evaluation + // can spuriously fail for otherwise valid replacements, because the + // entities they refer to are not odr-used in such a context (e.g. the + // implicit copy of a function argument of class type cannot be constant + // folded when the special members were never instantiated). TemplateArgument SugaredConverted, CanonicalConverted; Replacement = SemaRef.CheckTemplateArgument( Param, ParamType, Replacement.get(), SugaredConverted, CanonicalConverted, - /*StrictCheck=*/false, Sema::CTAK_Specified); + /*StrictCheck=*/false, Sema::CTAK_Specified, + /*SkipConstantEvaluation=*/SemaRef.isUnevaluatedContext()); if (Replacement.isInvalid()) return true; } else { >From e10169fae91325c593ce09e82568d3f3a80114f9 Mon Sep 17 00:00:00 2001 From: Matheus Izvekov <[email protected]> Date: Thu, 4 Jun 2026 10:18:09 +0900 Subject: [PATCH 11/15] add test --- clang/test/SemaTemplate/concepts.cpp | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/clang/test/SemaTemplate/concepts.cpp b/clang/test/SemaTemplate/concepts.cpp index f735bfc1251c2..6f7f00bf12e61 100644 --- a/clang/test/SemaTemplate/concepts.cpp +++ b/clang/test/SemaTemplate/concepts.cpp @@ -1,5 +1,5 @@ -// RUN: %clang_cc1 -std=c++20 -ferror-limit 0 -verify=expected,cxx20 %s -// RUN: %clang_cc1 -std=c++2c -ferror-limit 0 -verify=expected %s +// RUN: %clang_cc1 -std=c++20 -ferror-limit 0 -fexceptions -fcxx-exceptions -verify=expected,cxx20 %s +// RUN: %clang_cc1 -std=c++2c -ferror-limit 0 -fexceptions -fcxx-exceptions -verify=expected %s namespace PR47043 { template<typename T> concept True = true; @@ -2022,7 +2022,7 @@ auto x = quantity<reference<int>{}, int>{}; } // namespace ShouldResolve -namespace CannotResolve { +namespace CannotResolve0 { template<class> struct reference {}; @@ -2042,6 +2042,25 @@ auto x = quantity<reference<char>{}, char>{}; // expected-note-re@-7 {{because 'decltype({{.*}})' (aka 'char') does not satisfy 'repr_impl'}} // expected-note@-10 {{because 'sizeof(char) > sizeof(char)' (1 > 1) evaluated to false}} -} // namespace CannotResolve +} // namespace CannotResolve0 + +namespace CannotResolve1 { + +template<class> +struct reference {}; +template<class Q> +consteval Q get_spec(reference<Q>) { throw; } + +template<class T> +concept repr_impl = sizeof(T) > 0; +template<class, auto V> +concept representation_of = repr_impl<decltype(V)>; +template<auto V, representation_of<get_spec(V)>> +struct quantity {}; + +auto x = quantity<reference<int>{}, int>{}; +// expected-error@-1 {{constraints not satisfied for class template 'quantity' [with V = reference<int>{}, $1 = int]}} + +} // namespace CannotResolve1 } // namespace GH175831 >From b8a548f6c62b1d569ec8f7b7ec7bf073371eefbc Mon Sep 17 00:00:00 2001 From: I <[email protected]> Date: Thu, 4 Jun 2026 10:21:40 +0900 Subject: [PATCH 12/15] Revert "skip constant evaluation if unevaluated context" This reverts commit bf8a90e40c66b1100f6f19a846ef82eb6ffbc390. --- clang/lib/Sema/TreeTransform.h | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index c3e3bdcad14fe..70cdc47e42d5d 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -16727,19 +16727,11 @@ ExprResult TreeTransform<Derived>::TransformSubstNonTypeTemplateParmExpr( // specific annotations, such as implicit casts, are discarded. Calling the // corresponding sema action is necessary to recover those. Otherwise, // equivalency of the result would be lost. - // - // In an unevaluated context, skip the constant evaluation of the - // replacement: only its converted form matters there, and the evaluation - // can spuriously fail for otherwise valid replacements, because the - // entities they refer to are not odr-used in such a context (e.g. the - // implicit copy of a function argument of class type cannot be constant - // folded when the special members were never instantiated). TemplateArgument SugaredConverted, CanonicalConverted; Replacement = SemaRef.CheckTemplateArgument( Param, ParamType, Replacement.get(), SugaredConverted, CanonicalConverted, - /*StrictCheck=*/false, Sema::CTAK_Specified, - /*SkipConstantEvaluation=*/SemaRef.isUnevaluatedContext()); + /*StrictCheck=*/false, Sema::CTAK_Specified); if (Replacement.isInvalid()) return true; } else { >From 0966706862132a8d0851b61d7b9cb730813ceef8 Mon Sep 17 00:00:00 2001 From: I <[email protected]> Date: Thu, 4 Jun 2026 10:21:42 +0900 Subject: [PATCH 13/15] Revert "add SkipConstantEvaluation option for CheckTemplateArgument" This reverts commit 512b3cc3d63f7e75d51a459d247ae458c9b42d9c. --- clang/include/clang/Sema/Sema.h | 11 +---------- clang/lib/Sema/SemaTemplate.cpp | 8 +++----- 2 files changed, 4 insertions(+), 15 deletions(-) diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index d3eef97811cbd..b8d760e7e0975 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -12198,21 +12198,12 @@ class Sema final : public SemaBase { /// If an error occurred, it returns ExprError(); otherwise, it /// returns the converted template argument. \p ParamType is the /// type of the non-type template parameter after it has been instantiated. - /// - /// If \p SkipConstantEvaluation is true, the argument is converted to the - /// parameter type, but is not required to be constant-evaluable, similarly - /// to a value-dependent argument. This is used when only the converted form - /// of the argument is needed, e.g. when re-checking the replacement of a - /// SubstNonTypeTemplateParmExpr in an unevaluated context, where constant - /// evaluation may fail for otherwise valid arguments because the entities - /// they refer to are not odr-used. ExprResult CheckTemplateArgument(NamedDecl *Param, QualType InstantiatedParamType, Expr *Arg, TemplateArgument &SugaredConverted, TemplateArgument &CanonicalConverted, bool StrictCheck, - CheckTemplateArgumentKind CTAK, - bool SkipConstantEvaluation = false); + CheckTemplateArgumentKind CTAK); /// Check a template argument against its corresponding /// template template parameter. diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 9c53d1501fea1..8c94a1ad39208 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -7140,8 +7140,7 @@ ExprResult Sema::CheckTemplateArgument(NamedDecl *Param, QualType ParamType, TemplateArgument &SugaredConverted, TemplateArgument &CanonicalConverted, bool StrictCheck, - CheckTemplateArgumentKind CTAK, - bool SkipConstantEvaluation) { + CheckTemplateArgumentKind CTAK) { SourceLocation StartLoc = Arg->getBeginLoc(); auto *ArgPE = dyn_cast<PackExpansionExpr>(Arg); Expr *DeductionArg = ArgPE ? ArgPE->getPattern() : Arg; @@ -7345,9 +7344,8 @@ ExprResult Sema::CheckTemplateArgument(NamedDecl *Param, QualType ParamType, } // For a value-dependent argument, CheckConvertedConstantExpression is - // permitted (and expected) to be unable to determine a value. Treat the - // argument the same way when the caller does not need the value. - if (ArgResult.get()->isValueDependent() || SkipConstantEvaluation) { + // permitted (and expected) to be unable to determine a value. + if (ArgResult.get()->isValueDependent()) { setDeductionArg(ArgResult.get()); SugaredConverted = TemplateArgument(Arg, /*IsCanonical=*/false); CanonicalConverted = >From e67097d09dde399ceb2e5792a9c8a4d7344a8786 Mon Sep 17 00:00:00 2001 From: I <[email protected]> Date: Fri, 5 Jun 2026 11:41:09 +0900 Subject: [PATCH 14/15] insert constant-evaluated context before transforming replacement --- clang/lib/Sema/TreeTransform.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 70cdc47e42d5d..d56769188b6d7 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -16701,6 +16701,19 @@ template <typename Derived> ExprResult TreeTransform<Derived>::TransformSubstNonTypeTemplateParmExpr( SubstNonTypeTemplateParmExpr *E) { Expr *OrigReplacement = E->getReplacement()->IgnoreImplicitAsWritten(); + + // Insert a constant-evaluated context for the transform. + // Otherwise, when a normalized constraint places the replacement inside + // an unevaluated operand (e.g. decltype), entities it refers to are not + // odr-used, and the constant evaluation performed by CheckTemplateArgument + // below can spuriously fail for otherwise valid replacements, + // e.g. when a call materializes a function parameter of class type whose + // special members were never instantiated. + EnterExpressionEvaluationContext ConstantEvaluated( + SemaRef, Sema::ExpressionEvaluationContext::ConstantEvaluated, + /*LambdaContextDecl=*/nullptr, + Sema::ExpressionEvaluationContextRecord::EK_TemplateArgument); + ExprResult Replacement = getDerived().TransformExpr(OrigReplacement); if (Replacement.isInvalid()) return true; >From 59cadb7ce787c6c5fb3a4388b1f3cf9a851007c3 Mon Sep 17 00:00:00 2001 From: I <[email protected]> Date: Fri, 5 Jun 2026 11:56:44 +0900 Subject: [PATCH 15/15] reuse lambda context decl --- clang/lib/Sema/TreeTransform.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index d56769188b6d7..fcc7a932ab194 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -16711,7 +16711,7 @@ ExprResult TreeTransform<Derived>::TransformSubstNonTypeTemplateParmExpr( // special members were never instantiated. EnterExpressionEvaluationContext ConstantEvaluated( SemaRef, Sema::ExpressionEvaluationContext::ConstantEvaluated, - /*LambdaContextDecl=*/nullptr, + Sema::ReuseLambdaContextDecl, Sema::ExpressionEvaluationContextRecord::EK_TemplateArgument); ExprResult Replacement = getDerived().TransformExpr(OrigReplacement); _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
