Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?

-- >8 --
A couple of problems here:

[meta.reflection.extract]/5.3 says "If r represents a variable, then
either that variable is usable in constant expressions or its lifetime
began within the core constant expression currently under evaluation."
but I was wrongly using is_constant_expression.  That led to a crash
because we passed a type to build_address.  For "is usable..." we want
decl_constant_var_p and for the "its lifetime began..." I'm adding a new
function.  Using cxx_eval_constant_expression for non-reference
variables wouldn't work since evaluating a variable as a glvalue always
succeeds, and as a prvalue fails for e.g. an uninitialized variable
whose lifetime did begin.

With this patch, a variable that isn't usable in constant expressions
throws.  Thus the extract2.C and extract3.C changes; one can use
object_of to get the object instead.

Also, DECL_INITIAL of a PARM_DECL is not an initializer but DECL_ARG_TYPE.
So we need cxx_eval_constant_expression to handle e.g.:

  int g;
  consteval void h (const int &p)
  {
    std::meta::extract<const int &> (^^p);
  }
  consteval { h (g); }

where we need to get "(const int &) &g" from PARM_DECL p.

This adds a new XFAIL because we don't have P2686 yet.

It seems that object_of will need similar tweaks but that's for another
patch.

        PR c++/127232

gcc/cp/ChangeLog:

        * constexpr.cc (constexpr_global_ctx::within_lifetime_p): New.
        (cxx_constexpr_in_eval_lifetime_p): New.
        * cp-tree.h (cxx_constexpr_in_eval_lifetime_p): Declare.
        * reflect.cc (extract_ref): Check decl_constant_var_p and
        cxx_constexpr_in_eval_lifetime_p instead of
        is_constant_expression.  Use cxx_eval_constant_expression
        instead of DECL_INITIAL for references.  Adjust the checking
        assert.

gcc/testsuite/ChangeLog:

        * g++.dg/reflect/extract2.C: Adjust dg-error.
        * g++.dg/reflect/extract3.C: Add dg-error.  Add tests using
        object_of.
        * g++.dg/reflect/extract13.C: New test.
        * g++.dg/reflect/extract14.C: New test.
---
 gcc/cp/constexpr.cc                      | 20 +++++++-
 gcc/cp/cp-tree.h                         |  1 +
 gcc/cp/reflect.cc                        | 15 ++++--
 gcc/testsuite/g++.dg/reflect/extract13.C | 59 ++++++++++++++++++++++++
 gcc/testsuite/g++.dg/reflect/extract14.C | 23 +++++++++
 gcc/testsuite/g++.dg/reflect/extract2.C  |  2 +-
 gcc/testsuite/g++.dg/reflect/extract3.C  | 21 ++++++---
 7 files changed, 129 insertions(+), 12 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/reflect/extract13.C
 create mode 100644 gcc/testsuite/g++.dg/reflect/extract14.C

diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index 31ef5bf1111..cf31c803be6 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -1247,7 +1247,16 @@ public:
        return true;
     return false;
   }
- tree get_value (tree t)
+  /* This differs from !is_outside_lifetime in that it returns false if
+     T is not in the map.  */
+  bool within_lifetime_p (tree t)
+  {
+    if (tree *p = values.get (t))
+      if (*p != void_node && *p != void_list_node)
+       return true;
+    return false;
+  }
+  tree get_value (tree t)
   {
     if (tree *p = values.get (t))
       if (*p != void_node && *p != void_list_node)
@@ -1404,6 +1413,15 @@ cxx_constexpr_consteval_block (const constexpr_ctx *ctx)
   return ctx->global->consteval_block;
 }
 
+/* Return true if T's lifetime began within the core constant expression
+   currently under evaluation.  */
+
+bool
+cxx_constexpr_in_eval_lifetime_p (const constexpr_ctx *ctx, tree t)
+{
+  return ctx->global->within_lifetime_p (t);
+}
+
 /* Predicates for the meaning of *jump_target.  */
 
 static bool
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 947bf62ff98..83a287471a5 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -9486,6 +9486,7 @@ extern bool cxx_constexpr_quiet_p         (const 
constexpr_ctx *);
 extern mce_value cxx_constexpr_manifestly_const_eval (const constexpr_ctx *);
 extern tree cxx_constexpr_caller               (const constexpr_ctx *);
 extern tree cxx_constexpr_consteval_block      (const constexpr_ctx *);
