aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2007-09-05 21:24:59 -0400
committerJason Merrill <jason@gcc.gnu.org>2007-09-05 21:24:59 -0400
commit6f06d231a09f1ac7facc006684f4cfdcb0d35194 (patch)
treeb083a51d2031960784caa354c53787eb62f3271a /gcc
parentdb44b39f4f9a464b9277dc5bbc1fba362a954ec0 (diff)
downloadgcc-6f06d231a09f1ac7facc006684f4cfdcb0d35194.zip
gcc-6f06d231a09f1ac7facc006684f4cfdcb0d35194.tar.gz
gcc-6f06d231a09f1ac7facc006684f4cfdcb0d35194.tar.bz2
re PR c++/15097 (code generator problem with ::delete and multiple inheritance and virtual deconstructs)
PR c++/15097 * init.c (build_delete): Use build_headof to get the address of the complete object if we aren't using the deleting destructor. * rtti.c (build_headof): No longer static. * cp-tree.h: Declare it. From-SVN: r128172
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/ChangeLog11
-rw-r--r--gcc/cp/cp-tree.h1
-rw-r--r--gcc/cp/init.c8
-rw-r--r--gcc/cp/rtti.c3
-rw-r--r--gcc/testsuite/g++.dg/init/delete2.C55
5 files changed, 75 insertions, 3 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index b8fb971..a32ecdb 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,11 @@
+2007-09-05 Jason Merrill <jason@redhat.com>
+
+ PR c++/15097
+ * init.c (build_delete): Use build_headof to get the address of the
+ complete object if we aren't using the deleting destructor.
+ * rtti.c (build_headof): No longer static.
+ * cp-tree.h: Declare it.
+
2007-09-06 Jakub Jelinek <jakub@redhat.com>
* decl.c (duplicate_decls): Set TREE_NOTHROW on __builtin_XX
@@ -28,6 +36,9 @@
2007-09-04 Jason Merrill <jason@redhat.com>
+ * except.c (initialize_handler_parm): Use
+ fold_build_cleanup_point_expr.
+
PR c++/31419
* call.c (reference_binding): Don't look for user-defined conversions
to the same type.
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 71f401f..9bd8ed2 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -4481,6 +4481,7 @@ extern void init_rtti_processing (void);
extern tree build_typeid (tree);
extern tree get_tinfo_decl (tree);
extern tree get_typeid (tree);
+extern tree build_headof (tree);
extern tree build_dynamic_cast (tree, tree);
extern void emit_support_tinfos (void);
extern bool emit_tinfo_decl (tree);
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index b46d687..1aa732c 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -2866,6 +2866,7 @@ build_delete (tree type, tree addr, special_function_kind auto_delete,
}
else
{
+ tree head = NULL_TREE;
tree do_delete = NULL_TREE;
tree ifexp;
@@ -2879,8 +2880,9 @@ build_delete (tree type, tree addr, special_function_kind auto_delete,
{
/* We will use ADDR multiple times so we must save it. */
addr = save_expr (addr);
+ head = get_target_expr (build_headof (addr));
/* Delete the object. */
- do_delete = build_builtin_delete_call (addr);
+ do_delete = build_builtin_delete_call (head);
/* Otherwise, treat this like a complete object destructor
call. */
auto_delete = sfk_complete_destructor;
@@ -2919,6 +2921,10 @@ build_delete (tree type, tree addr, special_function_kind auto_delete,
if (do_delete)
expr = build2 (COMPOUND_EXPR, void_type_node, expr, do_delete);
+ /* We need to calculate this before the dtor changes the vptr. */
+ if (head)
+ expr = build2 (COMPOUND_EXPR, void_type_node, head, expr);
+
if (flags & LOOKUP_DESTRUCTOR)
/* Explicit destructor call; don't check for null pointer. */
ifexp = integer_one_node;
diff --git a/gcc/cp/rtti.c b/gcc/cp/rtti.c
index 8253a28..9d2ffdf 100644
--- a/gcc/cp/rtti.c
+++ b/gcc/cp/rtti.c
@@ -101,7 +101,6 @@ VEC(tree,gc) *unemitted_tinfo_decls;
and are generated as needed. */
static GTY (()) VEC(tinfo_s,gc) *tinfo_descs;
-static tree build_headof (tree);
static tree ifnonnull (tree, tree);
static tree tinfo_name (tree);
static tree build_dynamic_cast_1 (tree, tree);
@@ -155,7 +154,7 @@ init_rtti_processing (void)
virtual functions (TYPE_POLYMORPHIC_P), else just return the
expression. */
-static tree
+tree
build_headof (tree exp)
{
tree type = TREE_TYPE (exp);
diff --git a/gcc/testsuite/g++.dg/init/delete2.C b/gcc/testsuite/g++.dg/init/delete2.C
new file mode 100644
index 0000000..8a486be
--- /dev/null
+++ b/gcc/testsuite/g++.dg/init/delete2.C
@@ -0,0 +1,55 @@
+// PR c++/15097
+// { dg-do run }
+
+typedef __SIZE_TYPE__ size_t;
+
+extern "C" void * malloc (size_t);
+extern "C" void free (void *);
+extern "C" void abort(void);
+
+void *saved;
+
+void * operator new (size_t size)
+{
+ void *p = malloc (size);
+ saved = p;
+ return p;
+}
+
+void operator delete (void *p)
+{
+ if (p != saved)
+ abort ();
+ free (p);
+}
+
+struct B1
+{
+ virtual ~B1 () throw() {}
+ B1 (){}
+ int x;
+};
+struct B2
+{
+ virtual ~B2 () throw() {}
+ B2 (){}
+ int x;
+};
+struct D : B1, B2
+{
+ D (){}
+ ~D () throw() {}
+ int y;
+};
+void f1 (D*);
+void f2 (B2*);
+void f3 (B1*);
+int main (void)
+{
+ f1 (::new D);
+ f2 (::new D);
+ f3 (::new D);
+}
+void f1 ( D* p) { ::delete p; }
+void f2 (B2* p) { ::delete p; }
+void f3 (B1* p) { ::delete p; }