decl.c (local_names): Define.
authorJakub Jelinek <jakub@redhat.com>
Fri, 23 Mar 2001 12:04:11 +0000 (13:04 +0100)
committerJakub Jelinek <jakub@gcc.gnu.org>
Fri, 23 Mar 2001 12:04:11 +0000 (13:04 +0100)
* decl.c (local_names): Define.
(push_local_name): New.
(grok_reference_init): Return init if initializing static reference
variable with non-constant instead of emitting it.
Move expand_static_init call to cp_finish_decl.
(layout_var_decl): Call push_local_name.
(maybe_commonize_var): Allow inlining functions even if they have
static local variables, use comdat_linkage for them if flag_weak.
(check_initializer): Call obscure_complex_init if
grok_reference_init returned non-zero.
(save_function_data): Clear x_local_names.
(pop_cp_function_context): Free x_local_names.
(mark_inlined_fns): Remove.
(mark_lang_function): Mark x_local_names.
(lang_mark_tree): Don't mark DECL_ACCESS for DECL_DISCRIMINATOR_P.
Mark inlined_fns as tree, remove call to mark_inlined_fns.
* class.c (alter_access): Ensure DECL_ACCESS is never set if
DECL_DISCRIMINATOR_P.
* cp-tree.h (cp_language_function): Add x_local_names.
(lang_decl_flags): Add discriminator into u2.
(lang_decl_inlined_fns): Remove.
(lang_decl): inlined_fns is now a TREE_VEC.
(DECL_DISCRIMINATOR_P, DECL_DISCRIMINATOR): Define.
* optimize.c (inlinable_function_p): DECL_INLINED_FNS is now a
TREE_VEC, not a custom structure.
(optimize_function): Likewise.
* mangle.c (discriminator_for_local_entity): Discriminate among
VAR_DECL local entities.
* search.c (dfs_access_in_type): If DECL_DISCRIMINATOR_P, DECL_ACCESS
is not valid.

* g++.old-deja/g++.other/mangle3.C: New test.

From-SVN: r40779

gcc/cp/ChangeLog
gcc/cp/class.c
gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/mangle.c
gcc/cp/optimize.c
gcc/cp/search.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.old-deja/g++.other/mangle3.C [new file with mode: 0644]

index e85d6b8529025c8bdf62c5552aa1ce94c996d295..2881da6ab5ef0ee6bd948ce121ac36e6bdff8fc9 100644 (file)
@@ -1,3 +1,36 @@
+2001-03-23  Jakub Jelinek  <jakub@redhat.com>
+
+       * decl.c (local_names): Define.
+       (push_local_name): New.
+       (grok_reference_init): Return init if initializing static reference
+       variable with non-constant instead of emitting it.
+       Move expand_static_init call to cp_finish_decl.
+       (layout_var_decl): Call push_local_name.
+       (maybe_commonize_var): Allow inlining functions even if they have
+       static local variables, use comdat_linkage for them if flag_weak.
+       (check_initializer): Call obscure_complex_init if
+       grok_reference_init returned non-zero.
+       (save_function_data): Clear x_local_names.
+       (pop_cp_function_context): Free x_local_names.
+       (mark_inlined_fns): Remove.
+       (mark_lang_function): Mark x_local_names.
+       (lang_mark_tree): Don't mark DECL_ACCESS for DECL_DISCRIMINATOR_P.
+       Mark inlined_fns as tree, remove call to mark_inlined_fns.
+       * class.c (alter_access): Ensure DECL_ACCESS is never set if
+       DECL_DISCRIMINATOR_P.
+       * cp-tree.h (cp_language_function): Add x_local_names.
+       (lang_decl_flags): Add discriminator into u2.
+       (lang_decl_inlined_fns): Remove.
+       (lang_decl): inlined_fns is now a TREE_VEC.
+       (DECL_DISCRIMINATOR_P, DECL_DISCRIMINATOR): Define.
+       * optimize.c (inlinable_function_p): DECL_INLINED_FNS is now a
+       TREE_VEC, not a custom structure.
+       (optimize_function): Likewise.
+       * mangle.c (discriminator_for_local_entity): Discriminate among
+       VAR_DECL local entities.
+       * search.c (dfs_access_in_type): If DECL_DISCRIMINATOR_P, DECL_ACCESS
+       is not valid.
+
 2001-03-22  Bryce McKinlay  <bryce@albatross.co.nz>
 
        Add support for Java interface method calls.
