diff options
author | Marek Polacek <polacek@redhat.com> | 2020-09-05 20:50:32 -0400 |
---|---|---|
committer | Marek Polacek <polacek@redhat.com> | 2020-09-09 17:46:04 -0400 |
commit | 81de459ec7ccf46c3e5a776b0c13f01e989d9593 (patch) | |
tree | 8ebc8c775d581e334adb900d038370649a4606b7 /gcc | |
parent | acbe30bbc884899da72df47d023ebde89f8f47f1 (diff) | |
download | gcc-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.c | 12 | ||||
-rw-r--r-- | gcc/cp/init.c | 54 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp2a/new-array5.C | 15 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp2a/paren-init36.C | 14 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp2a/paren-init37.C | 14 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/pr84729.C | 2 | ||||
-rw-r--r-- | gcc/testsuite/g++.old-deja/g++.ext/arrnew2.C | 2 | ||||
-rw-r--r-- | gcc/testsuite/g++.old-deja/g++.robertl/eb58.C | 2 | ||||
-rw-r--r-- | gcc/testsuite/g++.old-deja/g++.robertl/eb63.C | 2 |
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 } } } |