[ABI PATCH] static anonymous unions of function scope
authorNathan Sidwell <nathan@acm.org>
Thu, 1 Nov 2018 11:18:06 +0000 (11:18 +0000)
committerNathan Sidwell <nathan@gcc.gnu.org>
Thu, 1 Nov 2018 11:18:06 +0000 (11:18 +0000)
https://gcc.gnu.org/ml/gcc-patches/2018-10/msg02076.html
* cp-tree.h (struct lang_function): Delete x_local_names field.
(struct lang_decl_base): Rename u2sel to spare.
(struct lang_decl_min): Remove lang_decl_u2 union.  Keep access
field.
(LANG_DECL_U2_CHECK): Delete.
(DECL_DISCRIMINATOR_P): Require function scope.
(DECL_DISCRIMINATOR): Adjust.
(DECL_DISCRIMINATOR_SET_P): Delete.
(DECL_CAPTURED_VARIABLE, DECL_ACCESS, THUnK_VIRTUAL_OFFSET): Adjust.
(local_classes): Don't declare.
(determine_local_discriminator): Declare.
* decl.c (push_local_name): Delete.
(local_entities, determina_local_discrminator): New.
(duplicate_decls): Copy DECL_ACCESS. Fix formatting.
(cp_finish_decl): Use determine_local_discriminator.
(save_function_data): Drop x_local_names.
(finish_function): Drop local_names.
* decl2.c (finish_anon_union): Use determine_local_disciminator.
* mangle.c (write_unnamed_type_name): Use
discriminator_for_local_entity.
(local_class_index): Delete.
(discriminator_for_local_entity): Reimplement.
(write_local_name): Adjust discriminator code.
* name-lookup.c (do_pushtag): Call determine_local_discrimiator.
* semantics.c (finish_omp_threadprivate): Drop DECL_DISCRIMINATOR
handling.
* class.c (local_classes): Delete.
(init_class_processing): Don't init it.

* g++.dg/abi/anon5.C: New.

From-SVN: r265714

gcc/cp/ChangeLog
gcc/cp/class.c
gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/decl2.c
gcc/cp/mangle.c
gcc/cp/name-lookup.c
gcc/cp/semantics.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/abi/anon5.C [new file with mode: 0644]

index 6d483455922714e9c11db8355b8d96c62d9c5c8f..b567d6565eb1ac80b52d80b82f458756a7141a51 100644 (file)
@@ -1,3 +1,34 @@
+2018-11-01  Nathan Sidwell  <nathan@acm.org>
+
+       * cp-tree.h (struct lang_function): Delete x_local_names field.
+       (struct lang_decl_base): Rename u2sel to spare.
+       (struct lang_decl_min): Remove lang_decl_u2 union.  Keep access
+       field.
+       (LANG_DECL_U2_CHECK): Delete.
+       (DECL_DISCRIMINATOR_P): Require function scope.
+       (DECL_DISCRIMINATOR): Adjust.
+       (DECL_DISCRIMINATOR_SET_P): Delete.
+       (DECL_CAPTURED_VARIABLE, DECL_ACCESS, THUnK_VIRTUAL_OFFSET): Adjust.
+       (local_classes): Don't declare.
+       (determine_local_discriminator): Declare.
+       * decl.c (push_local_name): Delete.
+       (local_entities, determina_local_discrminator): New.
+       (duplicate_decls): Copy DECL_ACCESS. Fix formatting.
+       (cp_finish_decl): Use determine_local_discriminator.
+       (save_function_data): Drop x_local_names.
+       (finish_function): Drop local_names.
+       * decl2.c (finish_anon_union): Use determine_local_disciminator.
+       * mangle.c (write_unnamed_type_name): Use
+       discriminator_for_local_entity.
+       (local_class_index): Delete.
+       (discriminator_for_local_entity): Reimplement.
+       (write_local_name): Adjust discriminator code.
+       * name-lookup.c (do_pushtag): Call determine_local_discrimiator.
+       * semantics.c (finish_omp_threadprivate): Drop DECL_DISCRIMINATOR
+       handling.
+       * class.c (local_classes): Delete.
+       (init_class_processing): Don't init it.
+
 2018-11-01  Martin Liska  <mliska@suse.cz>
            Jason Merrill  <jason@redhat.com>
 