index ea726d8c572aeccc424512f370da3f1d4de70e3b..b4838b17bcf36740dccc6859dd89ead5577cb459 100644 (file)
@@ -1458,6 +1458,9 @@ alter_access (t, fdecl, access)
   if (!DECL_LANG_SPECIFIC (fdecl))
     retrofit_lang_decl (fdecl);
 
+  if (DECL_DISCRIMINATOR_P (fdecl))
+    abort ();
+
   elem = purpose_member (t, DECL_ACCESS (fdecl));
   if (elem)
     {
index f8dd6928f34b1f42c1996f5c8d9e59512eed4fe8..28f519dd29be1ca1c01fd5f9bc29e6863cc4a9b1 100644 (file)
@@ -887,6 +887,7 @@ struct cp_language_function
   struct named_label_use_list *x_named_label_uses;
   struct named_label_list *x_named_labels;
   struct binding_level *bindings;
+  varray_type x_local_names;
 
   const char *cannot_inline;
 };
@@ -1840,6 +1841,9 @@ struct lang_decl_flags
     /* This is DECL_ACCESS.  */
     tree access;
 
+    /* For VAR_DECL in function, this is DECL_DISCRIMINATOR.  */
+    int discriminator;
+
     /* In a namespace-scope FUNCTION_DECL, this is
        GLOBAL_INIT_PRIORITY.  */
     int init_priority;
@@ -1852,12 +1856,6 @@ struct lang_decl_flags
 
 struct unparsed_text;
 
