This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

[PATCH] Inline even functions containing static variables (was Re: Removing space waste for g++ static inlined objects)


On Sat, Feb 24, 2001 at 09:45:09AM +0000, Jason Merrill wrote:
> >>>>> "Ronald" == Ronald F Guilmette <rfg@monkeys.com> writes:
> 
> >> Finally, we need to support calculating the discriminator properly for
> >> non-types.
> 
> > Whatever you just said, it is Greek to me.
> 
> > Can you elucidate (please)?
> 
> >From my earlier response:
> 
> The v3 C++ ABI (http://reality.sgi.com/dehnert_engr/cxx/) deals with [the
> possibility of multiple local statics with the same name] by specifying
> that locals after the first get a number appended:
> 
>   <local-name> := Z <function encoding> E <entity name> [<discriminator>]
>   <discriminator> := _ <non-negative number> 
> 
> We don't currently handle calculating this number for non-types, which will
> need to be fixed.  This is already a potential problem on targets that
> don't support weak symbols.

Here is what I hacked up yesterday and today.
It bootstraps and creates no regressions on i386-redhat-linux.
BTW: The fact that mangle was not discriminating among non-type local
entities caused problems even when inlining was disallowed in inline
functions: if 2 static variables with the same identifier in one function
required a guard variable, they would share the same guard variable because
it would be mangled the same way.

There are 2 things unclear to me in
http://reality.sgi.com/dehnert_engr/cxx/abi.html#mangling
>   The first production is used for named local static objects and classes, which are identified by their declared names. The
>   <entity name> may itself be a compound name, but it is relative to the closest enclosing function, i.e. none of the
>   components of the function encoding appear in the entity name. It is possible to have nested function scopes, e.g. when
>   dealing with a member function in a local class. In such cases, the function encoding will itself have <local-name>
>   structure. The discriminator is used only for the second and later occurrences of the same name within a single function.
>   In this case <number> is n - 2, if this is the nth occurrence, in lexical order, of the given name.