index 1789d1ecb70ad34a9637fc5198a3169af5bb533e..0b50f67157882f036f0fd741a99843ff241e74cb 100644 (file)
@@ -111,10 +111,6 @@ static class_stack_node_t current_class_stack;
 /* The size of the largest empty class seen in this translation unit.  */
 static GTY (()) tree sizeof_biggest_empty_class;
 
-/* An array of all local classes present in this translation unit, in
-   declaration order.  */
-vec<tree, va_gc> *local_classes;
-
 static tree get_vfield_name (tree);
 static void finish_struct_anon (tree);
 static tree get_vtable_name (tree);
@@ -7431,7 +7427,6 @@ init_class_processing (void)
   current_class_stack_size = 10;
   current_class_stack
     = XNEWVEC (struct class_stack_node, current_class_stack_size);
-  vec_alloc (local_classes, 8);
   sizeof_biggest_empty_class = size_zero_node;
 
   ridpointers[(int) RID_PUBLIC] = access_public_node;
index 42449f10a48907ffa220638a5d8027952a86a2cd..6d49744b8301d53c2453010c3309351f5873155d 100644 (file)
@@ -1793,7 +1793,7 @@ struct GTY(()) language_function {
   hash_table<named_label_hash> *x_named_labels;
 
   cp_binding_level *bindings;
-  vec<tree, va_gc> *x_local_names;
+
   /* Tracking possibly infinite loops.  This is a vec<tree> only because
      vec<bool> doesn't work with gtype.  */
   vec<tree, va_gc> *infinite_loops;
@@ -2527,7 +2527,7 @@ struct GTY(()) lang_decl_base {
   unsigned friend_or_tls : 1;             /* var, fn, type or template */
   unsigned unknown_bound_p : 1;                   /* var */
   unsigned odr_used : 1;                  /* var or fn */
-  unsigned u2sel : 1;
+  unsigned spare : 1;
   unsigned concept_p : 1;                  /* applies to vars and functions */
   unsigned var_declared_inline_p : 1;     /* var */
   unsigned dependent_init_p : 1;          /* var */
@@ -2555,17 +2555,12 @@ struct GTY(()) lang_decl_min {
      DECL_TEMPLATE_INFO.  */
   tree template_info;
 
-  union lang_decl_u2 {
-    /* In a FUNCTION_DECL for which DECL_THUNK_P holds, this is
-       THUNK_VIRTUAL_OFFSET.
-       In a VAR_DECL for which DECL_HAS_VALUE_EXPR_P holds,
-       this is DECL_CAPTURED_VARIABLE.
-       Otherwise this is DECL_ACCESS.  */
-    tree GTY ((tag ("0"))) access;
-
-    /* For TREE_STATIC VAR_DECL in function, this is DECL_DISCRIMINATOR.  */
-    int GTY ((tag ("1"))) discriminator;
-  } GTY ((desc ("%0.u.base.u2sel"))) u2;
+  /* In a DECL_THUNK_P FUNCTION_DECL, this is THUNK_VIRTUAL_OFFSET.
+     In a lambda-capture proxy VAR_DECL, this is DECL_CAPTURED_VARIABLE.
+     In a function-scope TREE_STATIC VAR_DECL or IMPLICIT_TYPEDEF_P TYPE_DECL,
+     this is DECL_DISCRIMINATOR.
+     Otherwise, in a class-scope DECL, this is DECL_ACCESS.   */
+  tree access;
 };
 
 /* Additional DECL_LANG_SPECIFIC information for functions.  */
@@ -2721,12 +2716,6 @@ struct GTY(()) lang_decl {
     lang_check_failed (__FILE__, __LINE__, __FUNCTION__);      \
   &lt->u.decomp; })
 
-#define LANG_DECL_U2_CHECK(NODE, TF) __extension__             \
-({  struct lang_decl *lt = DECL_LANG_SPECIFIC (NODE);          \
-    if (!LANG_DECL_HAS_MIN (NODE) || lt->u.base.u2sel != TF)   \
-      lang_check_failed (__FILE__, __LINE__, __FUNCTION__);    \
-    &lt->u.min.u2; })
-
 #else
 
 #define LANG_DECL_MIN_CHECK(NODE) \
@@ -2744,9 +2733,6 @@ struct GTY(()) lang_decl {
 #define LANG_DECL_DECOMP_CHECK(NODE) \
   (&DECL_LANG_SPECIFIC (NODE)->u.decomp)
 
-#define LANG_DECL_U2_CHECK(NODE, TF) \
-  (&DECL_LANG_SPECIFIC (NODE)->u.min.u2)
-
 #endif /* ENABLE_TREE_CHECKING */
 
 /* For a FUNCTION_DECL or a VAR_DECL, the language linkage for the
@@ -2854,15 +2840,13 @@ struct GTY(()) lang_decl {
         CLONE = DECL_CHAIN (CLONE))
 
 /* Nonzero if NODE has DECL_DISCRIMINATOR and not DECL_ACCESS.  */
-#define DECL_DISCRIMINATOR_P(NODE)     \
-  (VAR_P (NODE) && DECL_FUNCTION_SCOPE_P (NODE))
+#define DECL_DISCRIMINATOR_P(NODE)                             \
+  (((TREE_CODE (NODE) == VAR_DECL && TREE_STATIC (NODE))       \
+    || DECL_IMPLICIT_TYPEDEF_P (NODE))                         \
+   && DECL_FUNCTION_SCOPE_P (NODE))
 
 /* Discriminator for name mangling.  */
-#define DECL_DISCRIMINATOR(NODE) (LANG_DECL_U2_CHECK (NODE, 1)->discriminator)
-
-/* True iff DECL_DISCRIMINATOR is set for a DECL_DISCRIMINATOR_P decl.  */
-#define DECL_DISCRIMINATOR_SET_P(NODE) \
-  (DECL_LANG_SPECIFIC (NODE) && DECL_LANG_SPECIFIC (NODE)->u.base.u2sel == 1)
+#define DECL_DISCRIMINATOR(NODE) (LANG_DECL_MIN_CHECK (NODE)->access)
 
 /* The index of a user-declared parameter in its function, starting at 1.
    All artificial parameters will have index 0.  */
@@ -3334,7 +3318,7 @@ struct GTY(()) lang_decl {
 
 /* For a lambda capture proxy, its captured variable.  */
 #define DECL_CAPTURED_VARIABLE(NODE) \
-  (LANG_DECL_U2_CHECK (NODE, 0)->access)
+  (LANG_DECL_MIN_CHECK (NODE)->access)
 
 /* For a VAR_DECL, indicates that the variable is actually a
    non-static data member of anonymous union that has been promoted to
@@ -4509,7 +4493,7 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter)
    For example, if a member that would normally be public in a
    derived class is made protected, then the derived class and the
    protected_access_node will appear in the DECL_ACCESS for the node.  */
-#define DECL_ACCESS(NODE) (LANG_DECL_U2_CHECK (NODE, 0)->access)
+#define DECL_ACCESS(NODE) (LANG_DECL_MIN_CHECK (NODE)->access)
 
 /* Nonzero if the FUNCTION_DECL is a global constructor.  */
 #define DECL_GLOBAL_CTOR_P(NODE) \
@@ -4846,7 +4830,7 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter)
    binfos.)  */
 
 #define THUNK_VIRTUAL_OFFSET(DECL) \
-  (LANG_DECL_U2_CHECK (FUNCTION_DECL_CHECK (DECL), 0)->access)
+  (LANG_DECL_MIN_CHECK (FUNCTION_DECL_CHECK (DECL))->access)
 
 /* A thunk which is equivalent to another thunk.  */
 #define THUNK_ALIAS(DECL) \
@@ -5240,10 +5224,6 @@ struct local_specialization_stack
 
 extern int current_class_depth;
 
-/* An array of all local classes present in this translation unit, in
-   declaration order.  */
-extern GTY(()) vec<tree, va_gc> *local_classes;
-
 /* in decl.c */
 
 /* An array of static vars & fns.  */
@@ -6303,6 +6283,7 @@ extern void pop_switch                            (void);
 extern void note_break_stmt                    (void);
 extern bool note_iteration_stmt_body_start     (void);
 extern void note_iteration_stmt_body_end       (bool);
+extern void determine_local_discriminator      (tree);
 extern tree make_lambda_name                   (void);
 extern int decls_match                         (tree, tree, bool = true);
 extern bool maybe_version_functions            (tree, tree, bool);
index 1cea5262b620c73d79d4b3ac21745981ae0046bd..23fcf6b04715a234615dd7c9f397fbc2e9839d40 100644 (file)
@@ -66,7 +66,6 @@ static const char *redeclaration_error_message (tree, tree);
 
 static int decl_jump_unsafe (tree);
 static void require_complete_types_for_parms (tree);
-static void push_local_name (tree);
 static tree grok_reference_init (tree, tree, tree, int);
 static tree grokvardecl (tree, tree, tree, const cp_decl_specifier_seq *,
                         int, int, int, bool, int, tree);
@@ -138,8 +137,6 @@ static void expand_static_init (tree, tree);
 
 tree cp_global_trees[CPTI_MAX];
 
-#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
@@ -871,40 +868,57 @@ create_implicit_typedef (tree name, tree type)
   return decl;
 }
 
