+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>
/* 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);
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;
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;
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 */
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. */
lang_check_failed (__FILE__, __LINE__, __FUNCTION__); \
<->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__); \
- <->u.min.u2; })
-
#else
#define LANG_DECL_MIN_CHECK(NODE) \
#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
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. */
/* 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
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) \
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) \
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. */
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);
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);
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
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.
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);
/* 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))
{
&& 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
/* 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;
}
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. */
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;
}
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);
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
}
}
-/* 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
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));
}
}
}
/* Lambdas use LAMBDA_EXPR_DISCRIMINATOR instead. */
else if (!LAMBDA_TYPE_P (type))
- vec_safe_push (local_classes, type);
+ determine_local_discriminator (TYPE_NAME (type));
}
}
{
/* 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))
{
+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
--- /dev/null
+// 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} } }