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 &lt;de34@<!-- -->live.cn&gt;

---
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
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to