Re: [PATCH] c++: Implement P1009: Array size deduction in new-expressions.
On 8/20/20 4:22 PM, Marek Polacek wrote: This patch implements C++20 P1009, allowing code like new double[]{1,2,3}; // array bound will be deduced Since this proposal makes the initialization rules more consistent, it is applied to all previous versions of C++ (thus, effectively, all the way back to C++11). My patch is based on Jason's patch that handled the basic case. I've extended it to work with ()-init and also the string literal case. Further testing revealed that to handle stuff like new int[]{t...}; in a template, we have to consider such a NEW_EXPR type-dependent. Obviously, we first have to expand the pack to be able to deduce the number of elements in the array. Curiously, while implementing this proposal, I noticed that we fail to accept new char[4]{"abc"}; so I've assigned 77841 to self. I think the fix will depend on the build_new_1 hunk in this patch. Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk? gcc/cp/ChangeLog: PR c++/93529 * init.c (build_new_1): Handle new char[]{"foo"}. (build_new): Deduce the array size in new-expression if not present. Handle ()-init. Handle initializing an array from a string literal. * parser.c (cp_parser_new_type_id): Leave [] alone. (cp_parser_direct_new_declarator): Allow []. * pt.c (type_dependent_expression_p): In a NEW_EXPR, consider array types whose dimension has to be deduced type-dependent. gcc/testsuite/ChangeLog: PR c++/93529 * g++.dg/cpp0x/sfinae4.C: Adjust expected result after P1009. * g++.dg/cpp2a/new-array1.C: New test. * g++.dg/cpp2a/new-array2.C: New test. * g++.dg/cpp2a/new-array3.C: New test. Co-authored-by: Jason Merrill --- gcc/cp/init.c | 54 ++- gcc/cp/parser.c | 11 ++-- gcc/cp/pt.c | 4 ++ gcc/testsuite/g++.dg/cpp0x/sfinae4.C| 8 ++- gcc/testsuite/g++.dg/cpp2a/new-array1.C | 70 + gcc/testsuite/g++.dg/cpp2a/new-array2.C | 22 gcc/testsuite/g++.dg/cpp2a/new-array3.C | 17 ++ 7 files changed, 180 insertions(+), 6 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp2a/new-array1.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/new-array2.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/new-array3.C diff --git a/gcc/cp/init.c b/gcc/cp/init.c index 872c23453fd..ae1177079e4 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -3559,8 +3559,8 @@ build_new_1 (vec **placement, tree type, tree nelts, else if (array_p) { tree vecinit = NULL_TREE; - if (vec_safe_length (*init) == 1 - && DIRECT_LIST_INIT_P ((**init)[0])) + const size_t len = vec_safe_length (*init); + if (len == 1 && DIRECT_LIST_INIT_P ((**init)[0])) { vecinit = (**init)[0]; if (CONSTRUCTOR_NELTS (vecinit) == 0) @@ -3578,6 +3578,15 @@ build_new_1 (vec **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) @@ -3917,6 +3926,47 @@ build_new (location_t loc, vec **placement, tree type, return error_mark_node; } + /* P1009: Array size deduction in new-expressions. */ + if (TREE_CODE (type) == ARRAY_TYPE + && !TYPE_DOMAIN (type) + && *init) +{ + /* 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; + vec_safe_push (*init, ctor); + } + tree = (**init)[0]; + /* 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 + { + /* Create a CONSTRUCTOR from the vector INIT. */ + tree list = build_tree_list_vec (*init); + tree ctor = build_constructor_from_list (init_list_type_node, list); + CONSTRUCTOR_IS_DIRECT_INIT (ctor) = true; + CONSTRUCTOR_IS_PAREN_INIT
[PATCH] c++: Implement P1009: Array size deduction in new-expressions.
This patch implements C++20 P1009, allowing code like new double[]{1,2,3}; // array bound will be deduced Since this proposal makes the initialization rules more consistent, it is applied to all previous versions of C++ (thus, effectively, all the way back to C++11). My patch is based on Jason's patch that handled the basic case. I've extended it to work with ()-init and also the string literal case. Further testing revealed that to handle stuff like new int[]{t...}; in a template, we have to consider such a NEW_EXPR type-dependent. Obviously, we first have to expand the pack to be able to deduce the number of elements in the array. Curiously, while implementing this proposal, I noticed that we fail to accept new char[4]{"abc"}; so I've assigned 77841 to self. I think the fix will depend on the build_new_1 hunk in this patch. Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk? gcc/cp/ChangeLog: PR c++/93529 * init.c (build_new_1): Handle new char[]{"foo"}. (build_new): Deduce the array size in new-expression if not present. Handle ()-init. Handle initializing an array from a string literal. * parser.c (cp_parser_new_type_id): Leave [] alone. (cp_parser_direct_new_declarator): Allow []. * pt.c (type_dependent_expression_p): In a NEW_EXPR, consider array types whose dimension has to be deduced type-dependent. gcc/testsuite/ChangeLog: PR c++/93529 * g++.dg/cpp0x/sfinae4.C: Adjust expected result after P1009. * g++.dg/cpp2a/new-array1.C: New test. * g++.dg/cpp2a/new-array2.C: New test. * g++.dg/cpp2a/new-array3.C: New test. Co-authored-by: Jason Merrill --- gcc/cp/init.c | 54 ++- gcc/cp/parser.c | 11 ++-- gcc/cp/pt.c | 4 ++ gcc/testsuite/g++.dg/cpp0x/sfinae4.C| 8 ++- gcc/testsuite/g++.dg/cpp2a/new-array1.C | 70 + gcc/testsuite/g++.dg/cpp2a/new-array2.C | 22 gcc/testsuite/g++.dg/cpp2a/new-array3.C | 17 ++ 7 files changed, 180 insertions(+), 6 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp2a/new-array1.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/new-array2.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/new-array3.C diff --git a/gcc/cp/init.c b/gcc/cp/init.c index 872c23453fd..ae1177079e4 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -3559,8 +3559,8 @@ build_new_1 (vec **placement, tree type, tree nelts, else if (array_p) { tree vecinit = NULL_TREE; - if (vec_safe_length (*init) == 1 - && DIRECT_LIST_INIT_P ((**init)[0])) + const size_t len = vec_safe_length (*init); + if (len == 1 && DIRECT_LIST_INIT_P ((**init)[0])) { vecinit = (**init)[0]; if (CONSTRUCTOR_NELTS (vecinit) == 0) @@ -3578,6 +3578,15 @@ build_new_1 (vec **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) @@ -3917,6 +3926,47 @@ build_new (location_t loc, vec **placement, tree type, return error_mark_node; } + /* P1009: Array size deduction in new-expressions. */ + if (TREE_CODE (type) == ARRAY_TYPE + && !TYPE_DOMAIN (type) + && *init) +{ + /* 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; + vec_safe_push (*init, ctor); + } + tree = (**init)[0]; + /* 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 + { + /* Create a CONSTRUCTOR from the vector INIT. */ + tree list = build_tree_list_vec (*init); + tree ctor = build_constructor_from_list (init_list_type_node, list); + CONSTRUCTOR_IS_DIRECT_INIT (ctor) = true; + CONSTRUCTOR_IS_PAREN_INIT (ctor) = true; + elt = ctor; + /* We've