diff mbox series

[pushed] c++: fix arm-eabi crash building libstdc++ [PR105529]

Message ID 20220510050532.3301176-1-jason@redhat.com
State New
Headers show
Series [pushed] c++: fix arm-eabi crash building libstdc++ [PR105529] | expand

Commit Message

Jason Merrill May 10, 2022, 5:05 a.m. UTC
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


base-commit: 0c7bce0ac184c057bacad9c8e615ce82923835fd
diff mbox series

Patch

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'); }