[clang] [Clang] Tolerate constant evaluation failure when transforming SubstNonTypeTemplateParmExpr in unevaluated contexts (PR #196791)
via cfe-commits
cfe-commits at lists.llvm.org
Mon May 11 04:58:04 PDT 2026
https://github.com/wx257osn2 updated https://github.com/llvm/llvm-project/pull/196791
>From adbf863c01a830dbed6dae82c7ce45ede7cd424d 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 1/5] 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 1b7cfc96243ef..c5fe4969a36b6 100644
--- a/clang/test/SemaTemplate/concepts.cpp
+++ b/clang/test/SemaTemplate/concepts.cpp
@@ -1836,7 +1836,6 @@ namespace GH191016 {
void test(){ S<int> s; }
}
-
namespace GH188640 {
namespace Ex1 {
@@ -1880,3 +1879,21 @@ void g() { static_assert(f<1>() == 42); }
} // namespace VAR
} // namespace GH188640
+
+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 31900217d9c19ab01b7ff4e1cf1b2339419c734e 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 2/5] 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 40187f71231bd..efaff4c0e02ec 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -16736,13 +16736,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 ecba5c863914869feb81798efb15b52df904e12c 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 3/5] 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 c17143e3c0398..6c2cecfb7dc20 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -543,6 +543,7 @@ Bug Fixes in This Version
- Fixed a crash when parsing invalid ``static_assert`` declarations with string-literal messages (#GH187690).
- Fixed a potential stack-use-after-return issue in Clang when copy-initializing
an array via an element-at-a-time copy loop (#GH192026)
+- 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 a4cc6b698973d52a81851b47037cf3931e97d360 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 4/5] 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 c5fe4969a36b6..cc7fa50f13bf5 100644
--- a/clang/test/SemaTemplate/concepts.cpp
+++ b/clang/test/SemaTemplate/concepts.cpp
@@ -1882,6 +1882,8 @@ void g() { static_assert(f<1>() == 42); }
namespace GH175831 {
+namespace ShuoldResolve {
+
template<class>
struct reference {};
template<class Q>
@@ -1896,4 +1898,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 315ef2b0fc0903e1b56e64c746187ae38454c240 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 5/5] 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 efaff4c0e02ec..5fea685acea74 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -16736,22 +16736,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.
More information about the cfe-commits
mailing list