Commit 41f927f4 by Nathan Sidwell Committed by Nathan Sidwell

[ABI PATCH] static anonymous unions of function scope

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
parent 5de9d931
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>
......
......@@ -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;
......
......@@ -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);
......
......@@ -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);
}
/* 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. */
......
......@@ -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;
}
......
......@@ -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));
}
}
......
......@@ -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));
}
}
......
......@@ -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))
{
......
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
......
// 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} } }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment