Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk? -- >8 -- Unfortunately, my r15-1946 fix broke the attached testcase. In it, we no longer go into the /* P1009: Array size deduction in new-expressions. */ block, and instead generate an operator new [] call along with a loop in build_new_1, which we can't constexpr-evaluate. So this patch reverts r15-1946 and uses CONSTRUCTOR_IS_PAREN_INIT to distinguish between () and {} to fix the original testcase (anew7.C).
PR c++/115645 gcc/cp/ChangeLog: * call.cc (convert_like_internal) <case ck_user>: Don't report errors about calling an explicit constructor when the constructor was marked CONSTRUCTOR_IS_PAREN_INIT. * init.cc (build_new): Revert r15-1946. Set CONSTRUCTOR_IS_PAREN_INIT. (build_vec_init): Maybe set CONSTRUCTOR_IS_PAREN_INIT. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/constexpr-new23.C: New test. --- gcc/cp/call.cc | 2 ++ gcc/cp/init.cc | 17 ++++----- gcc/testsuite/g++.dg/cpp2a/constexpr-new23.C | 38 ++++++++++++++++++++ 3 files changed, 49 insertions(+), 8 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp2a/constexpr-new23.C diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc index a5d3426b70c..2d94d5e0d07 100644 --- a/gcc/cp/call.cc +++ b/gcc/cp/call.cc @@ -8592,6 +8592,8 @@ convert_like_internal (conversion *convs, tree expr, tree fn, int argnum, && BRACE_ENCLOSED_INITIALIZER_P (expr) /* Unless this is for direct-list-initialization. */ && (!CONSTRUCTOR_IS_DIRECT_INIT (expr) || convs->need_temporary_p) + /* And it wasn't a ()-init. */ + && !CONSTRUCTOR_IS_PAREN_INIT (expr) /* And in C++98 a default constructor can't be explicit. */ && cxx_dialect >= cxx11) { diff --git a/gcc/cp/init.cc b/gcc/cp/init.cc index e9561c146d7..4138a6077dd 100644 --- a/gcc/cp/init.cc +++ b/gcc/cp/init.cc @@ -4005,20 +4005,17 @@ build_new (location_t loc, vec<tree, va_gc> **placement, tree type, /* P1009: Array size deduction in new-expressions. */ const bool array_p = TREE_CODE (type) == ARRAY_TYPE; if (*init - /* If the array didn't specify its bound, we have to deduce it. */ - && ((array_p && !TYPE_DOMAIN (type)) - /* For C++20 array with parenthesized-init, we have to process - the parenthesized-list. But don't do it for (), which is - value-initialization, and INIT should stay empty. */ - || (cxx_dialect >= cxx20 - && (array_p || nelts) - && !(*init)->is_empty ()))) + /* If ARRAY_P, we have to deduce the array bound. For C++20 paren-init, + we have to process the parenthesized-list. But don't do it for (), + which is value-initialization, and INIT should stay empty. */ + && (array_p || (cxx_dialect >= cxx20 && nelts && !(*init)->is_empty ()))) { /* 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; + CONSTRUCTOR_IS_PAREN_INIT (ctor) = true; vec_safe_push (*init, ctor); } tree &elt = (**init)[0]; @@ -4735,6 +4732,9 @@ build_vec_init (tree base, tree maxindex, tree init, bool do_static_init = (DECL_P (obase) && TREE_STATIC (obase)); bool empty_list = false; + const bool paren_init_p = (init + && TREE_CODE (init) == CONSTRUCTOR + && CONSTRUCTOR_IS_PAREN_INIT (init)); if (init && BRACE_ENCLOSED_INITIALIZER_P (init) && CONSTRUCTOR_NELTS (init) == 0) /* Skip over the handling of non-empty init lists. */ @@ -4927,6 +4927,7 @@ build_vec_init (tree base, tree maxindex, tree init, || TREE_CODE (type) == ARRAY_TYPE)) { init = build_constructor (init_list_type_node, NULL); + CONSTRUCTOR_IS_PAREN_INIT (init) = paren_init_p; } else { diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-new23.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-new23.C new file mode 100644 index 00000000000..1abbef18fae --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-new23.C @@ -0,0 +1,38 @@ +// PR c++/115645 +// { dg-do compile { target c++20 } } + +using size_t = decltype(sizeof(0)); + +void* operator new(size_t, void* p) { return p; } +void* operator new[](size_t, void* p) { return p; } + +#define VERIFY(C) if (!(C)) throw + +namespace std { + template<typename T> + constexpr T* construct_at(T* p) + { + if constexpr (__is_array(T)) + return ::new((void*)p) T[1](); + else + return ::new((void*)p) T(); + } +} + +constexpr void +test_array() +{ + int arr[1] { 99 }; + std::construct_at(&arr); + VERIFY( arr[0] == 0 ); + + union U { + long long x = -1; + int arr[4]; + } u; + + auto p = std::construct_at(&u.arr); + VERIFY( (*p)[0] == 0 ); +} + +static_assert( [] { test_array(); return true; }() ); base-commit: 43a7ece873eba47a11c0b21b0068eee53740551a -- 2.45.2