/* Brace elision is not performed for a CONSTRUCTOR representing
parenthesized aggregate initialization. */
if (CONSTRUCTOR_IS_PAREN_INIT (init))
- return init;
+ {
+ tree elt = (*v)[0].value;
+ /* If we're initializing a char array from a string-literal that is
+ enclosed in braces, unwrap it here. */
+ if (TREE_CODE (type) == ARRAY_TYPE
+ && vec_safe_length (v) == 1
+ && char_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (type)))
+ && TREE_CODE (tree_strip_any_location_wrapper (elt)) == STRING_CST)
+ return elt;
+ return init;
+ }
/* Handle [dcl.init.list] direct-list-initialization from
single element of enumeration with a fixed underlying type. */
vecinit = digest_init (arraytype, vecinit, complain);
}
}
- /* This handles code like new char[]{"foo"}. */
- else if (len == 1
- && char_type_p (TYPE_MAIN_VARIANT (type))
- && TREE_CODE (tree_strip_any_location_wrapper ((**init)[0]))
- == STRING_CST)
- {
- vecinit = (**init)[0];
- STRIP_ANY_LOCATION_WRAPPER (vecinit);
- }
else if (*init)
{
if (complain & tf_error)
}
/* P1009: Array size deduction in new-expressions. */
- if (TREE_CODE (type) == ARRAY_TYPE
- && !TYPE_DOMAIN (type)
- && *init)
+ const bool array_p = TREE_CODE (type) == ARRAY_TYPE;
+ if (*init && (array_p || (nelts && cxx_dialect >= cxx20)))
{
/* This means we have 'new T[]()'. */
if ((*init)->is_empty ())
/* The C++20 'new T[](e_0, ..., e_k)' case allowed by P0960. */
if (!DIRECT_LIST_INIT_P (elt) && cxx_dialect >= cxx20)
{
- /* Handle new char[]("foo"). */
- if (vec_safe_length (*init) == 1
- && char_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (type)))
- && TREE_CODE (tree_strip_any_location_wrapper (elt))
- == STRING_CST)
- /* Leave it alone: the string should not be wrapped in {}. */;
- else
- {
- tree ctor = build_constructor_from_vec (init_list_type_node, *init);
- CONSTRUCTOR_IS_DIRECT_INIT (ctor) = true;
- CONSTRUCTOR_IS_PAREN_INIT (ctor) = true;
- elt = ctor;
- /* We've squashed all the vector elements into the first one;
- truncate the rest. */
- (*init)->truncate (1);
- }
+ tree ctor = build_constructor_from_vec (init_list_type_node, *init);
+ CONSTRUCTOR_IS_DIRECT_INIT (ctor) = true;
+ CONSTRUCTOR_IS_PAREN_INIT (ctor) = true;
+ elt = ctor;
+ /* We've squashed all the vector elements into the first one;
+ truncate the rest. */
+ (*init)->truncate (1);
}
/* Otherwise we should have 'new T[]{e_0, ..., e_k}'. */
- if (BRACE_ENCLOSED_INITIALIZER_P (elt))
- elt = reshape_init (type, elt, complain);
- cp_complete_array_type (&type, elt, /*do_default*/false);
+ if (array_p && !TYPE_DOMAIN (type))
+ {
+ /* We need to reshape before deducing the bounds to handle code like
+
+ struct S { int x, y; };
+ new S[]{1, 2, 3, 4};
+
+ which should deduce S[2]. But don't change ELT itself: we want to
+ pass a list-initializer to build_new_1, even for STRING_CSTs. */
+ tree e = elt;
+ if (BRACE_ENCLOSED_INITIALIZER_P (e))
+ e = reshape_init (type, e, complain);
+ cp_complete_array_type (&type, e, /*do_default*/false);
+ }
}
/* The type allocated must be complete. If the new-type-id was
--- /dev/null
+// PR c++/77841
+// { dg-do compile { target c++11 } }
+
+auto p1 = new int[][1]();
+auto p2 = new int[1][1]();
+#if __cpp_aggregate_paren_init
+auto p3 = new int[][4]({1, 2}, {3, 4});
+auto p4 = new int[2][4]({1, 2}, {3, 4});
+auto p5 = new int[2][1]({1, 2}, {3}); // { dg-error "too many initializers" "" { target c++20 } }
+#endif
+
+auto b1 = new int[][1]{};
+auto b2 = new int[1][1]{};
+auto b3 = new int[][4]{{1, 2}, {3, 4}};
+auto b4 = new int[2][4]{{1, 2}, {3, 4}};
--- /dev/null
+// PR c++/77841
+// { dg-do compile { target c++20 } }
+
+int *p0 = new int[1]();
+int *p1 = new int[1](1);
+int *p2 = new int[4](1, 2, 3, 4);
+int *p3 = new int[2](1, 2, 3, 4); // { dg-error "too many initializers" }
+
+char *c1 = new char[]("foo");
+char *c2 = new char[4]("foo");
+char *c3 = new char[]{"foo"};
+char *c4 = new char[4]{"foo"};
+char *c5 = new char[3]("so_sad"); // { dg-error "too long" }
+char *c6 = new char[3]{"so_sad"}; // { dg-error "too long" }
--- /dev/null
+// PR c++/77841
+// { dg-do compile { target c++20 } }
+
+int *p0 = new (int[1])();
+int *p1 = new (int[1])(1);
+int *p2 = new (int[4])(1, 2, 3, 4);
+int *p3 = new (int[2])(1, 2, 3, 4); // { dg-error "too many initializers" }
+
+char *c1 = new (char[])("foo");
+char *c2 = new (char[4])("foo");
+char *c3 = new (char[]){"foo"};
+char *c4 = new (char[4]){"foo"};
+char *c5 = new (char[3])("so_sad"); // { dg-error "too long" }
+char *c6 = new (char[3]){"so_sad"}; // { dg-error "too long" }
typedef int b[2];
void a() {
- new b(a); // { dg-error "parenthesized initializer in array new" }
+ new b(a); // { dg-error "parenthesized initializer in array new|invalid conversion" }
}
// { dg-do compile }
// { dg-options "-w -fpermissive" }
-int *foo = new int[1](42); // { dg-error "parenthesized" }
+int *foo = new int[1](42); // { dg-error "parenthesized" "" { target c++17_down } }
int main ()
{
return foo[0] != 42;
main()
{
- A *list = new A[10](4); // { dg-error "parenthesized" }
+ A *list = new A[10](4); // { dg-error "parenthesized|could not convert" }
}
main() {
A* a;
- a = new A[2](1,false); // { dg-error "parenthesized" }
+ a = new A[2](1,false); // { dg-error "parenthesized" "" { target c++17_down } }
}