[clang] [Clang] Tolerate constant evaluation failure when transforming SubstNonTypeTemplateParmExpr in unevaluated contexts (PR #196791)
via cfe-commits
cfe-commits at lists.llvm.org
Sun May 10 03:04:10 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: I (wx257osn2)
<details>
<summary>Changes</summary>
Fixes #<!-- -->175831.
When transforming a `SubstNonTypeTemplateParmExpr`, `TreeTransform::TransformSubstNonTypeTemplateParmExpr` calls `Sema::CheckTemplateArgument` so that any sema annotations (such as implicit casts) that were stripped from the replacement are recovered.
However, `CheckTemplateArgument` forces constant evaluation of the replacement expression, and that evaluation can fail in unevaluated contexts (e.g. inside `decltype`) for otherwise valid expressions.
A typical case is a function call that takes a class-type parameter by value: in an unevaluated context the special members of the argument's class are not instantiated, so the implicit copy used to materialize the parameter cannot be constant-folded and `CheckTemplateArgument` reports an error. This caused rejects-valid regressions on real code such as mp-units.
In an unevaluated context we only need the type of the resulting expression, not its value. This PR keeps the existing behavior in evaluated contexts but, when `CheckTemplateArgument` fails inside an unevaluated context, falls back to using the already-transformed replacement as-is instead of propagating the failure.
--
Co-authored-by: A. Jiang <de34@<!-- -->live.cn>
---
Full diff: https://github.com/llvm/llvm-project/pull/196791.diff
3 Files Affected:
- (modified) clang/docs/ReleaseNotes.rst (+1)
- (modified) clang/lib/Sema/TreeTransform.h (+13-3)
- (modified) clang/test/SemaTemplate/concepts.cpp (+18-1)
``````````diff
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
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
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();
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
``````````
</details>
https://github.com/llvm/llvm-project/pull/196791
More information about the cfe-commits
mailing list