My recent change to cxx_eval_store_expression asserts that the target and value can only end up having different types in the case of an empty base; this was crashing arm-eabi compilers because in that ABI [cd]tors return *this, and weren't converting it to void* first.
This also shares the 'return this' code between the three places it occurs. Thanks to Marek for the tests. Tested x86_64-pc-linux-gnu and arm-sim, applying to trunk. PR c++/105529 gcc/cp/ChangeLog: * decl.cc (maybe_return_this): Replace... (finish_constructor_body, finish_destructor_body): ...these. (finish_function_body): Call it. * optimize.cc (build_delete_destructor_body): Call it. * cp-tree.h (maybe_return_this): Declare. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/constexpr-dtor13.C: New test. * g++.dg/cpp2a/constexpr-dtor14.C: New test. --- gcc/cp/cp-tree.h | 1 + gcc/cp/decl.cc | 47 ++++--------------- gcc/cp/optimize.cc | 9 +--- gcc/testsuite/g++.dg/cpp2a/constexpr-dtor13.C | 11 +++++ gcc/testsuite/g++.dg/cpp2a/constexpr-dtor14.C | 13 +++++ 5 files changed, 36 insertions(+), 45 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp2a/constexpr-dtor13.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/constexpr-dtor14.C diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 7e50db0e35a..9fb07d8ea39 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -6841,6 +6841,7 @@ extern tree lookup_enumerator (tree, tree); extern bool start_preparsed_function (tree, tree, int); extern bool start_function (cp_decl_specifier_seq *, const cp_declarator *, tree); +extern void maybe_return_this (void); extern tree begin_function_body (void); extern void finish_function_body (tree); extern tree outer_curly_brace_block (tree); diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc index 872b02d55bd..9c9cf9f7f6b 100644 --- a/gcc/cp/decl.cc +++ b/gcc/cp/decl.cc @@ -86,9 +86,7 @@ static tree check_initializer (tree, tree, int, vec<tree, va_gc> **); static void make_rtl_for_nonlocal_decl (tree, tree, const char *); static void copy_type_enum (tree , tree); static void check_function_type (tree, tree); -static void finish_constructor_body (void); static void begin_destructor_body (void); -static void finish_destructor_body (void); static void record_key_method_defined (tree); static tree create_array_type_for_decl (tree, tree, tree, location_t); static tree get_atexit_node (void); @@ -17502,22 +17500,20 @@ store_parm_decls (tree current_function_parms) } -/* Set the return value of the constructor (if present). */ +/* Set the return value of the [cd]tor if the ABI wants that. */ -static void -finish_constructor_body (void) +void +maybe_return_this (void) { - tree val; - tree exprstmt; - if (targetm.cxx.cdtor_returns_this ()) { - val = DECL_ARGUMENTS (current_function_decl); + /* Return the address of the object. */ + tree val = DECL_ARGUMENTS (current_function_decl); suppress_warning (val, OPT_Wuse_after_free); + val = fold_convert (TREE_TYPE (DECL_RESULT (current_function_decl)), val); val = build2 (MODIFY_EXPR, TREE_TYPE (val), DECL_RESULT (current_function_decl), val); - /* Return the address of the object. */ - exprstmt = build_stmt (input_location, RETURN_EXPR, val); + tree exprstmt = build_stmt (input_location, RETURN_EXPR, val); add_stmt (exprstmt); } } @@ -17590,28 +17586,6 @@ begin_destructor_body (void) } } -/* At the end of every destructor we generate code to delete the object if - necessary. Do that now. */ - -static void -finish_destructor_body (void) -{ - tree exprstmt; - - if (targetm.cxx.cdtor_returns_this ()) - { - tree val; - - val = DECL_ARGUMENTS (current_function_decl); - suppress_warning (val, OPT_Wuse_after_free); - val = build2 (MODIFY_EXPR, TREE_TYPE (val), - DECL_RESULT (current_function_decl), val); - /* Return the address of the object. */ - exprstmt = build_stmt (input_location, RETURN_EXPR, val); - add_stmt (exprstmt); - } -} - /* Do the necessary processing for the beginning of a function body, which in this case includes member-initializers, but not the catch clauses of a function-try-block. Currently, this means opening a binding level @@ -17662,10 +17636,9 @@ finish_function_body (tree compstmt) if (processing_template_decl) /* Do nothing now. */; - else if (DECL_CONSTRUCTOR_P (current_function_decl)) - finish_constructor_body (); - else if (DECL_DESTRUCTOR_P (current_function_decl)) - finish_destructor_body (); + else if (DECL_CONSTRUCTOR_P (current_function_decl) + || DECL_DESTRUCTOR_P (current_function_decl)) + maybe_return_this (); } /* Given a function, returns the BLOCK corresponding to the outermost level diff --git a/gcc/cp/optimize.cc b/gcc/cp/optimize.cc index 13ab8b7361e..5c134fd2fed 100644 --- a/gcc/cp/optimize.cc +++ b/gcc/cp/optimize.cc @@ -163,14 +163,7 @@ build_delete_destructor_body (tree delete_dtor, tree complete_dtor) /* Return the address of the object. ??? How is it useful to return an invalid address? */ - if (targetm.cxx.cdtor_returns_this ()) - { - tree val = DECL_ARGUMENTS (delete_dtor); - suppress_warning (val, OPT_Wuse_after_free); - val = build2 (MODIFY_EXPR, TREE_TYPE (val), - DECL_RESULT (delete_dtor), val); - add_stmt (build_stmt (0, RETURN_EXPR, val)); - } + maybe_return_this (); } /* Return name of comdat group for complete and base ctor (or dtor) diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-dtor13.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-dtor13.C new file mode 100644 index 00000000000..7b289614fc1 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-dtor13.C @@ -0,0 +1,11 @@ +// PR c++/105529 +// { dg-do compile { target c++20 } } +// { dg-options "-O" } + +struct allocator { + constexpr ~allocator() {} +}; +struct S { + S(int, int, allocator = allocator()); +}; +void to_string() { S(0, '\0'); } diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-dtor14.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-dtor14.C new file mode 100644 index 00000000000..9c55121eb8a --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-dtor14.C @@ -0,0 +1,13 @@ +// PR c++/105529 +// { dg-do compile { target c++20 } } +// { dg-options "-O" } +// Like constexpr-dtor13.C, except that allocator is not an empty class. + +struct allocator { + constexpr ~allocator() {} + int a; +}; +struct S { + S(int, int, allocator = allocator()); +}; +void to_string() { S(0, '\0'); } base-commit: 0c7bce0ac184c057bacad9c8e615ce82923835fd -- 2.27.0