-struct lang_decl_inlined_fns
-{
-  size_t num_fns;
-  tree fns[1];
-};
-
 struct lang_decl
 {
   struct lang_decl_flags decl_flags;
@@ -1871,8 +1869,9 @@ struct lang_decl
   /* In a FUNCTION_DECL, this is DECL_CLONED_FUNCTION.  */
   tree cloned_function;
 
-  /* In a FUNCTION_DECL, this is a list of trees inlined into its body.  */
-  struct lang_decl_inlined_fns *inlined_fns;
+  /* In a FUNCTION_DECL, these are function data which is to be kept
+     as long as FUNCTION_DECL is kept.  */
+  tree inlined_fns;
 
   union
   {
@@ -1989,6 +1988,15 @@ struct lang_decl
 #define DECL_INLINED_FNS(NODE) \
   (DECL_LANG_SPECIFIC (NODE)->inlined_fns)
 
+/* Nonzero if NODE has DECL_DISCRIMINATOR and not DECL_ACCESS.  */
+#define DECL_DISCRIMINATOR_P(NODE)     \
+  (TREE_CODE (NODE) == VAR_DECL                \
+   && DECL_FUNCTION_SCOPE_P (NODE))
+
+/* Discriminator for name mangling.  */
+#define DECL_DISCRIMINATOR(NODE) \
+  (DECL_LANG_SPECIFIC (NODE)->decl_flags.u2.discriminator)
+
 /* Non-zero if the VTT parm has been added to NODE.  */
 #define DECL_HAS_VTT_PARM_P(NODE) \
   (DECL_LANG_SPECIFIC (NODE)->decl_flags.has_vtt_parm_p)
index 0a6296a47a0c44952a16e281aa19c10f10a315dc..4794f659d3debbad8897b93744b2e24b0e146a98 100644 (file)
@@ -75,8 +75,9 @@ static tree store_bindings PARAMS ((tree, tree));
 static tree lookup_tag_reverse PARAMS ((tree, tree));
 static tree obscure_complex_init PARAMS ((tree, tree));
 static tree lookup_name_real PARAMS ((tree, int, int, int));
+static void push_local_name PARAMS ((tree));
 static void warn_extern_redeclared_static PARAMS ((tree, tree));
-static void grok_reference_init PARAMS ((tree, tree, tree));
+static tree grok_reference_init PARAMS ((tree, tree, tree));
 static tree grokfndecl PARAMS ((tree, tree, tree, tree, int,
                              enum overload_flags, tree,
                              tree, int, int, int, int, int, int, tree));
@@ -130,7 +131,6 @@ static void mark_binding_level PARAMS ((void *));
 static void mark_named_label_lists PARAMS ((void *, void *));
 static void mark_cp_function_context PARAMS ((struct function *));
 static void mark_saved_scope PARAMS ((void *));
-static void mark_inlined_fns PARAMS ((struct lang_decl_inlined_fns *));
 static void mark_lang_function PARAMS ((struct cp_language_function *));
 static void save_function_data PARAMS ((tree));
 static void check_function_type PARAMS ((tree, tree));
@@ -248,6 +248,8 @@ struct named_label_use_list
 
 #define named_label_uses cp_function_chain->x_named_label_uses
 
+#define local_names cp_function_chain->x_local_names
+
 /* A list of objects which have constructors or destructors
    which reside in the global scope.  The decl is stored in
    the TREE_VALUE slot and the initializer is stored
@@ -2750,6 +2752,41 @@ create_implicit_typedef (name, type)
   return decl;
 }
 
+/* Remember a local name for name-mangling purposes.  */
+
+static void
+push_local_name (decl)
+     tree decl;
+{
+  size_t i, nelts;
+  tree t, name;
+
+  if (!local_names)
+    VARRAY_TREE_INIT (local_names, 8, "local_names");
+
+  name = DECL_NAME (decl);
+
+  nelts = VARRAY_ACTIVE_SIZE (local_names);
+  for (i = 0; i < nelts; i++)
+    {
+      t = VARRAY_TREE (local_names, i);
+      if (DECL_NAME (t) == name)
+       {
+         if (!DECL_LANG_SPECIFIC (decl))
+           retrofit_lang_decl (decl);
+         if (DECL_LANG_SPECIFIC (t))
+           DECL_DISCRIMINATOR (decl) = DECL_DISCRIMINATOR (t) + 1;
+         else
+           DECL_DISCRIMINATOR (decl) = 1;
+
+         VARRAY_TREE (local_names, i) = decl;
+         return;
+       }
+    }
+
+  VARRAY_PUSH_TREE (local_names, decl);
+}
+
 /* Push a tag name NAME for struct/class/union/enum type TYPE.
    Normally put it into the inner-most non-tag-transparent scope,
    but if GLOBALIZE is true, put it in the inner-most non-class scope.
@@ -7292,7 +7329,7 @@ start_decl_1 (decl)
 
    Quotes on semantics can be found in ARM 8.4.3.  */
 
-static void
+static tree
 grok_reference_init (decl, type, init)
      tree decl, type, init;
 {
@@ -7304,16 +7341,16 @@ grok_reference_init (decl, type, init)
           || DECL_IN_AGGR_P (decl) == 0)
          && ! DECL_THIS_EXTERN (decl))
        cp_error ("`%D' declared as reference but not initialized", decl);
-      return;
+      return NULL_TREE;
     }
 
   if (init == error_mark_node)
-    return;
+    return NULL_TREE;
 
   if (TREE_CODE (init) == CONSTRUCTOR)
     {
       cp_error ("ISO C++ forbids use of initializer list to initialize reference `%D'", decl);
-      return;
+      return NULL_TREE;
     }
 
   if (TREE_CODE (init) == TREE_LIST)
@@ -7342,32 +7379,26 @@ grok_reference_init (decl, type, init)
      decl);
 
   if (tmp == error_mark_node)
