aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2022-05-09 16:03:35 -0400
committerJason Merrill <jason@redhat.com>2022-05-10 01:05:51 -0400
commitbb2921ab84dba014f24be06663636c7fb1361474 (patch)
tree4916f6215202be7c12b436d43d04f050ec5f10ef /gcc
parent067fe66c8ba9b16feacf66fce9ae668091e42821 (diff)
downloadgcc-bb2921ab84dba014f24be06663636c7fb1361474.zip
gcc-bb2921ab84dba014f24be06663636c7fb1361474.tar.gz
gcc-bb2921ab84dba014f24be06663636c7fb1361474.tar.bz2
c++: fix arm-eabi crash building libstdc++ [PR105529]
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. 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.
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/cp-tree.h1
-rw-r--r--gcc/cp/decl.cc47
-rw-r--r--gcc/cp/optimize.cc9
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/constexpr-dtor13.C11
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/constexpr-dtor14.C13
5 files changed, 36 insertions, 45 deletions
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 7e50db0..9fb07d8 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 872b02d..9c9cf9f 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 13ab8b7..5c134fd 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 0000000..7b28961
--- /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 0000000..9c55121
--- /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'); }