diff options
author | Jason Merrill <jason@redhat.com> | 2010-02-02 19:07:49 -0500 |
---|---|---|
committer | Jason Merrill <jason@gcc.gnu.org> | 2010-02-02 19:07:49 -0500 |
commit | e6ca6e2a1fe9c90168499d67f31eb363168275cc (patch) | |
tree | 3d22a04c84152bc16b404b618adbabcaffe23712 | |
parent | 80ec737fd0c2fe533ec39d8e707b1fbe39425bf9 (diff) | |
download | gcc-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/ChangeLog | 8 | ||||
-rw-r--r-- | gcc/cp/decl.c | 13 | ||||
-rw-r--r-- | gcc/cp/optimize.c | 32 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 5 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/ext/label13.C | 20 |
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); +} |