+extern bool cxx_constexpr_in_eval_lifetime_p   (const constexpr_ctx *, tree);
 
 /* An RAII sentinel used to restrict constexpr evaluation so that it
    doesn't do anything that causes extra DECL_UID generation.  */
diff --git a/gcc/cp/reflect.cc b/gcc/cp/reflect.cc
index 8bf518df64f..8a4c5490bbf 100644
--- a/gcc/cp/reflect.cc
+++ b/gcc/cp/reflect.cc
@@ -7686,18 +7686,27 @@ extract_ref (location_t loc, const constexpr_ctx *ctx, 
tree T, tree r,
       if (adju != error_mark_node
          && adjt != error_mark_node
          && is_convertible (adju, adjt)
-         && (!var_p || is_constant_expression (r)))
+         && (!var_p
+             || decl_constant_var_p (r)
+             || cxx_constexpr_in_eval_lifetime_p (ctx, r)))
        {
          if (TYPE_REF_P (TREE_TYPE (r)))
            {
-             r = DECL_INITIAL (r);
+             bool nc = false, ovf = false;
+             tree jt = NULL_TREE;
+             r = cxx_eval_constant_expression (ctx, r, vc_prvalue,
+                                               &nc, &ovf, &jt);
+             if (nc || jt)
+               goto throw_;
              r = maybe_get_reference_referent (r);
-             gcc_checking_assert (!TYPE_REF_P (TREE_TYPE (r)));
+             gcc_checking_assert (r && !TYPE_P (r)
+                                  && !TYPE_REF_P (TREE_TYPE (r)));
            }
          return build_address (r);
        }
     }
 
+throw_:
   return throw_exception (loc, ctx, "value cannot be extracted", fun,
                          non_constant_p, jump_target);
 }
diff --git a/gcc/testsuite/g++.dg/reflect/extract13.C 
b/gcc/testsuite/g++.dg/reflect/extract13.C
new file mode 100644
index 00000000000..8b9ecdd10bf
--- /dev/null
+++ b/gcc/testsuite/g++.dg/reflect/extract13.C
@@ -0,0 +1,59 @@
+// PR c++/127232
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+#include <meta>
+
+void
+foo (int const& x)
+{
+  constexpr std::meta::info y = ^^x;
+  constexpr auto e = extract<int const&>(y);    // { dg-error "value cannot be 
extracted" }
+}
+
+consteval bool
+throws_p (std::meta::info r)
+{
+  try { extract<const int &> (r); }
+  catch (std::meta::exception &) { return true; }
+  return false;
+}
+
+int g;
+constexpr const int &cr = g;
+
+void
+f (const int &x, int y)
+{
+  static_assert (throws_p (^^x));
+  static_assert (throws_p (^^y));
+  const int &lx = x;
+  static_assert (throws_p (^^lx));
+  int &lg = g;
+  static_assert (!throws_p (^^lg));
+  static_assert (throws_p (^^g));
+  int a = 42;
+  int &la = a;
+  static_assert (!throws_p (^^la)); // { dg-bogus "" "P2686" { xfail *-*-* } }
+}
+
+consteval bool
+lifetime ()
+{
+  int i = 0;
+  int &ri = i;
+  return &extract<int &> (^^ri) == &i;
+}
+static_assert (lifetime ());
+
+consteval void
+h (const int &p)
+{
+  int i = 42;
+  const int &ri = i;
+  extract<const int &> (^^i);
+  extract<const int &> (^^ri);
+  extract<const int &> (^^p);
+}
+
+consteval { h (g); }
diff --git a/gcc/testsuite/g++.dg/reflect/extract14.C 
b/gcc/testsuite/g++.dg/reflect/extract14.C
new file mode 100644
index 00000000000..ede1a5b3c92
--- /dev/null
+++ b/gcc/testsuite/g++.dg/reflect/extract14.C
@@ -0,0 +1,23 @@
+// PR c++/127232
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+#include <meta>
+
+// Check that reflections of locals/parameters refer to the current frame in
+// recursive calls.
+consteval bool
+foo (int n, int *outer)
+{
+  int i = n;
+  if (&std::meta::extract<int &> (^^i) != &i
+      || &std::meta::extract<int &> (^^n) != &n)
+    return false;
+  if (outer && &std::meta::extract<int &> (^^i) == outer)
+    return false;
+  int &ri = i;
+  if (&std::meta::extract<int &> (^^ri) != &i)
+    return false;
+  return n == 0 || foo (n - 1, &i);
+}
+static_assert (foo (2, nullptr));
diff --git a/gcc/testsuite/g++.dg/reflect/extract2.C 
b/gcc/testsuite/g++.dg/reflect/extract2.C
index 9de23d1e931..2d5f758ea96 100644
--- a/gcc/testsuite/g++.dg/reflect/extract2.C
+++ b/gcc/testsuite/g++.dg/reflect/extract2.C
@@ -93,7 +93,7 @@ static_assert (!can_extract<const int &>(reflect_constant 
(i)));
 static_assert (!can_extract<int &>(^^i));
 
 int j;
