From e6ca6e2a1fe9c90168499d67f31eb363168275cc Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Tue, 2 Feb 2010 19:07:49 -0500 Subject: [PATCH] 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 --- gcc/cp/ChangeLog | 8 ++++++++ gcc/cp/decl.c | 13 +++++++++++- gcc/cp/optimize.c | 32 ++++++++++++++++++++++++++++++ gcc/testsuite/ChangeLog | 5 +++++ gcc/testsuite/g++.dg/ext/label13.C | 20 +++++++++++++++++++ 5 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/g++.dg/ext/label13.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 2cb7f4753d3..b122aecbe54 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,11 @@ +2010-02-02 Jason Merrill + + 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 PR c++/42758 diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index db3d7054dc1..a22cf0114fa 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 325df8ffcd7..5fb769c2c63 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 d409f98f15f..3a7499d2e97 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2010-02-02 Jason Merrill + + PR c++/41090 + * g++.dg/ext/label13.C: New. + 2010-02-02 Tobias Burnus 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 00000000000..5f3c0f5cb38 --- /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); +} -- 2.30.2