Message ID | 20200901161032.4095949-1-polacek@redhat.com |
---|---|
State | New |
Headers | show |
Series | c++: Allow new char[4]{"foo"} [PR77841] | expand |
On 9/1/20 12:10 PM, Marek Polacek wrote: > Currently, we allow new char[]{"foo"}, but not new char[4]{"foo"}. > We should accept the latter too: [dcl.init.list]p3.3 says to treat > this as [dcl.init.string]. > > We were rejecting this code because we never called reshape_init before > the digest_init in build_new_1. reshape_init handles [dcl.init.string] > by unwrapping the STRING_CST from its enclosing { }, and digest_init > assumes that reshape_init has been called for aggregates anyway, and an > array is an aggregate. > > Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk? > > gcc/cp/ChangeLog: > > PR c++/77841 > * init.c (build_new_1): Call reshape_init. > > gcc/testsuite/ChangeLog: > > PR c++/77841 > * g++.dg/cpp0x/initlist-new4.C: New test. > --- > gcc/cp/init.c | 6 ++++++ > gcc/testsuite/g++.dg/cpp0x/initlist-new4.C | 6 ++++++ > 2 files changed, 12 insertions(+) > create mode 100644 gcc/testsuite/g++.dg/cpp0x/initlist-new4.C > > diff --git a/gcc/cp/init.c b/gcc/cp/init.c > index 360ab8c0b52..d4540db3605 100644 > --- a/gcc/cp/init.c > +++ b/gcc/cp/init.c > @@ -3575,6 +3575,12 @@ build_new_1 (vec<tree, va_gc> **placement, tree type, tree nelts, > /* We'll check the length at runtime. */ > domain = NULL_TREE; > arraytype = build_cplus_array_type (type, domain); > + /* If we have new char[4]{"foo"}, we have to reshape > + so that the STRING_CST isn't wrapped in { }. */ > + vecinit = reshape_init (arraytype, vecinit, complain); > + /* The middle end doesn't cope with the location wrapper > + around a STRING_CST. */ > + STRIP_ANY_LOCATION_WRAPPER (vecinit); > vecinit = digest_init (arraytype, vecinit, complain); > } This is OK, but now I wonder why your earlier addition, > /* 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); > } isn't handled by the block you're changing in this patch. Why isn't DIRECT_LIST_INIT_P true for new char[]{"foo"}? Jason
On Tue, Sep 01, 2020 at 03:27:36PM -0400, Jason Merrill via Gcc-patches wrote: > On 9/1/20 12:10 PM, Marek Polacek wrote: > > Currently, we allow new char[]{"foo"}, but not new char[4]{"foo"}. > > We should accept the latter too: [dcl.init.list]p3.3 says to treat > > this as [dcl.init.string]. > > > > We were rejecting this code because we never called reshape_init before > > the digest_init in build_new_1. reshape_init handles [dcl.init.string] > > by unwrapping the STRING_CST from its enclosing { }, and digest_init > > assumes that reshape_init has been called for aggregates anyway, and an > > array is an aggregate. > > > > Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk? > > > > gcc/cp/ChangeLog: > > > > PR c++/77841 > > * init.c (build_new_1): Call reshape_init. > > > > gcc/testsuite/ChangeLog: > > > > PR c++/77841 > > * g++.dg/cpp0x/initlist-new4.C: New test. > > --- > > gcc/cp/init.c | 6 ++++++ > > gcc/testsuite/g++.dg/cpp0x/initlist-new4.C | 6 ++++++ > > 2 files changed, 12 insertions(+) > > create mode 100644 gcc/testsuite/g++.dg/cpp0x/initlist-new4.C > > > > diff --git a/gcc/cp/init.c b/gcc/cp/init.c > > index 360ab8c0b52..d4540db3605 100644 > > --- a/gcc/cp/init.c > > +++ b/gcc/cp/init.c > > @@ -3575,6 +3575,12 @@ build_new_1 (vec<tree, va_gc> **placement, tree type, tree nelts, > > /* We'll check the length at runtime. */ > > domain = NULL_TREE; > > arraytype = build_cplus_array_type (type, domain); > > + /* If we have new char[4]{"foo"}, we have to reshape > > + so that the STRING_CST isn't wrapped in { }. */ > > + vecinit = reshape_init (arraytype, vecinit, complain); > > + /* The middle end doesn't cope with the location wrapper > > + around a STRING_CST. */ > > + STRIP_ANY_LOCATION_WRAPPER (vecinit); > > vecinit = digest_init (arraytype, vecinit, complain); > > } > > This is OK, but now I wonder why your earlier addition, > > > /* 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); > > } > > isn't handled by the block you're changing in this patch. Why isn't > DIRECT_LIST_INIT_P true for new char[]{"foo"}? Yes, I was hoping this hunk would handle the new char[4]{"foo"} case too, but for new char[]{"foo"} DIRECT_LIST_INIT_P is false because earlier in build_new we called reshape_init: 4011 /* Otherwise we should have 'new T[]{e_0, ..., e_k}'. */ 4012 if (BRACE_ENCLOSED_INITIALIZER_P (elt)) 4013 elt = reshape_init (type, elt, complain); which unwraps the { } from {"foo"}, so it's no longer a list init. We won't get there with new char[4]{"foo"} because TREE_CODE (type) will not be ARRAY_TYPE; instead, nelts is set to INTEGER_CST 4 when we know the array bound. I could make it so that we call reshape_init in build_new for the [4] case too, but it was uglier than this fix. Should I go ahead with this patch as-is or would you prefer any changes? Marek
On 9/1/20 3:41 PM, Marek Polacek wrote: > On Tue, Sep 01, 2020 at 03:27:36PM -0400, Jason Merrill via Gcc-patches wrote: >> On 9/1/20 12:10 PM, Marek Polacek wrote: >>> Currently, we allow new char[]{"foo"}, but not new char[4]{"foo"}. >>> We should accept the latter too: [dcl.init.list]p3.3 says to treat >>> this as [dcl.init.string]. >>> >>> We were rejecting this code because we never called reshape_init before >>> the digest_init in build_new_1. reshape_init handles [dcl.init.string] >>> by unwrapping the STRING_CST from its enclosing { }, and digest_init >>> assumes that reshape_init has been called for aggregates anyway, and an >>> array is an aggregate. >>> >>> Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk? >>> >>> gcc/cp/ChangeLog: >>> >>> PR c++/77841 >>> * init.c (build_new_1): Call reshape_init. >>> >>> gcc/testsuite/ChangeLog: >>> >>> PR c++/77841 >>> * g++.dg/cpp0x/initlist-new4.C: New test. >>> --- >>> gcc/cp/init.c | 6 ++++++ >>> gcc/testsuite/g++.dg/cpp0x/initlist-new4.C | 6 ++++++ >>> 2 files changed, 12 insertions(+) >>> create mode 100644 gcc/testsuite/g++.dg/cpp0x/initlist-new4.C >>> >>> diff --git a/gcc/cp/init.c b/gcc/cp/init.c >>> index 360ab8c0b52..d4540db3605 100644 >>> --- a/gcc/cp/init.c >>> +++ b/gcc/cp/init.c >>> @@ -3575,6 +3575,12 @@ build_new_1 (vec<tree, va_gc> **placement, tree type, tree nelts, >>> /* We'll check the length at runtime. */ >>> domain = NULL_TREE; >>> arraytype = build_cplus_array_type (type, domain); >>> + /* If we have new char[4]{"foo"}, we have to reshape >>> + so that the STRING_CST isn't wrapped in { }. */ >>> + vecinit = reshape_init (arraytype, vecinit, complain); >>> + /* The middle end doesn't cope with the location wrapper >>> + around a STRING_CST. */ >>> + STRIP_ANY_LOCATION_WRAPPER (vecinit); >>> vecinit = digest_init (arraytype, vecinit, complain); >>> } >> >> This is OK, but now I wonder why your earlier addition, >> >>> /* 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); >>> } >> >> isn't handled by the block you're changing in this patch. Why isn't >> DIRECT_LIST_INIT_P true for new char[]{"foo"}? > > Yes, I was hoping this hunk would handle the new char[4]{"foo"} case too, > but for new char[]{"foo"} DIRECT_LIST_INIT_P is false because earlier in > build_new we called reshape_init: > > 4011 /* Otherwise we should have 'new T[]{e_0, ..., e_k}'. */ > 4012 if (BRACE_ENCLOSED_INITIALIZER_P (elt)) > 4013 elt = reshape_init (type, elt, complain); > > which unwraps the { } from {"foo"}, so it's no longer a list init. Ah, I see. > We > won't get there with new char[4]{"foo"} because TREE_CODE (type) will > not be ARRAY_TYPE; instead, nelts is set to INTEGER_CST 4 when we know > the array bound. > > I could make it so that we call reshape_init in build_new for the [4] > case too, but it was uglier than this fix. > > Should I go ahead with this patch as-is or would you prefer any changes? Go ahead with this for now, but I notice that we also still don't support new char[4](1,2,3,4); because the handling of parenthesized-init is limited to the deduced array size case. It would be nice to find a way to combine the two places that we're messing with array initializers. Jason
On Tue, Sep 01, 2020 at 05:33:43PM -0400, Jason Merrill via Gcc-patches wrote: > On 9/1/20 3:41 PM, Marek Polacek wrote: > > On Tue, Sep 01, 2020 at 03:27:36PM -0400, Jason Merrill via Gcc-patches wrote: > > > On 9/1/20 12:10 PM, Marek Polacek wrote: > > > > Currently, we allow new char[]{"foo"}, but not new char[4]{"foo"}. > > > > We should accept the latter too: [dcl.init.list]p3.3 says to treat > > > > this as [dcl.init.string]. > > > > > > > > We were rejecting this code because we never called reshape_init before > > > > the digest_init in build_new_1. reshape_init handles [dcl.init.string] > > > > by unwrapping the STRING_CST from its enclosing { }, and digest_init > > > > assumes that reshape_init has been called for aggregates anyway, and an > > > > array is an aggregate. > > > > > > > > Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk? > > > > > > > > gcc/cp/ChangeLog: > > > > > > > > PR c++/77841 > > > > * init.c (build_new_1): Call reshape_init. > > > > > > > > gcc/testsuite/ChangeLog: > > > > > > > > PR c++/77841 > > > > * g++.dg/cpp0x/initlist-new4.C: New test. > > > > --- > > > > gcc/cp/init.c | 6 ++++++ > > > > gcc/testsuite/g++.dg/cpp0x/initlist-new4.C | 6 ++++++ > > > > 2 files changed, 12 insertions(+) > > > > create mode 100644 gcc/testsuite/g++.dg/cpp0x/initlist-new4.C > > > > > > > > diff --git a/gcc/cp/init.c b/gcc/cp/init.c > > > > index 360ab8c0b52..d4540db3605 100644 > > > > --- a/gcc/cp/init.c > > > > +++ b/gcc/cp/init.c > > > > @@ -3575,6 +3575,12 @@ build_new_1 (vec<tree, va_gc> **placement, tree type, tree nelts, > > > > /* We'll check the length at runtime. */ > > > > domain = NULL_TREE; > > > > arraytype = build_cplus_array_type (type, domain); > > > > + /* If we have new char[4]{"foo"}, we have to reshape > > > > + so that the STRING_CST isn't wrapped in { }. */ > > > > + vecinit = reshape_init (arraytype, vecinit, complain); > > > > + /* The middle end doesn't cope with the location wrapper > > > > + around a STRING_CST. */ > > > > + STRIP_ANY_LOCATION_WRAPPER (vecinit); > > > > vecinit = digest_init (arraytype, vecinit, complain); > > > > } > > > > > > This is OK, but now I wonder why your earlier addition, > > > > > > > /* 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); > > > > } > > > > > > isn't handled by the block you're changing in this patch. Why isn't > > > DIRECT_LIST_INIT_P true for new char[]{"foo"}? > > > > Yes, I was hoping this hunk would handle the new char[4]{"foo"} case too, > > but for new char[]{"foo"} DIRECT_LIST_INIT_P is false because earlier in > > build_new we called reshape_init: > > > > 4011 /* Otherwise we should have 'new T[]{e_0, ..., e_k}'. */ > > 4012 if (BRACE_ENCLOSED_INITIALIZER_P (elt)) > > 4013 elt = reshape_init (type, elt, complain); > > > > which unwraps the { } from {"foo"}, so it's no longer a list init. > > Ah, I see. > > > We > > won't get there with new char[4]{"foo"} because TREE_CODE (type) will > > not be ARRAY_TYPE; instead, nelts is set to INTEGER_CST 4 when we know > > the array bound. > > > > I could make it so that we call reshape_init in build_new for the [4] > > case too, but it was uglier than this fix. > > > > Should I go ahead with this patch as-is or would you prefer any changes? > > Go ahead with this for now, but I notice that we also still don't support Pushed. > new char[4](1,2,3,4); > > because the handling of parenthesized-init is limited to the deduced array > size case. Ah, that should work. And conversely here I'd expect an error: new char[2]("so_sad"); but we don't give any. > It would be nice to find a way to combine the two places that we're messing > with array initializers. I'll look into that. Thanks, Marek
diff --git a/gcc/cp/init.c b/gcc/cp/init.c index 360ab8c0b52..d4540db3605 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -3575,6 +3575,12 @@ build_new_1 (vec<tree, va_gc> **placement, tree type, tree nelts, /* We'll check the length at runtime. */ domain = NULL_TREE; arraytype = build_cplus_array_type (type, domain); + /* If we have new char[4]{"foo"}, we have to reshape + so that the STRING_CST isn't wrapped in { }. */ + vecinit = reshape_init (arraytype, vecinit, complain); + /* The middle end doesn't cope with the location wrapper + around a STRING_CST. */ + STRIP_ANY_LOCATION_WRAPPER (vecinit); vecinit = digest_init (arraytype, vecinit, complain); } } diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist-new4.C b/gcc/testsuite/g++.dg/cpp0x/initlist-new4.C new file mode 100644 index 00000000000..d7b418426bb --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/initlist-new4.C @@ -0,0 +1,6 @@ +// PR c++/77841 +// { dg-do compile { target c++11 } } + +char *p1 = new char[4]{"foo"}; +char *p2 = new char[5]{"foo"}; +char *p3 = new char[3]{"foo"}; // { dg-error "too long" }