-/* Remember a local name for name-mangling purposes.  */
+/* Function-scope local entities that need discriminators.  Each entry
+   is a {decl,name} pair.  VAR_DECLs for anon unions get their name
+   smashed, so we cannot rely on DECL_NAME.  */
 
-static void
-push_local_name (tree decl)
-{
-  size_t i, nelts;
-  tree t, name;
+static GTY((deletable)) vec<tree, va_gc> *local_entities;
 
-  timevar_start (TV_NAME_LOOKUP);
+/* Determine the mangling discriminator of local DECL.  There are
+   generally very few of these in any particular function.  */
 
-  name = DECL_NAME (decl);
+void
+determine_local_discriminator (tree decl)
+{
+  bool subtime = timevar_cond_start (TV_NAME_LOOKUP);
+  retrofit_lang_decl (decl);
+  tree ctx = DECL_CONTEXT (decl);
+  tree name = (TREE_CODE (decl) == TYPE_DECL
+              && TYPE_UNNAMED_P (TREE_TYPE (decl))
+              ? NULL_TREE : DECL_NAME (decl));
+  size_t nelts = vec_safe_length (local_entities);
+  for (size_t i = 0; i < nelts; i += 2)
+    {
+      tree *pair = &(*local_entities)[i];
+      tree d = pair[0];
+      tree n = pair[1];
+      gcc_checking_assert (d != decl);
+      if (name == n
+         && TREE_CODE (decl) == TREE_CODE (d)
+         && ctx == DECL_CONTEXT (d))
+       {
+         tree disc = integer_one_node;
+         if (DECL_DISCRIMINATOR (d))
+           disc = build_int_cst (TREE_TYPE (disc),
+                                 TREE_INT_CST_LOW (DECL_DISCRIMINATOR (d)) + 1);
+         DECL_DISCRIMINATOR (decl) = disc;
+         /* Replace the saved decl.  */
+         pair[0] = decl;
+         decl = NULL_TREE;
+         break;
+       }
+    }
 
-  nelts = vec_safe_length (local_names);
-  for (i = 0; i < nelts; i++)
+  if (decl)
     {
-      t = (*local_names)[i];
-      if (DECL_NAME (t) == name)
-       {
-         retrofit_lang_decl (decl);
-         DECL_LANG_SPECIFIC (decl)->u.base.u2sel = 1;
-         if (DECL_DISCRIMINATOR_SET_P (t))
-           DECL_DISCRIMINATOR (decl) = DECL_DISCRIMINATOR (t) + 1;
-         else
-           DECL_DISCRIMINATOR (decl) = 1;
-
-         (*local_names)[i] = decl;
-         timevar_stop (TV_NAME_LOOKUP);
-         return;
-       }
+      vec_safe_reserve (local_entities, 2);
+      local_entities->quick_push (decl);
+      local_entities->quick_push (name);
     }
 
-  vec_safe_push (local_names, decl);
-  timevar_stop (TV_NAME_LOOKUP);
+  timevar_cond_stop (TV_NAME_LOOKUP, subtime);
 }
+
 \f
 /* Subroutine of duplicate_decls: return truthvalue of whether
    or not types of these decls match.
@@ -2360,8 +2374,7 @@ next_arg:;
 
       if (LANG_DECL_HAS_MIN (newdecl))
        {
-         DECL_LANG_SPECIFIC (newdecl)->u.min.u2 =
-           DECL_LANG_SPECIFIC (olddecl)->u.min.u2;
+         DECL_ACCESS (newdecl) = DECL_ACCESS (olddecl);
          if (DECL_TEMPLATE_INFO (newdecl))
            {
              new_template_info = DECL_TEMPLATE_INFO (newdecl);
@@ -2397,15 +2410,15 @@ next_arg:;
 
       /* Merge parameter attributes. */
       tree oldarg, newarg;
-      for (oldarg = DECL_ARGUMENTS(olddecl), 
-               newarg = DECL_ARGUMENTS(newdecl);
+      for (oldarg = DECL_ARGUMENTS(olddecl),  newarg = DECL_ARGUMENTS(newdecl);
            oldarg && newarg;
-           oldarg = DECL_CHAIN(oldarg), newarg = DECL_CHAIN(newarg)) {
+           oldarg = DECL_CHAIN(oldarg), newarg = DECL_CHAIN(newarg))
+       {
           DECL_ATTRIBUTES (newarg)
-              = (*targetm.merge_decl_attributes) (oldarg, newarg);
+           = (*targetm.merge_decl_attributes) (oldarg, newarg);
           DECL_ATTRIBUTES (oldarg) = DECL_ATTRIBUTES (newarg);
-      }
-      
+       }
+
       if (DECL_TEMPLATE_INSTANTIATION (olddecl)
          && !DECL_TEMPLATE_INSTANTIATION (newdecl))
        {
@@ -7135,7 +7148,11 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
          && TREE_STATIC (decl)
          && !DECL_ARTIFICIAL (decl))
        {
-         push_local_name (decl);
+         /* The variable holding an anonymous union will have had its
+            discriminator set in finish_anon_union, after which it's
+            NAME will have been cleared.  */
+         if (DECL_NAME (decl))
+           determine_local_discriminator (decl);
          /* Normally has_forced_label_in_static is set during GIMPLE
             lowering, but [cd]tors are never actually compiled directly.
             We need to set this early so we can deal with the label
@@ -15620,7 +15637,6 @@ save_function_data (tree decl)
   /* Clear out the bits we don't need.  */
   f->base.x_stmt_tree.x_cur_stmt_list = NULL;
   f->bindings = NULL;
-  f->x_local_names = NULL;
   f->base.local_typedefs = NULL;
 }
 
@@ -16125,8 +16141,6 @@ finish_function (bool inline_p)
       f->extern_decl_map = NULL;
       f->infinite_loops = NULL;
     }