-    return;
-  else if (tmp != NULL_TREE)
-    {
-      init = tmp;
-      tmp = save_expr (tmp);
-      if (building_stmt_tree ())
-       {
-         /* Initialize the declaration.  */
-         tmp = build (INIT_EXPR, TREE_TYPE (decl), decl, tmp);
-         finish_expr_stmt (tmp);
-       }
-      else
-       DECL_INITIAL (decl) = tmp;
-    }
-  else
+    return NULL_TREE;
+  else if (tmp == NULL_TREE)
     {
       cp_error ("cannot initialize `%T' from `%T'", type, TREE_TYPE (init));
-      return;
+      return NULL_TREE;
     }
 
-  if (TREE_STATIC (decl) && ! TREE_CONSTANT (DECL_INITIAL (decl)))
+  if (TREE_STATIC (decl) && !TREE_CONSTANT (tmp))
+    return tmp;
+
+  if (building_stmt_tree ())
     {
-      expand_static_init (decl, DECL_INITIAL (decl));
-      DECL_INITIAL (decl) = NULL_TREE;
+      /* Initialize the declaration.  */
+      tmp = build (INIT_EXPR, TREE_TYPE (decl), decl, tmp);
+      finish_expr_stmt (tmp);
     }
-  return;
+  else
+    DECL_INITIAL (decl) = tmp;
+
+  return NULL_TREE;
 }
 
 /* Fill in DECL_INITIAL with some magical value to prevent expand_decl from
@@ -7493,6 +7524,12 @@ layout_var_decl (decl)
       else
        cp_error ("storage size of `%D' isn't constant", decl);
     }
+
+  if (TREE_STATIC (decl)
+      && !DECL_ARTIFICIAL (decl)
+      && current_function_decl
+      && DECL_CONTEXT (decl) == current_function_decl)
+    push_local_name (decl);
 }
 
 /* If a local static variable is declared in an inline function, or if
@@ -7514,12 +7551,6 @@ maybe_commonize_var (decl)
          || DECL_TEMPLATE_INSTANTIATION (current_function_decl))
       && TREE_PUBLIC (current_function_decl))
     {
-      /* Rather than try to get this right with inlining, we suppress
-        inlining of such functions.  */
-      current_function_cannot_inline
-       = "function with static variable cannot be inline";
-      DECL_UNINLINABLE (current_function_decl) = 1;
-
       /* If flag_weak, we don't need to mess with this, as we can just
         make the function weak, and let it refer to its unique local
         copy.  This works because we don't allow the function to be
@@ -7546,6 +7577,8 @@ maybe_commonize_var (decl)
              cp_warning_at ("  you can work around this by removing the initializer", decl);
            }
        }
+      else
+       comdat_linkage (decl);
     }
   else if (DECL_LANG_SPECIFIC (decl) && DECL_COMDAT (decl))
     /* Set it up again; we might have set DECL_INITIAL since the last
@@ -7632,8 +7665,9 @@ check_initializer (decl, init)
     }
   else if (!DECL_EXTERNAL (decl) && TREE_CODE (type) == REFERENCE_TYPE)
     {
-      grok_reference_init (decl, type, init);
-      init = NULL_TREE;
+      init = grok_reference_init (decl, type, init);
+      if (init)
+       init = obscure_complex_init (decl, init);
     }
   else if (init)
     {
@@ -13694,6 +13728,7 @@ save_function_data (decl)
   f->base.x_stmt_tree.x_last_expr_type = NULL_TREE;
   f->x_named_label_uses = NULL;
   f->bindings = NULL;
+  f->x_local_names = NULL;
 
   /* When we get back here again, we will be expanding.  */
   f->x_expanding_p = 1;
@@ -14312,23 +14347,16 @@ pop_cp_function_context (f)
      struct function *f;
 {
   if (f->language)
-    free (f->language);
+    {
+      struct cp_language_function *cp =
+       (struct cp_language_function *) f->language;
+      if (cp->x_local_names)
+       VARRAY_FREE (cp->x_local_names);
+      free (f->language);
+    }
   f->language = 0;
 }
 
