On Tue, Feb 24, 2026 at 10:54:55PM +0900, Jason Merrill wrote:
> On 2/24/26 5:44 AM, Marek Polacek wrote:
> > Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?
> > 
> > -- >8 --
> > This patch fixes a very annoying problem where we emit a bogus
> > check_out_of_consteval_use error.  The error is provoked while
> > processing
> > 
> >    [: std::meta::reflect_constant_array (data) :]
> > 
> > The argument of a [: :] is a constant-expression = a manifestly
> > constant-evaluated context, so any consteval-only exprs in it
> > are OK.  But in eval_reflect_constant_array we do get_template_parm_object
> > which does push_to_top_level -- so we have no scope_chain, therefore
> > any in_consteval_if_p and current_function_decl are cleared, so we're
> > not in an immediate context.
> 
> Since we're initializing a constexpr variable (the template parameter
> object), we should be in MCE for that regardless of the splice expression.
> Maybe check_initializer should set that up?

Yeah, that sounds right, thanks.

I think that my change is also right, but not necessary anymore.

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

-- >8 --
This patch fixes a very annoying problem where we emit a bogus
check_out_of_consteval_use error.  The error is provoked while
processing

  [: std::meta::reflect_constant_array (data) :]

The argument of a [: :] is a constant-expression = a manifestly
constant-evaluated context, so any consteval-only exprs in it
are OK.  But in eval_reflect_constant_array we do get_template_parm_object
which does push_to_top_level -- so we have no scope_chain, therefore
any in_consteval_if_p and current_function_decl are cleared, so we're
not in an immediate context.  As part of this get_template_parm_object,
we call cp_finish_decl -> check_initializer -> build_aggr_init ->
-> build_vec_init.

Here in build_vec_init try_const is true, but we still generate code
for the initializer like

  <<< Unknown tree: expr_stmt
  (void)  ++D.67757 >>>;
<<< Unknown tree: expr_stmt
  (void)  --D.67758 >>>;

etc.  We add ++D.67757 with finish_expr_stmt which calls
convert_to_void -> check_out_of_consteval_use which causes the error
because ++D.67757's type is consteval-only.  Note that what we end up using
is the simple

  _ZTAX... = {{.name=<<< Unknown tree: reflect_expr _ZTAXtlA2_KcLS_95EEE >>>, 
.none=1}}

because we didn't see anything non-const in the initializer.

When initializing a constexpr variable, we are in a manifestly
constant-evaluated context, so fix check_initializer to that effect.

        PR c++/123662
        PR c++/123611

gcc/cp/ChangeLog:

        * decl.cc (check_initializer): Set in_consteval_if_p when initializing
        a constexpr variable.

gcc/testsuite/ChangeLog:

        * g++.dg/reflect/reflect_constant_array5.C: New test.
        * g++.dg/reflect/reflect_constant_array6.C: New test.
---
 gcc/cp/decl.cc                                |   4 +
 .../g++.dg/reflect/reflect_constant_array5.C  |  16 +++
 .../g++.dg/reflect/reflect_constant_array6.C  | 104 ++++++++++++++++++
 3 files changed, 124 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/reflect/reflect_constant_array5.C
 create mode 100644 gcc/testsuite/g++.dg/reflect/reflect_constant_array6.C

diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index 6b210a30b6a..5580dc87e9a 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -8574,6 +8574,10 @@ check_initializer (tree decl, tree init, int flags, 
vec<tree, va_gc> **cleanups)
                    || type_has_extended_temps (type))))
          || (DECL_DECOMPOSITION_P (decl) && TREE_CODE (type) == ARRAY_TYPE))
        {
+         /* If we're initializing a constexpr variable, we are in
+            a manifestly constant-evaluated context.  */
+         in_consteval_if_p_temp_override icip;
+         in_consteval_if_p |= DECL_DECLARED_CONSTEXPR_P (decl);
          init_code = build_aggr_init_full_exprs (decl, init, flags);
 
          /* A constructor call is a non-trivial initializer even if
diff --git a/gcc/testsuite/g++.dg/reflect/reflect_constant_array5.C 
b/gcc/testsuite/g++.dg/reflect/reflect_constant_array5.C
new file mode 100644
index 00000000000..9e52f408d5a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/reflect/reflect_constant_array5.C
@@ -0,0 +1,16 @@
+// PR c++/123662
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+#include <meta>
+
+struct arg {
+    std::meta::info name;
+    bool none = true;
+};
+
+template<size_t...Is>
+void test1() {
+    constexpr auto py_arg_data = 
std::array{arg{std::meta::reflect_constant_string("_")}};
+    constexpr auto short_py_arg_data = [: 
std::meta::reflect_constant_array(py_arg_data) :];
+}
diff --git a/gcc/testsuite/g++.dg/reflect/reflect_constant_array6.C 
b/gcc/testsuite/g++.dg/reflect/reflect_constant_array6.C
new file mode 100644
index 00000000000..918b07ffb88
--- /dev/null
+++ b/gcc/testsuite/g++.dg/reflect/reflect_constant_array6.C
@@ -0,0 +1,104 @@
+// PR c++/123611
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+#include <string>
+#include <meta>
+#include <algorithm>
+#include <ranges>
+#include <sstream>
+
+namespace clap {
+  struct Flags {
+      bool use_short;
+      bool use_long;
+  };
+
+  template <typename T, Flags flags>
+  struct Option {
+      std::optional<T> initializer;
+
+      Option() = default;
+      Option(T t) : initializer(t) { }
+
+      static constexpr bool use_short = flags.use_short;
+      static constexpr bool use_long = flags.use_long;
+  };
+
+  consteval auto spec_to_opts(std::meta::info opts, std::meta::info spec) -> 
std::meta::info {
+    std::vector<std::meta::info> new_members;
+    for (auto member :
+          nonstatic_data_members_of(spec, 
std::meta::access_context::current())) {
+      auto new_type = template_arguments_of(type_of(member))[0];
+      new_members.push_back(data_member_spec(new_type, 
{.name=identifier_of(member)}));
+    }
+    return define_aggregate(opts, new_members);
+  }
+
+  struct Clap {
+    template <typename Spec>
+    auto parse(this Spec const& spec, int argc, const char** argv) {
+      std::vector<std::string_view> cmdline(argv + 1, argv + argc);
+
+      struct Opts;
+      consteval {
+        spec_to_opts(^^Opts, ^^Spec);
+      }
+      Opts opts;
+
+      constexpr auto ctx = std::meta::access_context::current();
+      template for (constexpr auto Pair :
+                    std::define_static_array(
+                      std::views::zip(nonstatic_data_members_of(^^Spec, ctx),
+                                      nonstatic_data_members_of(^^Opts, ctx)) |
+                      std::views::transform([](auto z) { return 
std::pair(get<0>(z), get<1>(z)); }))) {
+        constexpr auto sm = Pair.first;
+        constexpr auto om = Pair.second;
+
+        auto& cur = spec.[:sm:];
+        constexpr auto type = type_of(om);
+
+        auto it = std::find_if(cmdline.begin(), cmdline.end(),
+            [&](std::string_view arg) {
+              return (cur.use_short && arg.size() == 2 && arg[0] == '-' &&
+                      arg[1] == identifier_of(sm)[0])
+                  || (cur.use_long && arg.starts_with("--") &&
+                      arg.substr(2) == identifier_of(sm));
+            });
+
+        if (it == cmdline.end()) {
+          if constexpr (has_template_arguments(type) &&
+                        template_of(type) == ^^std::optional) {
+            continue;
+          } else if (cur.initializer) {
+            opts.[:om:] = *cur.initializer;
+            continue;
+          } else {
+            std::exit(EXIT_FAILURE);
+          }
+        } else if (it + 1 == cmdline.end()) {
+          std::exit(EXIT_FAILURE);
+        }
+
+        std::stringstream iss;
+        iss << it[1];
+        if (iss >> opts.[:om:]; !iss) {
+          std::exit(EXIT_FAILURE);
+        }
+      }
+
+      return opts;
+    }
+  };
+}
+
+using namespace clap;
+struct Args : Clap {
+  Option<std::string, Flags{.use_short=true, .use_long=true}> name;
+  Option<int, Flags{.use_short=true, .use_long=true}> count = 1;
+};
+
+int main(int argc, const char** argv) {
+  auto opts = Args{}.parse(argc, argv);
+  for (int i = 0; i < opts.count; ++i) { }
+}

base-commit: 33b856931c78661944f27b60457365ef2b451b54
-- 
2.53.0

Reply via email to