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/10] 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 b427e6a4d2fa51..4275f639896078 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/10] 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 70cdc47e42d5d7..34b0ac9e86be55 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/10] 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 9e4a47a5b18fca..a654a94adceb47 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/10] 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 4275f639896078..794229cf0b1db0 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/10] 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 34b0ac9e86be55..8c661ce27fc4c5 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/10] 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 8c661ce27fc4c5..34b0ac9e86be55 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/10] 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 34b0ac9e86be55..70cdc47e42d5d7 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/10] 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 794229cf0b1db0..f735bfc1251c21 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/10] 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 b8d760e7e0975a..d3eef97811cbdf 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 8c94a1ad392086..9c53d1501fea17 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/10] 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 70cdc47e42d5d7..c3e3bdcad14fef 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 {

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to