]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++: fix arm-eabi crash building libstdc++ [PR105529]
authorJason Merrill <jason@redhat.com>
Mon, 9 May 2022 20:03:35 +0000 (16:03 -0400)
committerJason Merrill <jason@redhat.com>
Tue, 10 May 2022 05:05:51 +0000 (01:05 -0400)
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.

gcc/cp/cp-tree.h
gcc/cp/decl.cc
gcc/cp/optimize.cc
gcc/testsuite/g++.dg/cpp2a/constexpr-dtor13.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp2a/constexpr-dtor14.C [new file with mode: 0644]

index 7e50db0e35a0aaa2ae0ffd7e42762bbeca5617a6..9fb07d8ea394ac74bbd5647eb1257040c5f0c67b 100644 (file)
@@ -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);
index 872b02d55bdce569201a1879afe6017fc95db2a6..9c9cf9f7f6bc98c9b39b1d3d3623bde4ef370adb 100644 (file)
@@ -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)
 }
 
 \f
-/* 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
index 13ab8b7361ed8a64f796e0dcbbaad45600709671..5c134fd2fed7324fb198d9138b339caa2f7b2b02 100644 (file)
@@ -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 (file)
index 0000000..7b28961
--- /dev/null
@@ -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 (file)
index 0000000..9c55121
--- /dev/null
@@ -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'); }