-/* Mark I for GC.  */
-
-static void
-mark_inlined_fns (i)
-     struct lang_decl_inlined_fns *i;
-{
-  int n;
-
-  for (n = i->num_fns - 1; n >= 0; n--)
-    ggc_mark_tree (i->fns [n]);
-  ggc_set_mark (i);
-}
-
 /* Mark P for GC.  */
 
 static void
@@ -14345,6 +14373,7 @@ mark_lang_function (p)
   ggc_mark_tree (p->x_current_class_ptr);
   ggc_mark_tree (p->x_current_class_ref);
   ggc_mark_tree (p->x_eh_spec_try_block);
+  ggc_mark_tree_varray (p->x_local_names);
 
   mark_named_label_lists (&p->x_named_labels, &p->x_named_label_uses);
   mark_binding_level (&p->bindings);
@@ -14402,7 +14431,8 @@ lang_mark_tree (t)
          c_mark_lang_decl (&ld->decl_flags.base);
          if (!DECL_GLOBAL_CTOR_P (t)
              && !DECL_GLOBAL_DTOR_P (t)
-             && !DECL_THUNK_P (t))
+             && !DECL_THUNK_P (t)
+             && !DECL_DISCRIMINATOR_P (t))
            ggc_mark_tree (ld->decl_flags.u2.access);
          else if (DECL_THUNK_P (t))
            ggc_mark_tree (ld->decl_flags.u2.vcall_offset);
@@ -14415,8 +14445,7 @@ lang_mark_tree (t)
              ggc_mark_tree (ld->befriending_classes);
              ggc_mark_tree (ld->context);
              ggc_mark_tree (ld->cloned_function);
-             if (ld->inlined_fns)
-               mark_inlined_fns (ld->inlined_fns);
+             ggc_mark_tree (ld->inlined_fns);
              if (TREE_CODE (t) == TYPE_DECL)
                ggc_mark_tree (ld->u.sorted_fields);
              else if (TREE_CODE (t) == FUNCTION_DECL
index 101f412385276b8ea298fdaad46d69e3bbb1d8a2..a908640088ef3c4f83b2da7a7a60d24d3a769da1 100644 (file)
@@ -1154,16 +1154,17 @@ discriminator_for_local_entity (entity)
   /* Assume this is the only local entity with this name.  */
   discriminator = 0;
 
-  /* For now, we don't discriminate amongst local variables.  */
-  if (TREE_CODE (entity) != TYPE_DECL)
-    return 0;
-
-  /* Scan the list of local classes.  */
-  entity = TREE_TYPE (entity);
-  for (type = &VARRAY_TREE (local_classes, 0); *type != entity; ++type)
-    if (TYPE_IDENTIFIER (*type) == TYPE_IDENTIFIER (entity)
-       && TYPE_CONTEXT (*type) == TYPE_CONTEXT (entity))
-      ++discriminator;
+  if (DECL_DISCRIMINATOR_P (entity) && DECL_LANG_SPECIFIC (entity))
+    discriminator = DECL_DISCRIMINATOR (entity);
+  else if (TREE_CODE (entity) == TYPE_DECL)
+    {
+      /* Scan the list of local classes.  */
+      entity = TREE_TYPE (entity);
+      for (type = &VARRAY_TREE (local_classes, 0); *type != entity; ++type)
+        if (TYPE_IDENTIFIER (*type) == TYPE_IDENTIFIER (entity)
+            && TYPE_CONTEXT (*type) == TYPE_CONTEXT (entity))
+         ++discriminator;
+    }  
 
   return discriminator;
 }
