[clang] [Clang] Transform SubstNonTypeTemplateParmExpr replacements in a constant-evaluated context (PR #196791)
via cfe-commits
cfe-commits at lists.llvm.org
Thu Jun 4 20:00:17 PDT 2026
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" <de34 at live.cn>
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 at -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 <wx257osn2 at yahoo.co.jp>
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 <wx257osn2 at yahoo.co.jp>
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 <wx257osn2 at yahoo.co.jp>
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 at -1 {{constraints not satisfied for class template 'quantity' [with V = reference<char>{}, $1 = char]}}
+// expected-note at -5 {{because 'representation_of<char, get_spec(reference<char>{})>' evaluated to false}}
+// expected-note-re at -7 {{because 'decltype({{.*}})' (aka 'char') does not satisfy 'repr_impl'}}
+// expected-note at -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 <wx257osn2 at yahoo.co.jp>
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 <wx257osn2 at yahoo.co.jp>
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 <wx257osn2 at yahoo.co.jp>
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 <wx257osn2 at yahoo.co.jp>
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 <wx257osn2 at yahoo.co.jp>
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 <wx257osn2 at yahoo.co.jp>
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 <mizvekov at gmail.com>
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 at -7 {{because 'decltype({{.*}})' (aka 'char') does not satisfy 'repr_impl'}}
// expected-note at -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 at -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 <wx257osn2 at yahoo.co.jp>
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 <wx257osn2 at yahoo.co.jp>
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 <wx257osn2 at yahoo.co.jp>
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 <wx257osn2 at yahoo.co.jp>
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);
More information about the cfe-commits
mailing list