On 9/11/26 6:45 AM, Jakub Jelinek wrote:
On Thu, Sep 10, 2026 at 05:52:18PM +0200, Jakub Jelinek wrote:
On Thu, Sep 10, 2026 at 11:50:01AM -0400, Marek Polacek wrote:
@@ -8799,6 +8801,10 @@ splice (tree refl)
       class for the access path.  */
    if (is_overloaded_fn (refl))
      refl = baselink_for_fns (refl, /*ignore_current_class_p=*/true);
+  /* For [:reflect_object(var):] wrap var into a VCE, so that it is an lvalue,
+     but not the var itself.  */
+  if (kind == REFLECT_OBJECT && DECL_P (refl))
+    refl = build1 (VIEW_CONVERT_EXPR, TREE_TYPE (refl), refl);

Should we give this VCE the location loc?

I think we could.  Will test adjusted patch.

This passed full bootstrap/regtest on x86_64-linux and i686-linux.

OK.
2026-09-11  Jakub Jelinek  <[email protected]>

        P3598R0
        PR c++/125840
        * reflect.cc: Implement C++26 CWG 3158 - const-ification of Splice
        Expressions.
        (splice): Remember REFLECT_EXPR_KIND of REFLECT_EXPR.  Set refl to
        REFLECT_EXPR_HANDLE earlier.  For REFLECT_OBJECT wrap decls into
        a VCE to differentiate it from corresponding variables.
        * pt.cc (tsubst_splice_expr): Call constify_contract_access if
        needed.

        * g++.dg/reflect/contract1.C: New test.
        * g++.dg/reflect/contract2.C: New test.
        * g++.dg/reflect/contract3.C: New test.
        * g++.dg/reflect/contract4.C: New test.
        * g++.dg/reflect/contract5.C: New test.
        * g++.dg/reflect/reflect_object2.C (g): Add test for setting of
        splice expr of an object reflection.

--- a/gcc/cp/reflect.cc 2026-08-20 08:39:02.400320178 +0200
+++ b/gcc/cp/reflect.cc 2026-09-10 17:55:59.978985838 +0200
@@ -8782,12 +8782,14 @@ splice (tree refl)
        return error_mark_node;
      }
+ reflect_kind kind = REFLECT_EXPR_KIND (refl);
+  refl = REFLECT_EXPR_HANDLE (refl);
+
    /* We are bringing some entity from the unevaluated expressions world
       to possibly outside of that, mark it used.  */
-  if (!mark_used (REFLECT_EXPR_HANDLE (refl)))
+  if (!mark_used (refl))
      return error_mark_node;
- refl = REFLECT_EXPR_HANDLE (refl);
    /* Function templates are wrapped in OVERLOAD from name lookup
       and a lot of places assume that.  Furthermore, if reflection comes
       from ^^fntmpl, it is wrapped with OVERLOAD already, only when
@@ -8799,6 +8801,10 @@ splice (tree refl)
       class for the access path.  */
    if (is_overloaded_fn (refl))
      refl = baselink_for_fns (refl, /*ignore_current_class_p=*/true);
+  /* For [:reflect_object(var):] wrap var into a VCE, so that it is an lvalue,
+     but not the var itself.  */
+  if (kind == REFLECT_OBJECT && DECL_P (refl))
+    refl = build1_loc (loc, VIEW_CONVERT_EXPR, TREE_TYPE (refl), refl);
return refl;
  }
--- a/gcc/cp/pt.cc      2026-09-10 15:13:06.631450280 +0200
+++ b/gcc/cp/pt.cc      2026-09-10 16:10:14.607111179 +0200
@@ -17174,7 +17174,11 @@ tsubst_splice_expr (tree t, tree args, t
    if (SPLICE_EXPR_MEMBER_ACCESS_P (t))
      gcc_assert (valid_splice_for_member_access_p (op, 
/*decls_only_p=*/false));
    else if (SPLICE_EXPR_EXPRESSION_P (t))
-    op = convert_from_reference (op);
+    {
+      op = convert_from_reference (op);
+      if (flag_contracts && processing_contract_condition)
+       op = constify_contract_access (op);
+    }
return op;
  }