-  /* Clear out the bits we don't need.  */
-  local_names = NULL;
 
   /* We're leaving the context of this function, so zap cfun.  It's still in
      DECL_STRUCT_FUNCTION, and we'll restore it in tree_rest_of_compilation.  */
index a5ad0eed3ad6ed2253efe9938d743cf8762448ec..a163558af54710b148e49818a4c8feeaf05e86ae 100644 (file)
@@ -1666,7 +1666,11 @@ finish_anon_union (tree anon_union_decl)
       DECL_NAME (anon_union_decl) = DECL_NAME (main_decl);
       maybe_commonize_var (anon_union_decl);
       if (TREE_STATIC (anon_union_decl) || DECL_EXTERNAL (anon_union_decl))
-       mangle_decl (anon_union_decl);
+       {
+         if (DECL_DISCRIMINATOR_P (anon_union_decl))
+           determine_local_discriminator (anon_union_decl);
+         mangle_decl (anon_union_decl);
+       }
       DECL_NAME (anon_union_decl) = NULL_TREE;
     }
 
index 59a3111fba249d8b84962c285b512fb444dea060..690d0bbdbd3bf9172adf06af80cf539d8d6dc707 100644 (file)
@@ -233,7 +233,6 @@ static void write_discriminator (const int);
 static void write_local_name (tree, const tree, const tree);
 static void dump_substitution_candidates (void);
 static tree mangle_decl_string (const tree);
