aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorMarek Polacek <polacek@redhat.com>2020-09-05 20:50:32 -0400
committerMarek Polacek <polacek@redhat.com>2020-09-09 17:46:04 -0400
commit81de459ec7ccf46c3e5a776b0c13f01e989d9593 (patch)
tree8ebc8c775d581e334adb900d038370649a4606b7 /gcc
parentacbe30bbc884899da72df47d023ebde89f8f47f1 (diff)
downloadgcc-81de459ec7ccf46c3e5a776b0c13f01e989d9593.zip
gcc-81de459ec7ccf46c3e5a776b0c13f01e989d9593.tar.gz
gcc-81de459ec7ccf46c3e5a776b0c13f01e989d9593.tar.bz2
c++: Further tweaks for new-expression and paren-init [PR77841]
This patch corrects our handling of array new-expression with ()-init: new int[4](1, 2, 3, 4); should work even with the explicit array bound, and new char[3]("so_sad"); should cause an error, but we weren't giving any. Fixed by handling array new-expressions with ()-init in the same spot where we deduce the array bound in array new-expression. I'm now always passing STRING_CSTs to build_new_1 wrapped in { } which allowed me to remove the special handling of STRING_CSTs in build_new_1. And since the DIRECT_LIST_INIT_P block in build_new_1 calls digest_init, we report errors about too short arrays. reshape_init now does the {"foo"} -> "foo" transformation even for CONSTRUCTOR_IS_PAREN_INIT, so no need to do it in build_new. I took a stab at cp_complete_array_type's "FIXME: this code is duplicated from reshape_init", but calling reshape_init there, I ran into issues with has_designator_problem: when we reshape an already reshaped CONSTRUCTOR again, d.cur.index has been filled, so we think that we have a user-provided designator (though there was no designator in the source code), and report an error. gcc/cp/ChangeLog: PR c++/77841 * decl.c (reshape_init): If we're initializing a char array from a string-literal that is enclosed in braces, unwrap it. * init.c (build_new_1): Don't handle string-initializers here. (build_new): Handle new-expression with paren-init when the array bound is known. Always pass string constants to build_new_1 enclosed in braces. Don't handle string-initializers in any special way. gcc/testsuite/ChangeLog: PR c++/77841 * g++.old-deja/g++.ext/arrnew2.C: Expect the error only in C++17 and less. * g++.old-deja/g++.robertl/eb58.C: Adjust dg-error. * g++.old-deja/g++.robertl/eb63.C: Expect the error only in C++17 and less. * g++.dg/cpp2a/new-array5.C: New test. * g++.dg/cpp2a/paren-init36.C: New test. * g++.dg/cpp2a/paren-init37.C: New test. * g++.dg/pr84729.C: Adjust dg-error.
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/decl.c12
-rw-r--r--gcc/cp/init.c54
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/new-array5.C15
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/paren-init36.C14
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/paren-init37.C14
-rw-r--r--gcc/testsuite/g++.dg/pr84729.C2
-rw-r--r--gcc/testsuite/g++.old-deja/g++.ext/arrnew2.C2
-rw-r--r--gcc/testsuite/g++.old-deja/g++.robertl/eb58.C2
-rw-r--r--gcc/testsuite/g++.old-deja/g++.robertl/eb63.C2
9 files changed, 81 insertions, 36 deletions
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index ca1c8a4..ce97d19 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -6599,7 +6599,17 @@ reshape_init (tree type, tree init, tsubst_flags_t complain)
/* 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. */
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index 3268ae4..e84e985 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -3596,15 +3596,6 @@ build_new_1 (vec<tree, va_gc> **placement, tree type, tree nelts,
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)
@@ -3944,9 +3935,8 @@ build_new (location_t loc, vec<tree, va_gc> **placement, tree type,
}
/* 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 ())
@@ -3959,27 +3949,29 @@ build_new (location_t loc, vec<tree, va_gc> **placement, tree type,
/* 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
diff --git a/gcc/testsuite/g++.dg/cpp2a/new-array5.C b/gcc/testsuite/g++.dg/cpp2a/new-array5.C
new file mode 100644
index 0000000..2379079
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/new-array5.C
@@ -0,0 +1,15 @@
+// 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}};
diff --git a/gcc/testsuite/g++.dg/cpp2a/paren-init36.C b/gcc/testsuite/g++.dg/cpp2a/paren-init36.C
new file mode 100644
index 0000000..9962495
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/paren-init36.C
@@ -0,0 +1,14 @@
+// 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" }
diff --git a/gcc/testsuite/g++.dg/cpp2a/paren-init37.C b/gcc/testsuite/g++.dg/cpp2a/paren-init37.C
new file mode 100644
index 0000000..551a982
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/paren-init37.C
@@ -0,0 +1,14 @@
+// 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" }
diff --git a/gcc/testsuite/g++.dg/pr84729.C b/gcc/testsuite/g++.dg/pr84729.C
index e5d689e..530dbff 100644
--- a/gcc/testsuite/g++.dg/pr84729.C
+++ b/gcc/testsuite/g++.dg/pr84729.C
@@ -3,5 +3,5 @@
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" }
}
diff --git a/gcc/testsuite/g++.old-deja/g++.ext/arrnew2.C b/gcc/testsuite/g++.old-deja/g++.ext/arrnew2.C
index aff6b9c..fceb95e 100644
--- a/gcc/testsuite/g++.old-deja/g++.ext/arrnew2.C
+++ b/gcc/testsuite/g++.old-deja/g++.ext/arrnew2.C
@@ -1,7 +1,7 @@
// { 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;
diff --git a/gcc/testsuite/g++.old-deja/g++.robertl/eb58.C b/gcc/testsuite/g++.old-deja/g++.robertl/eb58.C
index d702296b..1e51e14 100644
--- a/gcc/testsuite/g++.old-deja/g++.robertl/eb58.C
+++ b/gcc/testsuite/g++.old-deja/g++.robertl/eb58.C
@@ -11,5 +11,5 @@ private:
main()
{
- A *list = new A[10](4); // { dg-error "parenthesized" }
+ A *list = new A[10](4); // { dg-error "parenthesized|could not convert" }
}
diff --git a/gcc/testsuite/g++.old-deja/g++.robertl/eb63.C b/gcc/testsuite/g++.old-deja/g++.robertl/eb63.C
index 653351b..50cf30f 100644
--- a/gcc/testsuite/g++.old-deja/g++.robertl/eb63.C
+++ b/gcc/testsuite/g++.old-deja/g++.robertl/eb63.C
@@ -13,5 +13,5 @@ public:
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 } }
}