On 2/22/23 14:45, Patrick Palka wrote:
Here we're mishandling the unevaluated array new-expressions due to a
supposed non-constant array size ever since r12-5253-g4df7f8c79835d569,
made us no longer perform constant evaluation of non-manifestly-constant
expressions within unevaluated contexts.  This shouldn't make a
difference here since the array sizes are constant literals, except
they're actually NON_LVALUE_EXPR location wrappers wrapping INTEGER_CST,
wrappers which used to get stripped as part of constant evaluation and
now no longer do.  Moreover it means build_vec_init can't constant fold
the 'maxindex' passed from build_new_1 (since it uses maybe_constant_value
with mce_unknown).

Hmm, now that you mention it I think the

  if (manifestly_const_eval != mce_unknown)

change in maybe_constant_value isn't quite right, we don't want to force evaluation in unevaluated mce_false context either.

This patch fixes the first issue by making maybe_constant_value and
fold_non_dependent_expr_template shortcut handling location wrappers
around constant nodes, and the second issue by using fold_build2_loc
instead of cp_build_binary_op when computing the maxindex to pass to
build_vec_init.

Maybe in unevaluated mce_unknown/false context maybe_constant_value should call fold?

Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
trunk/12?

        PR c++/108219
        PR c++/108218

gcc/cp/ChangeLog:

        * constexpr.cc (maybe_constant_value): Extend the constant node
        shortcut to look through location wrappers too.
        (fold_non_dependent_expr_template): Mirror the constant node
        shortcut from maybe_constant_value.
        * init.cc (build_new_1): Use fold_build2_loc instead
        of cp_build_binary_op to build a MINUS_EXPR representing the
        maximum index.

gcc/testsuite/ChangeLog:

        * g++.dg/cpp0x/new6.C: New test.
        * g++.dg/cpp2a/concepts-new1.C: New test.
---
  gcc/cp/constexpr.cc                        |  8 ++++++--
  gcc/cp/init.cc                             | 18 ++++++++----------
  gcc/testsuite/g++.dg/cpp0x/new6.C          |  9 +++++++++
  gcc/testsuite/g++.dg/cpp2a/concepts-new1.C | 13 +++++++++++++
  4 files changed, 36 insertions(+), 12 deletions(-)
  create mode 100644 gcc/testsuite/g++.dg/cpp0x/new6.C
  create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-new1.C

diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index aa2c14355f8..d38c4c80415 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -8538,9 +8538,9 @@ maybe_constant_value (tree t, tree decl /* = NULL_TREE */,
        t = mark_non_constant (t);
        return t;
      }
-  else if (CONSTANT_CLASS_P (t))
+  else if (CONSTANT_CLASS_OR_WRAPPER_P (t))
      /* No caching or evaluation needed.  */
-    return t;
+    return tree_strip_any_location_wrapper (t);
if (manifestly_const_eval != mce_unknown)
      return cxx_eval_outermost_constant_expr (t, true, true,
@@ -8631,6 +8631,10 @@ fold_non_dependent_expr_template (tree t, tsubst_flags_t 
complain,
          return t;
        }
+ if (CONSTANT_CLASS_OR_WRAPPER_P (t))
+       /* No evaluation needed.  */
+       return tree_strip_any_location_wrapper (t);
+
        if (cp_unevaluated_operand && !manifestly_const_eval)
        return t;
diff --git a/gcc/cp/init.cc b/gcc/cp/init.cc
index 705a5b3bdb6..574d2e2586c 100644
--- a/gcc/cp/init.cc
+++ b/gcc/cp/init.cc
@@ -3653,16 +3653,14 @@ build_new_1 (vec<tree, va_gc> **placement, tree type, 
tree nelts,
                  error ("parenthesized initializer in array new");
              return error_mark_node;
              }
-         init_expr
-           = build_vec_init (data_addr,
-                             cp_build_binary_op (input_location,
-                                                 MINUS_EXPR, outer_nelts,
-                                                 integer_one_node,
-                                                 complain),
-                             vecinit,
-                             explicit_value_init_p,
-                             /*from_array=*/0,
-                              complain);
+         tree maxindex = fold_build2_loc (input_location, MINUS_EXPR,
+                                          TREE_TYPE (outer_nelts),
+                                          outer_nelts,
+                                          build_one_cst (TREE_TYPE
+                                                         (outer_nelts)));
+         init_expr = build_vec_init (data_addr, maxindex, vecinit,
+                                     explicit_value_init_p, /*from_array=*/0,
+                                     complain);
        }
        else
        {
diff --git a/gcc/testsuite/g++.dg/cpp0x/new6.C 
b/gcc/testsuite/g++.dg/cpp0x/new6.C
new file mode 100644
index 00000000000..17a669b42d0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/new6.C
@@ -0,0 +1,9 @@
+// PR c++/108218
+// { dg-do compile { target c++11 } }
+
+template<class T>
+void f() {
+  decltype(new int[-1]) p; // { dg-error "negative" }
+}
+
+decltype(new int[-1]) q; // { dg-error "negative" }
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-new1.C 
b/gcc/testsuite/g++.dg/cpp2a/concepts-new1.C
new file mode 100644
index 00000000000..62007205108
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-new1.C
@@ -0,0 +1,13 @@
+// PR c++/108219
+// { dg-do compile { target c++20 } }
+
+template<class T>
+concept C = requires { new T[1]{{ 42 }}; };
+
+template<class T>
+concept D = requires { new T[2][1]{{{ 42 }}, {{ 42 }}}; };
+
+struct A { A(int); };
+
+static_assert(C<A>);
+static_assert(D<A>);

Reply via email to