-static int local_class_index (tree);
 static void maybe_check_abi_tags (tree, tree = NULL_TREE, int = 10);
 static bool equal_abi_tags (tree, tree);
 
@@ -1642,7 +1641,7 @@ write_unnamed_type_name (const tree type)
   MANGLE_TRACE_TREE ("unnamed-type-name", type);
 
   if (TYPE_FUNCTION_SCOPE_P (type))
-    discriminator = local_class_index (type);
+    discriminator = discriminator_for_local_entity (TYPE_NAME (type));
   else if (TYPE_CLASS_SCOPE_P (type))
     discriminator = nested_anon_class_index (type);
   else
@@ -1913,58 +1912,25 @@ write_special_name_destructor (const tree dtor)
     }
 }
 
-/* Scan the vector of local classes and return how many others with the
-   same name (or same no name) and context precede ENTITY.  */
-
-static int
-local_class_index (tree entity)
-{
-  int ix, discriminator = 0;
-  tree name = (TYPE_UNNAMED_P (entity) ? NULL_TREE
-              : TYPE_IDENTIFIER (entity));
-  tree ctx = TYPE_CONTEXT (entity);
-  for (ix = 0; ; ix++)
-    {
-      tree type = (*local_classes)[ix];
-      if (type == entity)
-       return discriminator;
-      if (TYPE_CONTEXT (type) == ctx
-         && (name ? TYPE_IDENTIFIER (type) == name
-             : TYPE_UNNAMED_P (type)))
-       ++discriminator;
-    }
-  gcc_unreachable ();
-}
-
 /* Return the discriminator for ENTITY appearing inside
-   FUNCTION.  The discriminator is the lexical ordinal of VAR among
-   entities with the same name in the same FUNCTION.  */
+   FUNCTION.  The discriminator is the lexical ordinal of VAR or TYPE among
+   entities with the same name and kind in the same FUNCTION.  */
 
 static int
 discriminator_for_local_entity (tree entity)
 {
-  if (DECL_DISCRIMINATOR_P (entity))
+  if (!DECL_LANG_SPECIFIC (entity))
     {
-      if (DECL_DISCRIMINATOR_SET_P (entity))
-       return DECL_DISCRIMINATOR (entity);
-      else
-       /* The first entity with a particular name doesn't get
-          DECL_DISCRIMINATOR set up.  */
-       return 0;
-    }
-  else if (TREE_CODE (entity) == TYPE_DECL)
-    {
-      /* Scan the list of local classes.  */
-      entity = TREE_TYPE (entity);
-
-      /* Lambdas and unnamed types have their own discriminators.  */
-      if (LAMBDA_TYPE_P (entity) || TYPE_UNNAMED_P (entity))
-       return 0;
-
-      return local_class_index (entity);
+      /* Some decls, like __FUNCTION__, don't need a discriminator.  */
+      gcc_checking_assert (DECL_ARTIFICIAL (entity));
+      return 0;
     }
+  else if (tree disc = DECL_DISCRIMINATOR (entity))
+    return TREE_INT_CST_LOW (disc);
   else
-    gcc_unreachable ();
+    /* The first entity with a particular name doesn't get
+       DECL_DISCRIMINATOR set up.  */
+    return 0;
 }
 
 /* Return the discriminator for STRING, a string literal used inside
@@ -2062,7 +2028,11 @@ write_local_name (tree function, const tree local_entity,
         from <local-name>, so it doesn't try to process the enclosing
         function scope again.  */
       write_name (entity, /*ignore_local_scope=*/1);
