aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2010-02-02 19:07:49 -0500
committerJason Merrill <jason@gcc.gnu.org>2010-02-02 19:07:49 -0500
commite6ca6e2a1fe9c90168499d67f31eb363168275cc (patch)
tree3d22a04c84152bc16b404b618adbabcaffe23712
parent80ec737fd0c2fe533ec39d8e707b1fbe39425bf9 (diff)
downloadgcc-e6ca6e2a1fe9c90168499d67f31eb363168275cc.zip
gcc-e6ca6e2a1fe9c90168499d67f31eb363168275cc.tar.gz
gcc-e6ca6e2a1fe9c90168499d67f31eb363168275cc.tar.bz2
re PR c++/41090 (Using static label reference in c++ class constructor produces wrong code)
PR c++/41090 * decl.c (cp_finish_decl): Add local statics to cfun->local_decls. * optimize.c (clone_body): Remap their initializers when making base variants. (maybe_clone_body): Complain if multiple clones aren't safe. From-SVN: r156455
-rw-r--r--gcc/cp/ChangeLog8
-rw-r--r--gcc/cp/decl.c13
-rw-r--r--gcc/cp/optimize.c32
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/g++.dg/ext/label13.C20
5 files changed, 77 insertions, 1 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 2cb7f47..b122aec 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,11 @@
+2010-02-02 Jason Merrill <jason@redhat.com>
+
+ PR c++/41090
+ * decl.c (cp_finish_decl): Add local statics to cfun->local_decls.
+ * optimize.c (clone_body): Remap their initializers when making base
+ variants.
+ (maybe_clone_body): Complain if multiple clones aren't safe.
+
2010-01-29 Dodji Seketeli <dodji@redhat.com>
PR c++/42758
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index db3d705..a22cf01 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -5743,7 +5743,18 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
if (DECL_FUNCTION_SCOPE_P (decl)
&& TREE_STATIC (decl)
&& !DECL_ARTIFICIAL (decl))
- push_local_name (decl);
+ {
+ push_local_name (decl);
+ if (DECL_CONSTRUCTOR_P (current_function_decl)
+ || DECL_DESTRUCTOR_P (current_function_decl))
+ /* Normally local_decls is populated during GIMPLE lowering,
+ but [cd]tors are never actually compiled directly. We need
+ to put statics on the list so we can deal with the label
+ address extension. */
+ cfun->local_decls = tree_cons (NULL_TREE, decl,
+ cfun->local_decls);
+ }
+
/* Convert the initializer to the type of DECL, if we have not
already initialized DECL. */
if (!DECL_INITIALIZED_P (decl)
diff --git a/gcc/cp/optimize.c b/gcc/cp/optimize.c
index 325df8f..5fb769c 100644
--- a/gcc/cp/optimize.c
+++ b/gcc/cp/optimize.c
@@ -104,6 +104,21 @@ clone_body (tree clone, tree fn, void *arg_map)
stmts = DECL_SAVED_TREE (fn);
walk_tree (&stmts, copy_tree_body_r, &id, NULL);
+
+ /* Also remap the initializer of any static variables so that they (in
+ particular, any label addresses) correspond to the base variant rather
+ than the abstract one. */
+ if (DECL_NAME (clone) == base_dtor_identifier
+ || DECL_NAME (clone) == base_ctor_identifier)
+ {
+ tree decls = DECL_STRUCT_FUNCTION (fn)->local_decls;
+ for (; decls; decls = TREE_CHAIN (decls))
+ {
+ tree decl = TREE_VALUE (decls);
+ walk_tree (&DECL_INITIAL (decl), copy_tree_body_r, &id, NULL);
+ }
+ }
+
append_to_statement_list_force (stmts, &DECL_SAVED_TREE (clone));
}
@@ -195,6 +210,7 @@ maybe_clone_body (tree fn)
bool first = true;
bool in_charge_parm_used;
int idx;
+ bool need_alias = false;
/* We only clone constructors and destructors. */
if (!DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (fn)
@@ -223,6 +239,11 @@ maybe_clone_body (tree fn)
else
gcc_unreachable ();
+ /* Remember if we can't have multiple clones for some reason. We need to
+ check this before we remap local static initializers in clone_body. */
+ if (!tree_versionable_function_p (fn))
+ need_alias = true;
+
/* We know that any clones immediately follow FN in the TYPE_METHODS
list. */
push_to_top_level ();
@@ -314,6 +335,17 @@ maybe_clone_body (tree fn)
/* No need to populate body. */ ;
else
{
+ /* If we can't have multiple copies of FN (say, because there's a
+ static local initialized with the address of a label), we need
+ to use an alias for the complete variant. */
+ if (idx == 1 && need_alias)
+ {
+ if (DECL_STRUCT_FUNCTION (fn)->cannot_be_copied_set)
+ sorry (DECL_STRUCT_FUNCTION (fn)->cannot_be_copied_reason, fn);
+ else
+ sorry ("making multiple clones of %qD", fn);
+ }
+
/* Remap the parameters. */
decl_map = pointer_map_create ();
for (parmno = 0,
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index d409f98..3a7499d 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2010-02-02 Jason Merrill <jason@redhat.com>
+
+ PR c++/41090
+ * g++.dg/ext/label13.C: New.
+
2010-02-02 Tobias Burnus <burnus@net-b.de>
PR fortran/42650
diff --git a/gcc/testsuite/g++.dg/ext/label13.C b/gcc/testsuite/g++.dg/ext/label13.C
new file mode 100644
index 0000000..5f3c0f5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/label13.C
@@ -0,0 +1,20 @@
+// PR c++/41090
+// { dg-do run }
+// { dg-options "" }
+
+int i;
+struct C
+{
+ C()
+ {
+ static void *labelref = &&label;
+ goto *labelref;
+ label: i = 1;
+ }
+};
+
+int main()
+{
+ C c;
+ return (i != 1);
+}