though:
1) gcc uses no discriminator for 1st occurrence, _ for 2nd occurrence, _0 for 3rd
   occurrence and onwards, while the above paragraph (at least in my reading suggests
   that no discriminator for 1st occurrence, _0 for 2nd occurrence, _1 for 3rd occurrence
   (at least my understanding is that n in above text is 1 based, not 0 based; speaking
   in native language about ``second'' occurrence I'd really think it is 1 based, Alex?).
2) it is also not really clear to me whether local static objects and local classes are
   discriminated together or whether they are discriminated separately.
   The patch below discriminates them separately (ie. first static object and first static
   class get the same mangling, but in the case of class I think it never occurres
   alone and e.g. in the testcase below there is even additional N after E), but I
   think it is more probable that they are discriminated together, ie. first occurence in
   lexical order of either local class or static object will get no discriminator, then
   discriminator _0, etc. The patch below can be changed easy for that, just by calling
   push_local_name at the place in decl.c where local_classes are pushed and adjusting
   discriminator_for_local_entity.

I had to tweak maybe_commonize_var, because if we are creating a guard variable
before maybe_commonize_var is called (which we do in reference initialization code),
the guard needs to get the same linkage as the variable it is guarding.
Unfortunately, maybe_commonize_var cannot be called normally before check_initializer,
since initializer is not yet set up and the code called from there overrides linkage
and maybe_commonize_var depends on the initializer as well.
The patch also cleans up DECL_INLINED_FNS handling to use a TREE_VEC instead of
custom data structure. It is done in the same patch, since this patch is moving
DECL_INLINED_FNS anyway (so that it does not eat any more space in lang_decl
structure).

2001-03-16  Jakub Jelinek  <jakub@redhat.com>

	* decl.c (local_names, local_names_fndecl, push_local_name,
	save_local_names): New.
	(init_decl_processing): Register local_names with GC.
	(grok_reference_init): Call maybe_commonize_var before making
	guard variable.
	(maybe_commonize_var): Add linkage_only argument.
	If flag_weak, allow inlining functions even if they have static
	local variables, use comdat_linkage for them.
	(cp_finish_decl): Pass additional argument to maybe_commonize_var.
	(expand_static_init): Call push_local_name before making guard
	variable.
	(start_function, finish_function): Call save_local_names.
	(mark_function_permanent): Renamed from mark_inlined_fns.
	(lang_mark_tree): Call it.
	* cp-tree.h (local_names, local_names_fndecl): New.
	(lang_decl_function_permanent): New structure.
	(lang_decl_inlined_fns): Remove.
	(lang_decl): Replace inlined_fns with function_permanent.
	(DECL_FUNCTION_PERMANENT, DECL_INLINED_FNS_P, DEFL_LOCAL_NAMES_P,
	DECL_LOCAL_NAMES): New macros.
	(DECL_INLINED_FNS): Use DECL_FUNCTION_PERMAMENT.
	* optimize.c (inlinable_function_p): Use DECL_INLINED_FNS_P.
	DECL_INLINED_FNS is now a TREE_VEC, not a custom structure.
	(expand_call_inline): Use DECL_INLINED_FNS_P.
	(optimize_function): DECL_INLINED_FNS is now a TREE_VEC, not a
	custom structure.
	* mangle.c (discriminator_for_local_entity): Discriminate among
	non-type local entities.

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

--- gcc/cp/decl.c.jj	Thu Mar 15 13:03:14 2001
+++ gcc/cp/decl.c	Fri Mar 16 10:24:44 2001
@@ -75,6 +75,8 @@ static tree store_bindings PARAMS ((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 save_local_names PARAMS ((tree));
 static void warn_extern_redeclared_static PARAMS ((tree, tree));
 static void grok_reference_init PARAMS ((tree, tree, tree));
 static tree grokfndecl PARAMS ((tree, tree, tree, tree, int,
@@ -121,7 +123,7 @@ static void pop_label PARAMS ((tree, tre
 static void pop_labels PARAMS ((tree));
 static void maybe_deduce_size_from_array_init PARAMS ((tree, tree));
 static void layout_var_decl PARAMS ((tree));
-static void maybe_commonize_var PARAMS ((tree));
+static void maybe_commonize_var PARAMS ((tree, int));
 static tree check_initializer PARAMS ((tree, tree));
 static void make_rtl_for_nonlocal_decl PARAMS ((tree, tree, const char *));
 static void push_cp_function_context PARAMS ((struct function *));
@@ -130,7 +132,8 @@ static void mark_binding_level PARAMS ((
 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_function_permanent
+  PARAMS ((struct lang_decl_function_permanent *));
 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));
@@ -158,6 +161,10 @@ static void indent PARAMS ((void));
 /* Erroneous argument lists can use this *IFF* they do not modify it.  */
 tree error_mark_list;
 
+/* Static local variables for name-mangling purposes.  */
+varray_type local_names;
+tree local_names_fndecl;
+
 /* The following symbols are subsumed in the cp_global_trees array, and
    listed here individually for documentation purposes.
 
@@ -2751,6 +2758,62 @@ 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 nelts;
+
+  if (DECL_LOCAL_NAMES_P (current_function_decl))
+    {
+      tree names = DECL_LOCAL_NAMES (current_function_decl);
+
+      if (local_names_fndecl)
+	abort ();
+
+      VARRAY_TREE_INIT (local_names, TREE_VEC_LENGTH (names) + 8,
+			"local_names");
+      memcpy (&VARRAY_TREE (local_names, 0), &TREE_VEC_ELT (names, 0),
+	      TREE_VEC_LENGTH (names) * sizeof (tree));
+      VARRAY_ACTIVE_SIZE (local_names) = TREE_VEC_LENGTH (names);
+    }
+  else if (!local_names)
+    VARRAY_TREE_INIT (local_names, 8, "local_names");
+
+  local_names_fndecl = current_function_decl;
+
+  /* Don't add the same decl twice.  */
+  nelts = VARRAY_ACTIVE_SIZE (local_names);
+  if (!nelts || VARRAY_TREE (local_names, nelts - 1) != decl)
+    VARRAY_PUSH_TREE (local_names, decl);
+}
+
+/* Store LOCAL_NAMES into FNDECL.  */
+
+static void
+save_local_names (fndecl)
+     tree fndecl;
+{
+  tree names;
+
+  if (!DECL_FUNCTION_PERMANENT (fndecl))
+    {
+      struct lang_decl_function_permanent *fp;
+              
+      fp = ggc_alloc (sizeof (struct lang_decl_function_permanent));
+      memset (fp, 0, sizeof (*fp));
+      DECL_FUNCTION_PERMANENT (fndecl) = fp;
+    }
+  names = make_tree_vec (VARRAY_ACTIVE_SIZE (local_names));
+  memcpy (&TREE_VEC_ELT (names, 0), &VARRAY_TREE (local_names, 0),
+	  VARRAY_ACTIVE_SIZE (local_names) * sizeof (tree));
+  DECL_LOCAL_NAMES (fndecl) = names;
+  VARRAY_FREE (local_names);
+  local_names_fndecl = NULL_TREE;
+}
+
 /* 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.
@@ -6563,6 +6626,8 @@ init_decl_processing ()
   ggc_add_tree_root (&current_function_parm_tags, 1);
   ggc_add_tree_root (&last_function_parms, 1);
   ggc_add_tree_root (&error_mark_list, 1);
+  ggc_add_tree_varray_root (&local_names, 1);
+  ggc_add_tree_root (&local_names_fndecl, 1);
 
   ggc_add_tree_root (&global_namespace, 1);
   ggc_add_tree_root (&global_type_node, 1);
@@ -7358,8 +7423,11 @@ grok_reference_init (decl, type, init)
 
   if (TREE_STATIC (decl) && ! TREE_CONSTANT (DECL_INITIAL (decl)))
     {
-      expand_static_init (decl, DECL_INITIAL (decl));
+      init = DECL_INITIAL (decl);
       DECL_INITIAL (decl) = NULL_TREE;
+      if (TREE_CODE (decl) == VAR_DECL)
+	maybe_commonize_var (decl, 1);
+      expand_static_init (decl, init);
     }
   return;
 }
@@ -7491,11 +7559,13 @@ layout_var_decl (decl)
 
 /* If a local static variable is declared in an inline function, or if
    we have a weak definition, we must endeavor to create only one
-   instance of the variable at link-time.  */
+   instance of the variable at link-time.
+   If LINKAGE_ONLY is non-zero, don't mangle names nor issue any warnings.  */
 
 static void
-maybe_commonize_var (decl)
+maybe_commonize_var (decl, linkage_only)
      tree decl;
+     int linkage_only;
 {
   /* Static data in a function with comdat linkage also has comdat
      linkage.  */
@@ -7508,12 +7578,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
@@ -7534,13 +7598,33 @@ maybe_commonize_var (decl)
 	  /* else we lose. We can only do this if we can use common,
 	     which we can't if it has been initialized.  */
 
+	  if (linkage_only)
+	    return;
+
 	  if (TREE_PUBLIC (decl))
-	    DECL_ASSEMBLER_NAME (decl) = mangle_decl (decl);
+	    {
+	      push_local_name (decl);
+	      DECL_ASSEMBLER_NAME (decl) = mangle_decl (decl);
+	    }
 	  else
 	    {
 	      cp_warning_at ("sorry: semantics of inline function static data `%#D' are wrong (you'll wind up with multiple copies)", decl);
 	      cp_warning_at ("  you can work around this by removing the initializer", 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;
+	}
+      else
+	{
+	  comdat_linkage (decl);
+	  if (linkage_only)
+	    return;
+	  push_local_name (decl);
+	  DECL_ASSEMBLER_NAME (decl) = mangle_decl (decl);
 	}
     }
   else if (DECL_LANG_SPECIFIC (decl) && DECL_COMDAT (decl))
@@ -8054,7 +8138,7 @@ cp_finish_decl (decl, init, asmspec_tree
       || TREE_CODE (decl) == RESULT_DECL)
     {
       if (TREE_CODE (decl) == VAR_DECL)
-	maybe_commonize_var (decl);
+	maybe_commonize_var (decl, 0);
 
       make_rtl_for_nonlocal_decl (decl, init, asmspec);
 
@@ -8427,6 +8511,8 @@ expand_static_init (decl, init)
 	 threads should not be able to initialize the variable more
 	 than once.  We don't yet attempt to ensure thread-safety.  */
 
+      push_local_name (decl);
+
       /* Create the guard variable.  */
       guard = get_guard (decl);
 
@@ -13348,6 +13434,9 @@ start_function (declspecs, declarator, a
   if (processing_template_decl)
     decl1 = push_template_decl (decl1);
 
+  if (local_names && local_names_fndecl == current_function_decl)
+    save_local_names (current_function_decl);
+
   /* We are now in the scope of the function being defined.  */
   current_function_decl = decl1;
 
@@ -13962,6 +14051,9 @@ finish_function (flags)
   if (!processing_template_decl && calls_setjmp_p (fndecl))
     DECL_UNINLINABLE (fndecl) = 1;
 
+  if (local_names_fndecl == fndecl)
+    save_local_names (fndecl);
+
   /* Clear out memory we no longer need.  */
   free_after_parsing (cfun);
   /* Since we never call rest_of_compilation, we never clear
@@ -14328,17 +14420,15 @@ pop_cp_function_context (f)
   f->language = 0;
 }
 
-/* Mark I for GC.  */
+/* Mark FP for GC.  */
 
 static void
-mark_inlined_fns (i)
-     struct lang_decl_inlined_fns *i;
+mark_function_permanent (fp)
+     struct lang_decl_function_permanent *fp;
 {
-  int n;
-
-  for (n = i->num_fns - 1; n >= 0; n--)
-    ggc_mark_tree (i->fns [n]);
-  ggc_set_mark (i);
+  ggc_mark_tree (fp->inlined_fns);
+  ggc_mark_tree (fp->local_names);
+  ggc_set_mark (fp);
 }
 
 /* Mark P for GC.  */
@@ -14427,8 +14517,8 @@ 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);
+	      if (ld->function_permanent)
+		mark_function_permanent (ld->function_permanent);
 	      if (TREE_CODE (t) == TYPE_DECL)
 		ggc_mark_tree (ld->u.sorted_fields);
 	      else if (TREE_CODE (t) == FUNCTION_DECL
--- gcc/cp/cp-tree.h.jj	Thu Mar 15 13:03:14 2001
+++ gcc/cp/cp-tree.h	Fri Mar 16 10:22:26 2001
@@ -1855,10 +1855,12 @@ struct lang_decl_flags
 
 struct unparsed_text;
 
-struct lang_decl_inlined_fns
+struct lang_decl_function_permanent
 {
-  size_t num_fns;
-  tree fns[1];
+  /* This is a list of trees inlined into its body.  */
+  tree inlined_fns;
+  /* This is a list of local names saved for name-mangling.  */
+  tree local_names;
 };
 
 struct lang_decl
@@ -1874,8 +1876,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.  */
+  struct lang_decl_function_permanent *function_permanent;
 
   union
   {
@@ -1987,9 +1990,28 @@ struct lang_decl
 #define DECL_CLONED_FUNCTION(NODE) \
   (DECL_LANG_SPECIFIC (NODE)->cloned_function)
 
+#define DECL_FUNCTION_PERMANENT(NODE) \
+  (DECL_LANG_SPECIFIC (NODE)->function_permanent)
+
+/* Nonzero if NODE (a FUNCTION_DECL) has DECL_INLINED_FNS set.  */
+#define DECL_INLINED_FNS_P(NODE)			\
+  (DECL_LANG_SPECIFIC (NODE)				\
+   && DECL_FUNCTION_PERMANENT (NODE)			\
+   && DECL_FUNCTION_PERMANENT (NODE)->inlined_fns)
+
 /* List of FUNCION_DECLs inlined into this function's body.  */
 #define DECL_INLINED_FNS(NODE) \
-  (DECL_LANG_SPECIFIC (NODE)->inlined_fns)
+  (DECL_FUNCTION_PERMANENT (NODE)->inlined_fns)
+
+/* Nonzero if NODE (a FUNCTION_DECL) has DECL_LOCAL_NAMES set.  */
+#define DECL_LOCAL_NAMES_P(NODE)			\
+  (DECL_LANG_SPECIFIC (NODE)				\
+   && DECL_FUNCTION_PERMANENT (NODE)			\
+   && DECL_FUNCTION_PERMANENT (NODE)->local_names)
+
+/* List of FUNCTION_DECLs local classes and static variable names.  */
+#define DECL_LOCAL_NAMES(NODE) \
+  (DECL_FUNCTION_PERMANENT (NODE)->local_names)
 
 /* Non-zero if the VTT parm has been added to NODE.  */
 #define DECL_HAS_VTT_PARM_P(NODE) \
@@ -3904,6 +3926,8 @@ extern int nonstatic_local_decl_p       
 extern tree declare_global_var                  PARAMS ((tree, tree));
 extern void register_dtor_fn                    PARAMS ((tree));
 extern tmpl_spec_kind current_tmpl_spec_kind    PARAMS ((int));
+extern varray_type local_names;
+extern tree local_names_fndecl;
 
 /* in decl2.c */
 extern void init_decl2				PARAMS ((void));
--- gcc/cp/optimize.c.jj	Fri Feb 23 12:05:05 2001
+++ gcc/cp/optimize.c	Thu Mar 15 16:09:16 2001
@@ -618,12 +618,13 @@ inlinable_function_p (fn, id)
 	if (VARRAY_TREE (id->fns, i) == fn)
 	  return 0;
 
-      if (inlinable && DECL_LANG_SPECIFIC (fn) && DECL_INLINED_FNS (fn))
+      if (inlinable && DECL_INLINED_FNS_P (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;
 	}
     }
@@ -743,7 +744,7 @@ expand_call_inline (tp, walk_subtrees, d
 
   /* Record the function we are about to inline if optimize_function
      has not been called on it yet and we don't have it in the list.  */
-  if (DECL_LANG_SPECIFIC (fn) && !DECL_INLINED_FNS (fn))
+  if (DECL_LANG_SPECIFIC (fn) && !DECL_INLINED_FNS_P (fn))
     {
       int i;
 
@@ -912,14 +913,18 @@ optimize_function (fn)
       VARRAY_FREE (id.target_exprs);
       if (DECL_LANG_SPECIFIC (fn))
 	{
-	  struct lang_decl_inlined_fns *ifn;
+	  tree ifn = make_tree_vec (VARRAY_ACTIVE_SIZE (id.inlined_fns));
 
-	  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));
+	  memcpy (&TREE_VEC_ELT (ifn, 0), &VARRAY_TREE (id.inlined_fns, 0),
+		  VARRAY_ACTIVE_SIZE (id.inlined_fns) * sizeof (tree));
+	  if (!DECL_FUNCTION_PERMANENT (fn))
+	    {
+	      struct lang_decl_function_permanent *fp;
+
+	      fp = ggc_alloc (sizeof (struct lang_decl_function_permanent));
+	      memset (fp, 0, sizeof (*fp));
+	      DECL_FUNCTION_PERMANENT (fn) = fp;
+	    }
 	  DECL_INLINED_FNS (fn) = ifn;
 	}
       VARRAY_FREE (id.inlined_fns);
--- gcc/cp/mangle.c.jj	Fri Feb 23 12:05:05 2001
+++ gcc/cp/mangle.c	Fri Mar 16 10:22:47 2001
@@ -1156,14 +1156,42 @@ discriminator_for_local_entity (entity)
 
   /* For now, we don't discriminate amongst local variables.  */
   if (TREE_CODE (entity) != TYPE_DECL)
-    return 0;
+    {
+      tree *decl, *end;
 
-  /* 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;
+      /* Scan the list of local names.  */
+      if (DECL_CONTEXT (entity) == local_names_fndecl)
+	{
+	  end = &VARRAY_TREE (local_names, VARRAY_ACTIVE_SIZE (local_names));
+	  for (decl = &VARRAY_TREE (local_names, 0);
+	       decl != end && *decl != entity; ++decl)
+	    if (DECL_NAME (*decl) == DECL_NAME (entity))
+	      ++discriminator;
+	  if (decl == end)
+	    abort ();
+	}
+      else if (DECL_LOCAL_NAMES (DECL_CONTEXT (entity)))
+	{
+	  tree fndecl = DECL_CONTEXT (entity);
+
+	  end = TREE_VEC_END (DECL_LOCAL_NAMES (fndecl));
+	  for (decl = &TREE_VEC_ELT (DECL_LOCAL_NAMES (fndecl), 0);
+	       decl != end && *decl != entity; ++decl)
+	    if (DECL_NAME (*decl) == DECL_NAME (entity))
+	      ++discriminator;
+	  if (decl == end)
+	    abort ();
+	}
+    }
+  else
+    {
+      /* 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;
 }
--- gcc/testsuite/g++.old-deja/g++.other/mangle3.C.jj	Thu Mar 15 18:20:51 2001
+++ gcc/testsuite/g++.old-deja/g++.other/mangle3.C	Thu Mar 15 18:19:19 2001
@@ -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;
+}

	Jakub


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]