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

-- >8 --
Unfortunately, my r15-1946 fix broke the attached testcase.  In it,
we no longer go into the
  /* P1009: Array size deduction in new-expressions.  */
block, and instead generate an operator new [] call along with a loop
in build_new_1, which we can't constexpr-evaluate.  So this patch
reverts r15-1946 and uses CONSTRUCTOR_IS_PAREN_INIT to distinguish
between () and {} to fix the original testcase (anew7.C).

        PR c++/115645

gcc/cp/ChangeLog:

        * call.cc (convert_like_internal) <case ck_user>: Don't report errors
        about calling an explicit constructor when the constructor was marked
        CONSTRUCTOR_IS_PAREN_INIT.
        * init.cc (build_new): Revert r15-1946.  Set CONSTRUCTOR_IS_PAREN_INIT.
        (build_vec_init): Maybe set CONSTRUCTOR_IS_PAREN_INIT.

gcc/testsuite/ChangeLog:

        * g++.dg/cpp2a/constexpr-new23.C: New test.
---
 gcc/cp/call.cc                               |  2 ++
 gcc/cp/init.cc                               | 17 ++++-----
 gcc/testsuite/g++.dg/cpp2a/constexpr-new23.C | 38 ++++++++++++++++++++
 3 files changed, 49 insertions(+), 8 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/constexpr-new23.C

diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
index a5d3426b70c..2d94d5e0d07 100644
--- a/gcc/cp/call.cc
+++ b/gcc/cp/call.cc
@@ -8592,6 +8592,8 @@ convert_like_internal (conversion *convs, tree expr, tree 
fn, int argnum,
            && BRACE_ENCLOSED_INITIALIZER_P (expr)
            /* Unless this is for direct-list-initialization.  */
            && (!CONSTRUCTOR_IS_DIRECT_INIT (expr) || convs->need_temporary_p)
+           /* And it wasn't a ()-init.  */
+           && !CONSTRUCTOR_IS_PAREN_INIT (expr)
            /* And in C++98 a default constructor can't be explicit.  */
            && cxx_dialect >= cxx11)
          {
diff --git a/gcc/cp/init.cc b/gcc/cp/init.cc
index e9561c146d7..4138a6077dd 100644
--- a/gcc/cp/init.cc
+++ b/gcc/cp/init.cc
@@ -4005,20 +4005,17 @@ build_new (location_t loc, vec<tree, va_gc> 
**placement, tree type,
   /* P1009: Array size deduction in new-expressions.  */
   const bool array_p = TREE_CODE (type) == ARRAY_TYPE;
   if (*init
-      /* If the array didn't specify its bound, we have to deduce it.  */
-      && ((array_p && !TYPE_DOMAIN (type))
-         /* For C++20 array with parenthesized-init, we have to process
-            the parenthesized-list.  But don't do it for (), which is
-            value-initialization, and INIT should stay empty.  */
-         || (cxx_dialect >= cxx20
-             && (array_p || nelts)
-             && !(*init)->is_empty ())))
+      /* If ARRAY_P, we have to deduce the array bound.  For C++20 paren-init,
+        we have to process the parenthesized-list.  But don't do it for (),
+        which is value-initialization, and INIT should stay empty.  */
+      && (array_p || (cxx_dialect >= cxx20 && nelts && !(*init)->is_empty ())))
     {
       /* This means we have 'new T[]()'.  */
       if ((*init)->is_empty ())
        {
          tree ctor = build_constructor (init_list_type_node, NULL);
          CONSTRUCTOR_IS_DIRECT_INIT (ctor) = true;
+         CONSTRUCTOR_IS_PAREN_INIT (ctor) = true;
          vec_safe_push (*init, ctor);
        }
       tree &elt = (**init)[0];
@@ -4735,6 +4732,9 @@ build_vec_init (tree base, tree maxindex, tree init,
   bool do_static_init = (DECL_P (obase) && TREE_STATIC (obase));
 
   bool empty_list = false;
+  const bool paren_init_p = (init
+                            && TREE_CODE (init) == CONSTRUCTOR
+                            && CONSTRUCTOR_IS_PAREN_INIT (init));
   if (init && BRACE_ENCLOSED_INITIALIZER_P (init)
       && CONSTRUCTOR_NELTS (init) == 0)
     /* Skip over the handling of non-empty init lists.  */
@@ -4927,6 +4927,7 @@ build_vec_init (tree base, tree maxindex, tree init,
                  || TREE_CODE (type) == ARRAY_TYPE))
            {
              init = build_constructor (init_list_type_node, NULL);
+             CONSTRUCTOR_IS_PAREN_INIT (init) = paren_init_p;
            }
          else
            {
diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-new23.C 
b/gcc/testsuite/g++.dg/cpp2a/constexpr-new23.C
new file mode 100644
index 00000000000..1abbef18fae
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-new23.C
@@ -0,0 +1,38 @@
+// PR c++/115645
+// { dg-do compile { target c++20 } }
+
+using size_t = decltype(sizeof(0));
+
+void* operator new(size_t, void* p) { return p; }
+void* operator new[](size_t, void* p) { return p; }
+
+#define VERIFY(C) if (!(C)) throw
+
+namespace std {
+  template<typename T>
+    constexpr T* construct_at(T* p)
+    {
+      if constexpr (__is_array(T))
+        return ::new((void*)p) T[1]();
+      else
+        return ::new((void*)p) T();
+    }
+}
+
+constexpr void
+test_array()
+{
+  int arr[1] { 99 };
+  std::construct_at(&arr);
+  VERIFY( arr[0] == 0 );
+
+  union U {
+    long long x = -1;
+    int arr[4];
+  } u;
+
+  auto p = std::construct_at(&u.arr);
+  VERIFY( (*p)[0] == 0 );
+}
+
+static_assert( [] { test_array(); return true; }() );

base-commit: 43a7ece873eba47a11c0b21b0068eee53740551a
-- 
2.45.2

Reply via email to