-      write_discriminator (discriminator_for_local_entity (local_entity));
+      if (DECL_DISCRIMINATOR_P (local_entity)
+         && !(TREE_CODE (local_entity) == TYPE_DECL
+              && (LAMBDA_TYPE_P (TREE_TYPE (local_entity))
+                  || TYPE_UNNAMED_P (TREE_TYPE (local_entity)))))
+       write_discriminator (discriminator_for_local_entity (local_entity));
     }
 }
 
index f2d9d2225050dded584257786e21942e532aba08..ad562ba219e41b4e70a031b67dc015c989608266 100644 (file)
@@ -6879,7 +6879,7 @@ do_pushtag (tree name, tree type, tag_scope scope)
            }
          /* Lambdas use LAMBDA_EXPR_DISCRIMINATOR instead.  */
          else if (!LAMBDA_TYPE_P (type))
-           vec_safe_push (local_classes, type);
+           determine_local_discriminator (TYPE_NAME (type));
        }
     }
 
index 4c053655e00945e94e7d43462595e9cf7c86dec5..0d9673db1c5691be4d854a2d29f71e2b4786f69a 100644 (file)
@@ -7566,14 +7566,7 @@ finish_omp_threadprivate (tree vars)
        {
          /* Allocate a LANG_SPECIFIC structure for V, if needed.  */
          if (DECL_LANG_SPECIFIC (v) == NULL)
-           {
-             retrofit_lang_decl (v);
-
-             /* Make sure that DECL_DISCRIMINATOR_P continues to be true
-                after the allocation of the lang_decl structure.  */
-             if (DECL_DISCRIMINATOR_P (v))
-               DECL_LANG_SPECIFIC (v)->u.base.u2sel = 1;
-           }
+           retrofit_lang_decl (v);
 
          if (! CP_DECL_THREAD_LOCAL_P (v))
            {
index 9f9d35e656c5ac0cf8c438de90b527d729dc1008..13e1a1c351920e86f27c3f2ea4b4faf9bcd3f6f6 100644 (file)
@@ -1,3 +1,7 @@
+2018-11-01  Nathan Sidwell  <nathan@acm.org>
+
+       * g++.dg/abi/anon5.C: New.
+
 2018-11-01  Jakub Jelinek  <jakub@redhat.com>
 
        PR d/87824
diff --git a/gcc/testsuite/g++.dg/abi/anon5.C b/gcc/testsuite/g++.dg/abi/anon5.C
new file mode 100644 (file)
index 0000000..4e724d4
--- /dev/null
@@ -0,0 +1,14 @@
+// anon-union decls may need a discriminator
+
+void f ()
+{
+  { static int bob; }
+  { static union {int bob;};}
+  { static int bob; }
+  { static union {int bob;}; }
+}
+
+// { dg-final { scan-assembler {_ZZ1fvE3bob[^_]} } }
+// { dg-final { scan-assembler {_ZZ1fvE3bob_0} } }
+// { dg-final { scan-assembler {_ZZ1fvE3bob_1} } }
+// { dg-final { scan-assembler {_ZZ1fvE3bob_2} } }