index c1cbf52c9fc8cbb6e750aeda4a810aefa2331f9d..d350fdaaeedb1c2429071642f47002c99c16a703 100644 (file)
@@ -620,10 +620,11 @@ inlinable_function_p (fn, id)
 
       if (inlinable && DECL_LANG_SPECIFIC (fn) && DECL_INLINED_FNS (fn))
        {
-         struct lang_decl_inlined_fns *ifn = DECL_INLINED_FNS (fn);
+         int j;
+         tree inlined_fns = DECL_INLINED_FNS (fn);
 
-         for (i = 0; i < ifn->num_fns; ++i)
-           if (ifn->fns [i] == VARRAY_TREE (id->fns, 0))
+         for (j = 0; j < TREE_VEC_LENGTH (inlined_fns); ++j)
+           if (TREE_VEC_ELT (inlined_fns, j) == VARRAY_TREE (id->fns, 0))
              return 0;
        }
     }
@@ -912,14 +913,10 @@ optimize_function (fn)
       VARRAY_FREE (id.target_exprs);
       if (DECL_LANG_SPECIFIC (fn))
        {
-         struct lang_decl_inlined_fns *ifn;
-
-         ifn = ggc_alloc (sizeof (struct lang_decl_inlined_fns)
-                          + (VARRAY_ACTIVE_SIZE (id.inlined_fns) - 1)
-                            * sizeof (tree));
-         ifn->num_fns = VARRAY_ACTIVE_SIZE (id.inlined_fns);
-         memcpy (&ifn->fns[0], &VARRAY_TREE (id.inlined_fns, 0),
-                 ifn->num_fns * sizeof (tree));
+         tree ifn = make_tree_vec (VARRAY_ACTIVE_SIZE (id.inlined_fns));
+
+         memcpy (&TREE_VEC_ELT (ifn, 0), &VARRAY_TREE (id.inlined_fns, 0),
+                 VARRAY_ACTIVE_SIZE (id.inlined_fns) * sizeof (tree));
          DECL_INLINED_FNS (fn) = ifn;
        }
       VARRAY_FREE (id.inlined_fns);
index 95ede8bcdea249c6d4938ada82298ba09be95756..c52620f0cf3400261424754621a42926bdfc7d0e 100644 (file)
@@ -842,7 +842,7 @@ dfs_access_in_type (binfo, data)
         access to the DECL.  The CONST_DECL for an enumeration
         constant will not have DECL_LANG_SPECIFIC, and thus no
         DECL_ACCESS.  */
-      if (DECL_LANG_SPECIFIC (decl))
+      if (DECL_LANG_SPECIFIC (decl) && !DECL_DISCRIMINATOR_P (decl))
        {
          tree decl_access = purpose_member (type, DECL_ACCESS (decl));
          if (decl_access)
index e75a1e01be484fce828606ce5b1d4d3392f70a05..4e61c615d26a626460739b212a6a5a93a0a6ac2b 100644 (file)
@@ -1,3 +1,7 @@
+2001-03-23  Jakub Jelinek  <jakub@redhat.com>
+
+       * g++.old-deja/g++.other/mangle3.C: New test.
+
 2001-03-22  Jakub Jelinek  <jakub@redhat.com>
 
        * g++.old-deja/g++.other/anon8.C: New test.
diff --git a/gcc/testsuite/g++.old-deja/g++.other/mangle3.C b/gcc/testsuite/g++.old-deja/g++.other/mangle3.C
new file mode 100644 (file)
index 0000000..d77a4b5
--- /dev/null
@@ -0,0 +1,41 @@
+struct foo {
+  static int bar ()
+  {
+    int i;
+    static int baz = 1;
+    {
+      static int baz = 2;
+      i = baz++;
+    }
+    {
+      struct baz {
+        static int m ()
+        {
+          static int n;
+          return n += 10;
+        }
+      };
+      baz a;
+      i += a.m ();
+    }
+    {
+      static int baz = 3;
+      i += baz;
+      baz += 30;
+    }
+    i += baz;
+    baz += 60;
+    return i;
+  }
+};
+
+int main ()
+{
+  foo x;
+
+  if (x.bar () != 16)
+    return 1;
+  if (x.bar() != 117)
+    return 1;
+  return 0;
+}