-static_assert (extract<int &>(^^j)); // { dg-error "non-constant|not usable" }
+constexpr auto e = extract<int &>(^^j); // { dg-error "cannot be extracted" }
 
 consteval info
 bar ()
diff --git a/gcc/testsuite/g++.dg/reflect/extract3.C 
b/gcc/testsuite/g++.dg/reflect/extract3.C
index f8c173c0208..42e06fac342 100644
--- a/gcc/testsuite/g++.dg/reflect/extract3.C
+++ b/gcc/testsuite/g++.dg/reflect/extract3.C
@@ -33,12 +33,16 @@ static_assert (extract<const int &>(^^rj) == j);
 static_assert (&extract<const int &>(^^rj) == &j);
 
 int k = 1;
-static_assert (&extract<int &>(^^k) == &k);
-static_assert (&extract<const int &>(^^k) == &k);
+constexpr auto e1 = extract<int &>(^^k);         // { dg-error "cannot be 
extracted" }
+constexpr auto e2 = extract<const int &>(^^k);   // { dg-error "cannot be 
extracted" }
+static_assert (&extract<int &> (object_of (^^k)) == &k);
+static_assert (&extract<const int &> (object_of (^^k)) == &k);
 
 int arr[5] {};
-static_assert (&extract<int (&)[5]>(^^arr) == &arr);
-static_assert (&extract<const int (&)[5]>(^^arr) == &arr);
+constexpr auto e3 = extract<int (&)[5]>(^^arr);              // { dg-error 
"cannot be extracted" }
+constexpr auto e4 = extract<const int (&)[5]>(^^arr); // { dg-error "cannot be 
extracted" }
+static_assert (&extract<int (&)[5]>(object_of (^^arr)) == &arr);
+static_assert (&extract<const int (&)[5]>(object_of (^^arr)) == &arr);
 
 struct S { int m; };
 constexpr S s{42};
@@ -54,9 +58,12 @@ same_type<decltype(extract<const S &>(reflect_constant 
(S{42}))), const S &> st7
 same_type<decltype(&extract<const S &>(reflect_constant (S{42}))), const S *> 
st8;
 
 S sr{42};
-static_assert (&extract<S&>(^^sr) == &sr);
-static_assert (&extract<const S&>(^^sr) == &sr);
-static_assert (&extract<S&>(^^sr).m == &sr.m);
+constexpr auto e5 = extract<S&>(^^sr);       // { dg-error "cannot be 
extracted" }
+constexpr auto e6 = extract<const S&>(^^sr);  // { dg-error "cannot be 
extracted" }
+constexpr auto e7 = extract<S&>(^^sr).m;      // { dg-error "cannot be 
extracted" }
+static_assert (&extract<S&>(object_of (^^sr)) == &sr);
+static_assert (&extract<const S&>(object_of (^^sr)) == &sr);
+static_assert (&extract<S&>(object_of (^^sr)).m == &sr.m);
 int &srm = sr.m;
 static_assert (&extract<int&>(^^srm) == &sr.m);
 

base-commit: b24418a22128668b21179dfcb73fa54ee3929ecf
-- 
2.55.0

Reply via email to