OSDN Git Service

PR c++/41090
authorjason <jason@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 3 Feb 2010 00:07:49 +0000 (00:07 +0000)
committerjason <jason@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 3 Feb 2010 00:07:49 +0000 (00:07 +0000)
* 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.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@156455 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/cp/ChangeLog
gcc/cp/decl.c
gcc/cp/optimize.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/ext/label13.C [new file with mode: 0644]

index 2cb7f47..b122aec 100644 (file)
@@ -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
 2010-01-29  Dodji Seketeli  <dodji@redhat.com>
 
        PR c++/42758
index db3d705..a22cf01 100644 (file)
@@ -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))
       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)
       /* Convert the initializer to the type of DECL, if we have not
         already initialized DECL.  */
       if (!DECL_INITIALIZED_P (decl)
index 325df8f..5fb769c 100644 (file)
@@ -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);
 
   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));
 }
 
   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 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)
 
   /* 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 ();
 
     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 ();
   /* 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
        {
        /* 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,
           /* Remap the parameters.  */
           decl_map = pointer_map_create ();
           for (parmno = 0,
index d409f98..3a7499d 100644 (file)
@@ -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
 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 (file)
index 0000000..5f3c0f5
--- /dev/null
@@ -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);
+}