--- a/gcc/testsuite/g++.dg/reflect/contract1.C  2026-09-10 15:13:14.746781204 
+0200
+++ b/gcc/testsuite/g++.dg/reflect/contract1.C  2026-09-10 16:14:24.660891506 
+0200
@@ -0,0 +1,32 @@
+// C++26 P3598R0 - CWG 3158 - const-ification of Splice Expressions
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+namespace std
+{
+  template<typename T>
+    struct add_lvalue_reference
+    { using type = __add_lvalue_reference (T); };
+  template<typename T>
+    using add_lvalue_reference_t = typename add_lvalue_reference <T>::type;
+}
+
+#define UNCONST(x) const_cast <std::add_lvalue_reference_t <decltype (x)>> (x)
+
+int v;
+
+void
+foo (int p)
+  pre ((++p, true))            // { dg-error "increment of read-only location 
'\\\(const int\\\)p'" }
+  pre ((++[:^^p:], true))      // { dg-error "increment of read-only location 
'\\\(const int\\\)p'" }
+  pre ((++UNCONST (p), true))
+{
+}
+
+void
+bar ()
+  pre ((++v, true))            // { dg-error "increment of read-only location 
'\\\(const int\\\)v'" }
+  pre ((++[:^^v:], true))      // { dg-error "increment of read-only location 
'\\\(const int\\\)v'" }
+  pre ((++UNCONST (v), true))
+{
+}
--- a/gcc/testsuite/g++.dg/reflect/contract2.C  2026-09-10 15:13:14.746898983 
+0200
+++ b/gcc/testsuite/g++.dg/reflect/contract2.C  2026-09-10 16:27:15.532724804 
+0200
@@ -0,0 +1,71 @@
+// C++26 P3598R0 - CWG 3158 - const-ification of Splice Expressions
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+namespace std
+{
+  template<typename T>
+    struct add_lvalue_reference
+    { using type = __add_lvalue_reference (T); };
+  template<typename T>
+    using add_lvalue_reference_t = typename add_lvalue_reference <T>::type;
+}
+
+#define UNCONST(x) const_cast <std::add_lvalue_reference_t <decltype (x)>> (x)
+
+template <typename T>
+void
+foo (T p)                      // { dg-error "increment of read-only location 
'\\\(const int\\\)p'" }
+  pre ((++p, true))
+{
+}
+
+template <typename T>
+void
+bar (T p)                      // { dg-error "increment of read-only location 
'\\\(const int\\\)p'" }
+  pre ((++[:^^p:], true))
+{
+}
+
+template <typename T>
+void
+baz (T p)
+  pre ((++UNCONST (p), true))
+{
+}
+
+int v;                         // { dg-error "increment of read-only location 
'\\\(const int\\\)v'" }
+int w;                         // { dg-error "increment of read-only location 
'\\\(const int\\\)w'" }
+int x;
+
+template <bool B>
+void
+corge (int p)                  // { dg-error "increment of read-only location 
'\\\(const int\\\)p'" }
+  pre ((++(B ? v : p), true))  // { dg-error "increment of read-only location 
'\\\(B \\\? \\\(\\\(const int\\\)v\\\) : \\\(\\\(const int\\\)p\\\)\\\)'" }
+{
+}
+
+template <bool B>
+void
+garply (int p)
+  pre ((++[:B ? ^^w : ^^p:], true))
+{
+}
+
+template <bool B>
+void
+waldo (int p)
+  pre ((++(B ? UNCONST (x) : UNCONST (p)), true))
+{
+}
+
+void
+qux (int p)
+{
+  foo (p);                     // { dg-message "required from here" }
+  bar (p);                     // { dg-message "required from here" }
+  baz (p);
+  corge <true> (p);              // { dg-message "required from here" }
+  garply <true> (p);             // { dg-message "required from here" }
+  waldo <true> (p);
+}
--- a/gcc/testsuite/g++.dg/reflect/contract3.C  2026-09-10 15:13:33.709088988 
+0200
+++ b/gcc/testsuite/g++.dg/reflect/contract3.C  2026-09-10 16:30:30.859154428 
+0200
@@ -0,0 +1,40 @@
+// C++26 P3598R0 - CWG 3158 - const-ification of Splice Expressions
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+#include <meta>
+
+int v;
+
+void
+foo ()
+  pre ((++[:object_of (^^v):], true))
+{
+}
+
+void
+bar ()
+  pre ((++[:std::meta::reflect_object (v):], true))
+{
+}
+
+template <bool B>
+void
+baz (int p)
+  pre ((++[:object_of (B ? ^^v : ^^p):], true))
+{
+}
+
+template <bool B>
+void
+qux (int p)
+  pre ((++[:std::meta::reflect_object (B ? v : p):], true))
+{
+}
+
+void
+corge (int p)
+{
+  baz <true> (p);
+  qux <true> (p);
+}
--- a/gcc/testsuite/g++.dg/reflect/contract4.C  2026-09-10 16:31:10.752629451 
+0200
+++ b/gcc/testsuite/g++.dg/reflect/contract4.C  2026-09-10 15:14:46.432118660 
+0200
@@ -0,0 +1,39 @@
+// C++26 P3598R0 - CWG 3158 - const-ification of Splice Expressions
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+#include <array>
+#include <meta>
+#include <vector>
+
+template <typename T1, typename T2>
+auto
+foo (const T1 &t1, const T2 &t2)
+  pre([: is_integral_type (^^T1) ? ^^t2 : ^^t1 :]
+      [ [: is_integral_type (^^T1) ? ^^t1 : ^^t2 :] ] >= 0)
+{
+  constexpr auto key = is_integral_type (^^T1) ? ^^t1 : ^^t2;
+  constexpr auto container = is_integral_type (^^T1) ? ^^t2 : ^^t1;
+  return [: container :][ [: key :] ];
+}
+
+void
+bar (std::vector <int> &v)
+{
+  foo (v, 5);
+  foo (5, v);
+}
+
+template <std::size_t N>
+void
+baz (std::array <int, N> &v)
+{
+  foo (v, 5);
+  foo (5, v);
+}
+
+void
+qux (std::array <int, 7> &v)
+{
+  baz (v);
+}
--- a/gcc/testsuite/g++.dg/reflect/contract5.C  2026-09-10 16:31:15.872562075 
+0200
+++ b/gcc/testsuite/g++.dg/reflect/contract5.C  2026-09-10 15:35:07.447779324 
+0200
@@ -0,0 +1,26 @@
+// C++26 P3598R0 - CWG 3158 - const-ification of Splice Expressions
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+#include <map>
+#include <meta>
+
+template <typename T1, typename T2>
+auto
+foo (const T1 &t1, const T2 &t2)
+  pre([: is_integral_type (^^T1) ? ^^t2 : ^^t1 :]
+      [ [: is_integral_type (^^T1) ? ^^t1 : ^^t2 :] ] >= 0) // { dg-error "no match for 
'operator\\\[\\\]' in 't1\\\[t2\\\]' \\\(operand types are 'const std::map<int, int>' and 
'const int'\\\)" }
+{                                                              // { dg-error "no match for 
'operator\\\[\\\]' in 't2\\\[t1\\\]' \\\(operand types are 'const std::map<int, int>' and 'const 
int'\\\)" "" { target *-*-* } .-1 }
+  constexpr auto key = is_integral_type (^^T1) ? ^^t1 : ^^t2;
+  constexpr auto container = is_integral_type (^^T1) ? ^^t2 : ^^t1;
+  return [: container :][ [: key :] ];                         // { dg-error "no match 
for 'operator\\\[\\\]' in 't1\\\[t2\\\]' \\\(operand types are 'const std::map<int, int>' 
and 'const int'\\\)" }
+}                                                              // { dg-error "no match for 
'operator\\\[\\\]' in 't2\\\[t1\\\]' \\\(operand types are 'const std::map<int, int>' and 'const 
int'\\\)" "" { target *-*-* } .-1 }
+
+void
+bar (std::map <int, int> &m)
+{
+  foo (m, 5);
+  foo (5, m);
+}
+
+// { dg-error "cannot bind rvalue reference of type 'std::map<int, int>::key_type\\\&\\\&' {aka 
'int\\\&\\\&'} to lvalue of type 'const int'" "" { target *-*-* } 0 }
--- a/gcc/testsuite/g++.dg/reflect/reflect_object2.C    2026-03-27 
10:17:16.140298005 +0100
+++ b/gcc/testsuite/g++.dg/reflect/reflect_object2.C    2026-09-10 
15:53:51.973822831 +0200
@@ -112,4 +112,5 @@ g ()
  {
    int i = [:robj:];
    [:rbar:](42);
+  [:robj:] += 42;
  }


        Jakub


Reply via email to