aboutsummaryrefslogtreecommitdiff
path: root/gcc/ada/gcc-interface
diff options
context:
space:
mode:
authorArnaud Charlet <charlet@gcc.gnu.org>2014-08-01 16:45:26 +0200
committerArnaud Charlet <charlet@gcc.gnu.org>2014-08-01 16:45:26 +0200
commit9a30c7c4092fa2e7f46ee54883404a3fe34f2919 (patch)
tree514c0aecb2430f2b39147e8bf572fd6c5dc59617 /gcc/ada/gcc-interface
parent88b1a3221d1a03211d78dec931d0cc8d84b180cb (diff)
downloadgcc-9a30c7c4092fa2e7f46ee54883404a3fe34f2919.zip
gcc-9a30c7c4092fa2e7f46ee54883404a3fe34f2919.tar.gz
gcc-9a30c7c4092fa2e7f46ee54883404a3fe34f2919.tar.bz2
[multiple changes]
2014-08-01 Olivier Hainque <hainque@adacore.com> * gcc-interface/Make-lang.in (ADA_TOOLS_FLAGS_TO_PASS, native): use $(CXX) instead of ../../xg++ to feed CXX. (CXX_LFLAGS): Remove. Now unused as the proper flags are expected to be included in the CXX variable. 2014-08-01 Pierre-Marie Derodat <derodat@adacore.com> * gcc-interface/decl.c (elaborate_expression_1): Return the new variable when debug info is needed and the expression is not constant. Tag as external only new variables that are global. (gnat_to_gnu_entity): Call it after the GNU declaration is saved. * gcc-interface/trans.c (Attribute_to_gnu): Do not cache attributes for IN array parameters when their actual subtype needs debug info. (Compilation_Unit_to_gnu): Call it to process all remaining nodes. * gcc-interface/gigi.h (process_deferred_decl_context): New. * gcc-interface/utils.c (gnat_write_global_declarations): Do not emit debug info for ignored global declarations. (struct deferred_decl_context_node, add_deferred_decl_context, add_deferred_type_context, compute_deferred_decl_context, defer_or_set_type_context, deferred_decl_context_queue, get_debug_scope, get_global_context, process_deferred_decl_context): New. (gnat_pushdecl): Re-implement the DECL_CONTEXT and TYPE_CONTEXT computation machinery to rely on the GNAT Scope attribute. 2014-08-01 Eric Botcazou <ebotcazou@adacore.com> * gcc-interface/utils2.c (build_simple_component_ref): Add guard. From-SVN: r213482
Diffstat (limited to 'gcc/ada/gcc-interface')
-rw-r--r--gcc/ada/gcc-interface/Make-lang.in13
-rw-r--r--gcc/ada/gcc-interface/decl.c24
-rw-r--r--gcc/ada/gcc-interface/gigi.h6
-rw-r--r--gcc/ada/gcc-interface/trans.c15
-rw-r--r--gcc/ada/gcc-interface/utils.c322
-rw-r--r--gcc/ada/gcc-interface/utils2.c3
6 files changed, 351 insertions, 32 deletions
diff --git a/gcc/ada/gcc-interface/Make-lang.in b/gcc/ada/gcc-interface/Make-lang.in
index fd44eb8..478272f 100644
--- a/gcc/ada/gcc-interface/Make-lang.in
+++ b/gcc/ada/gcc-interface/Make-lang.in
@@ -128,11 +128,12 @@ ada: gnat1$(exeext) gnatbind$(exeext)
# Tell GNU Make to ignore these, if they exist.
.PHONY: ada
-CXX_LFLAGS = \
- -B../../../$(target_noncanonical)/libstdc++-v3/src/.libs \
- -B../../../$(target_noncanonical)/libstdc++-v3/libsupc++/.libs \
- -L../../../$(target_noncanonical)/libstdc++-v3/src/.libs \
- -L../../../$(target_noncanonical)/libstdc++-v3/libsupc++/.libs
+# Compute the FLAGS to pass for gnattools, now linked with a C++ driver as
+# we're linking against at least libcommon which contains C++ compiled code.
+# We need to use the same driver to link as the one that was used to produce
+# the objects, which depends on whether we're bootstrapping or not. The CXX
+# variable conveys what we need for this, set to "g++" if not bootstrapping,
+# ".../xg++" otherwise.
# There are too many Ada sources to check against here. Let's
# always force the recursive make.
@@ -142,7 +143,7 @@ ifeq ($(build), $(host))
# tree.
ADA_TOOLS_FLAGS_TO_PASS=\
CC="../../xgcc -B../../" \
- CXX="../../xg++ -B../../ $(CXX_LFLAGS)" \
+ CXX="$(CXX)" \
$(COMMON_FLAGS_TO_PASS) $(ADA_FLAGS_TO_PASS) \
ADA_INCLUDES="-I- -I../rts" \
GNATMAKE="../../gnatmake" \
diff --git a/gcc/ada/gcc-interface/decl.c b/gcc/ada/gcc-interface/decl.c
index 9f05067..1e390ef 100644
--- a/gcc/ada/gcc-interface/decl.c
+++ b/gcc/ada/gcc-interface/decl.c
@@ -5190,6 +5190,10 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition)
if (!saved)
save_gnu_tree (gnat_entity, gnu_decl, false);
+ /* Now we are sure gnat_entity has a corresponding ..._DECL node,
+ eliminate as many deferred computations as possible. */
+ process_deferred_decl_context (false);
+
/* If this is an enumeration or floating-point type, we were not able to set
the bounds since they refer to the type. These are always static. */
if ((kind == E_Enumeration_Type && Present (First_Literal (gnat_entity)))
@@ -6184,14 +6188,30 @@ elaborate_expression_1 (tree gnu_expr, Entity_Id gnat_entity, tree gnu_name,
/* Now create it, possibly only for debugging purposes. */
if (use_variable || need_debug)
{
+ /* The following variable creation can happen when processing the body of
+ subprograms that are defined out of the extended main unit and
+ inlined. In this case, we are not at the global scope, and thus the
+ new variable must not be tagged "external", as we used to do here as
+ long as definition == 0. */
+ const bool external_flag = !definition && expr_global_p;
tree gnu_decl
= create_var_decl_1
(create_concat_name (gnat_entity, IDENTIFIER_POINTER (gnu_name)),
NULL_TREE, TREE_TYPE (gnu_expr), gnu_expr, true, expr_public_p,
- !definition, expr_global_p, !need_debug, NULL, gnat_entity);
+ external_flag, expr_global_p, !need_debug, NULL, gnat_entity);
DECL_ARTIFICIAL (gnu_decl) = 1;
- if (use_variable)
+
+ /* Using this variable at debug time (if need_debug is true) requires a
+ proper location. The back-end will compute a location for this
+ variable only if the variable is used by the generated code.
+ Returning the variable ensures the caller will use it in generated
+ code. Note that there is no need for a location if the debug info
+ contains an integer constant.
+ FIXME: when the encoding-based debug scheme is dropped, move this
+ condition to the top-level IF block: we will not need to create a
+ variable anymore in such cases, then. */
+ if (use_variable || (need_debug && !TREE_CONSTANT (gnu_expr)))
return gnu_decl;
}
diff --git a/gcc/ada/gcc-interface/gigi.h b/gcc/ada/gcc-interface/gigi.h
index 72983f8..6cee20b 100644
--- a/gcc/ada/gcc-interface/gigi.h
+++ b/gcc/ada/gcc-interface/gigi.h
@@ -999,6 +999,12 @@ extern int fp_size_to_prec (int size);
initialization is likely to disturb debugging. */
extern bool renaming_from_generic_instantiation_p (Node_Id gnat_node);
+/* Try to process all nodes in the deferred context queue. Keep in the queue
+ the ones that cannot be processed yet, remove the other ones. If FORCE is
+ true, force the processing for all nodes, use the global context when nodes
+ don't have a GNU translation. */
+extern void process_deferred_decl_context (bool force);
+
#ifdef __cplusplus
extern "C" {
#endif
diff --git a/gcc/ada/gcc-interface/trans.c b/gcc/ada/gcc-interface/trans.c
index 64e428a..3323a56 100644
--- a/gcc/ada/gcc-interface/trans.c
+++ b/gcc/ada/gcc-interface/trans.c
@@ -1975,8 +1975,16 @@ Attribute_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, int attribute)
gcc_assert (TREE_CODE (gnu_type) == ARRAY_TYPE);
/* When not optimizing, look up the slot associated with the parameter
- and the dimension in the cache and create a new one on failure. */
- if (!optimize && Present (gnat_param))
+ and the dimension in the cache and create a new one on failure.
+ Don't do this when the actual subtype needs debug info (this happens
+ with -gnatD): in elaborate_expression_1, we create variables that
+ hold the bounds, so caching attributes isn't very interesting and
+ causes dependency issues between these variables and cached
+ expressions. */
+ if (!optimize
+ && Present (gnat_param)
+ && !(Present (Actual_Subtype (gnat_param))
+ && Needs_Debug_Info (Actual_Subtype (gnat_param))))
{
FOR_EACH_VEC_SAFE_ELT (f_parm_attr_cache, i, pa)
if (pa->id == gnat_param && pa->dim == Dimension)
@@ -4978,6 +4986,9 @@ Compilation_Unit_to_gnu (Node_Id gnat_node)
stabilization of the renamed entities may create SAVE_EXPRs which
have been tied to a specific elaboration routine just above. */
invalidate_global_renaming_pointers ();
+
+ /* Force the processing for all nodes that remain in the queue. */
+ process_deferred_decl_context (true);
}
/* Subroutine of gnat_to_gnu to translate gnat_node, an N_Raise_xxx_Error,
diff --git a/gcc/ada/gcc-interface/utils.c b/gcc/ada/gcc-interface/utils.c
index f44bda3..918b6cc 100644
--- a/gcc/ada/gcc-interface/utils.c
+++ b/gcc/ada/gcc-interface/utils.c
@@ -244,6 +244,32 @@ static tree float_type_for_precision (int, enum machine_mode);
static tree convert_to_fat_pointer (tree, tree);
static unsigned int scale_by_factor_of (tree, unsigned int);
static bool potential_alignment_gap (tree, tree, tree);
+
+/* A linked list used as a queue to defer the initialization of the
+ DECL_CONTEXT attribute of ..._DECL nodes and of the TYPE_CONTEXT attribute
+ of ..._TYPE nodes. */
+struct deferred_decl_context_node
+{
+ tree decl; /* The ..._DECL node to work on. */
+ Entity_Id gnat_scope; /* The corresponding entity's Scope attribute. */
+ int force_global; /* force_global value when pushing DECL. */
+ vec<tree, va_heap, vl_ptr> types; /* A list of ..._TYPE nodes to propagate the
+ context to. */
+ struct deferred_decl_context_node *next; /* The next queue item. */
+};
+
+static struct deferred_decl_context_node *deferred_decl_context_queue = NULL;
+
+/* Defer the initialization of DECL's DECL_CONTEXT attribute, scheduling to
+ feed it with the elaboration of GNAT_SCOPE. */
+static struct deferred_decl_context_node *
+add_deferred_decl_context (tree decl, Entity_Id gnat_scope, int force_global);
+
+/* Defer the initialization of TYPE's TYPE_CONTEXT attribute, scheduling to
+ feed it with the DECL_CONTEXT computed as part of N as soon as it is
+ computed. */
+static void add_deferred_type_context (struct deferred_decl_context_node *n,
+ tree type);
/* Initialize data structures of the utils.c module. */
@@ -554,31 +580,139 @@ gnat_set_type_context (tree type, tree context)
}
}
+/* Return the innermost scope, starting at GNAT_NODE, we are be interested in
+ the debug info, or Empty if there is no such scope. If not NULL, set
+ IS_SUBPROGRAM to whether the returned entity is a subprogram. */
+
+static Entity_Id
+get_debug_scope (Node_Id gnat_node, bool *is_subprogram)
+{
+ Entity_Id gnat_entity;
+
+ if (is_subprogram)
+ *is_subprogram = false;
+
+ if (Nkind (gnat_node) == N_Defining_Identifier)
+ gnat_entity = Scope (gnat_node);
+ else
+ return Empty;
+
+ while (Present (gnat_entity))
+ {
+ switch (Ekind (gnat_entity))
+ {
+ case E_Function:
+ case E_Procedure:
+ if (Present (Protected_Body_Subprogram (gnat_entity)))
+ gnat_entity = Protected_Body_Subprogram (gnat_entity);
+
+ /* If the scope is a subprogram, then just rely on
+ current_function_decl, so that we don't have to defer
+ anything. This is needed because other places rely on the
+ validity of the DECL_CONTEXT attribute of FUNCTION_DECL nodes. */
+ if (is_subprogram)
+ *is_subprogram = true;
+ return gnat_entity;
+
+ case E_Record_Type:
+ case E_Record_Subtype:
+ return gnat_entity;
+
+ default:
+ /* By default, we are not interested in this particular scope: go to
+ the outer one. */
+ break;
+ }
+ gnat_entity = Scope (gnat_entity);
+ }
+ return Empty;
+}
+
+/* If N is NULL, set TYPE's context to CONTEXT. Defer this to the processing of
+ N otherwise. */
+
+static void
+defer_or_set_type_context (tree type,
+ tree context,
+ struct deferred_decl_context_node *n)
+{
+ if (n)
+ add_deferred_type_context (n, type);
+ else
+ gnat_set_type_context (type, context);
+}
+
+/* Return global_context. Create it if needed, first. */
+
+static tree
+get_global_context (void)
+{
+ if (!global_context)
+ global_context = build_translation_unit_decl (NULL_TREE);
+ return global_context;
+}
+
/* Record DECL as belonging to the current lexical scope and use GNAT_NODE
for location information and flag propagation. */
void
gnat_pushdecl (tree decl, Node_Id gnat_node)
{
- /* If DECL is public external or at top level, it has global context. */
- if ((TREE_PUBLIC (decl) && DECL_EXTERNAL (decl)) || global_bindings_p ())
- {
- if (!global_context)
- global_context = build_translation_unit_decl (NULL_TREE);
- DECL_CONTEXT (decl) = global_context;
- }
- else
+ tree context = NULL_TREE;
+ struct deferred_decl_context_node *deferred_decl_context = NULL;
+
+ /* If explicitely asked to make DECL global or if it's an imported nested
+ object, short-circuit the regular Scope-based context computation. */
+ if (!((TREE_PUBLIC (decl) && DECL_EXTERNAL (decl)) || force_global == 1))
{
- DECL_CONTEXT (decl) = current_function_decl;
-
- /* Functions imported in another function are not really nested.
- For really nested functions mark them initially as needing
- a static chain for uses of that flag before unnesting;
- lower_nested_functions will then recompute it. */
- if (TREE_CODE (decl) == FUNCTION_DECL && !TREE_PUBLIC (decl))
- DECL_STATIC_CHAIN (decl) = 1;
+ /* Rely on the GNAT scope, or fallback to the current_function_decl if
+ the GNAT scope reached the global scope, if it reached a subprogram
+ or the declaration is a subprogram or a variable (for them we skip
+ intermediate context types because the subprogram body elaboration
+ machinery and the inliner both expect a subprogram context).
+
+ Falling back to current_function_decl is necessary for implicit
+ subprograms created by gigi, such as the elaboration subprograms. */
+ bool context_is_subprogram = false;
+ const Entity_Id gnat_scope
+ = get_debug_scope (gnat_node, &context_is_subprogram);
+
+ if (Present (gnat_scope)
+ && !context_is_subprogram
+ && TREE_CODE (decl) != FUNCTION_DECL
+ && TREE_CODE (decl) != VAR_DECL)
+ /* Always assume the scope has not been elaborated, thus defer the
+ context propagation to the time its elaboration will be
+ available. */
+ deferred_decl_context
+ = add_deferred_decl_context (decl, gnat_scope, force_global);
+
+ /* External declarations (when force_global > 0) may not be in a
+ local context. */
+ else if (current_function_decl != NULL_TREE && force_global == 0)
+ context = current_function_decl;
}
+ /* If either we are forced to be in global mode or if both the GNAT scope and
+ the current_function_decl did not help determining the context, use the
+ global scope. */
+ if (!deferred_decl_context && context == NULL_TREE)
+ context = get_global_context ();
+
+ /* Functions imported in another function are not really nested.
+ For really nested functions mark them initially as needing
+ a static chain for uses of that flag before unnesting;
+ lower_nested_functions will then recompute it. */
+ if (TREE_CODE (decl) == FUNCTION_DECL
+ && !TREE_PUBLIC (decl)
+ && context != NULL_TREE
+ && (TREE_CODE (context) == FUNCTION_DECL
+ || decl_function_context (context) != NULL_TREE))
+ DECL_STATIC_CHAIN (decl) = 1;
+
+ if (!deferred_decl_context)
+ DECL_CONTEXT (decl) = context;
+
TREE_NO_WARNING (decl) = (No (gnat_node) || Warnings_Off (gnat_node));
/* Set the location of DECL and emit a declaration for it. */
@@ -635,7 +769,9 @@ gnat_pushdecl (tree decl, Node_Id gnat_node)
if (TREE_CODE (t) == POINTER_TYPE)
TYPE_NEXT_PTR_TO (t) = tt;
TYPE_NAME (tt) = DECL_NAME (decl);
- gnat_set_type_context (tt, DECL_CONTEXT (decl));
+ defer_or_set_type_context (tt,
+ DECL_CONTEXT (decl),
+ deferred_decl_context);
TYPE_STUB_DECL (tt) = TYPE_STUB_DECL (t);
DECL_ORIGINAL_TYPE (decl) = tt;
}
@@ -645,7 +781,9 @@ gnat_pushdecl (tree decl, Node_Id gnat_node)
/* We need a variant for the placeholder machinery to work. */
tree tt = build_variant_type_copy (t);
TYPE_NAME (tt) = decl;
- gnat_set_type_context (tt, DECL_CONTEXT (decl));
+ defer_or_set_type_context (tt,
+ DECL_CONTEXT (decl),
+ deferred_decl_context);
TREE_USED (tt) = TREE_USED (t);
TREE_TYPE (decl) = tt;
if (DECL_ORIGINAL_TYPE (TYPE_NAME (t)))
@@ -667,7 +805,9 @@ gnat_pushdecl (tree decl, Node_Id gnat_node)
if (!(TYPE_NAME (t) && TREE_CODE (TYPE_NAME (t)) == TYPE_DECL))
{
TYPE_NAME (t) = decl;
- gnat_set_type_context (t, DECL_CONTEXT (decl));
+ defer_or_set_type_context (t,
+ DECL_CONTEXT (decl),
+ deferred_decl_context);
}
}
}
@@ -2590,6 +2730,146 @@ renaming_from_generic_instantiation_p (Node_Id gnat_node)
&& Present (Corresponding_Generic_Association (gnat_node)));
}
+/* Defer the initialization of DECL's DECL_CONTEXT attribute, scheduling to
+ feed it with the elaboration of GNAT_SCOPE. */
+
+static struct deferred_decl_context_node *
+add_deferred_decl_context (tree decl, Entity_Id gnat_scope, int force_global)
+{
+ struct deferred_decl_context_node *new_node;
+
+ new_node
+ = (struct deferred_decl_context_node * ) xmalloc (sizeof (*new_node));
+ new_node->decl = decl;
+ new_node->gnat_scope = gnat_scope;
+ new_node->force_global = force_global;
+ new_node->types.create (1);
+ new_node->next = deferred_decl_context_queue;
+ deferred_decl_context_queue = new_node;
+ return new_node;
+}
+
+/* Defer the initialization of TYPE's TYPE_CONTEXT attribute, scheduling to
+ feed it with the DECL_CONTEXT computed as part of N as soon as it is
+ computed. */
+
+static void
+add_deferred_type_context (struct deferred_decl_context_node *n, tree type)
+{
+ n->types.safe_push (type);
+}
+
+/* Get the GENERIC node corresponding to GNAT_SCOPE, if available. Return
+ NULL_TREE if it is not available. */
+
+static tree
+compute_deferred_decl_context (Entity_Id gnat_scope)
+{
+ tree context;
+
+ if (present_gnu_tree (gnat_scope))
+ context = get_gnu_tree (gnat_scope);
+ else
+ return NULL_TREE;
+
+ if (TREE_CODE (context) == TYPE_DECL)
+ {
+ const tree context_type = TREE_TYPE (context);
+
+ /* Skip dummy types: only the final ones can appear in the context
+ chain. */
+ if (TYPE_DUMMY_P (context_type))
+ return NULL_TREE;
+
+ /* ..._TYPE nodes are more useful than TYPE_DECL nodes in the context
+ chain. */
+ else
+ context = context_type;
+ }
+
+ return context;
+}
+
+/* Try to process all deferred nodes in the queue. Keep in the queue the ones
+ that cannot be processed yet, remove the other ones. If FORCE is true,
+ force the processing for all nodes, use the global context when nodes don't
+ have a GNU translation. */
+
+void
+process_deferred_decl_context (bool force)
+{
+ struct deferred_decl_context_node **it = &deferred_decl_context_queue;
+ struct deferred_decl_context_node *node;
+
+ while (*it != NULL)
+ {
+ bool processed = false;
+ tree context = NULL_TREE;
+ Entity_Id gnat_scope;
+
+ node = *it;
+
+ /* If FORCE, get the innermost elaborated scope. Otherwise, just try to
+ get the first scope. */
+ gnat_scope = node->gnat_scope;
+ while (Present (gnat_scope))
+ {
+ context = compute_deferred_decl_context (gnat_scope);
+ if (!force || context != NULL_TREE)
+ break;
+ gnat_scope = get_debug_scope (gnat_scope, NULL);
+ }
+
+ /* Imported declarations must not be in a local context (i.e. not inside
+ a function). */
+ if (context != NULL_TREE && node->force_global > 0)
+ {
+ tree ctx = context;
+
+ while (ctx != NULL_TREE)
+ {
+ gcc_assert (TREE_CODE (ctx) != FUNCTION_DECL);
+ ctx = (DECL_P (ctx))
+ ? DECL_CONTEXT (ctx)
+ : TYPE_CONTEXT (ctx);
+ }
+ }
+
+ /* If FORCE, we want to get rid of all nodes in the queue: in case there
+ was no elaborated scope, use the global context. */
+ if (force && context == NULL_TREE)
+ context = get_global_context ();
+
+ if (context != NULL_TREE)
+ {
+ tree t;
+ int i;
+
+ DECL_CONTEXT (node->decl) = context;
+
+ /* Propagate it to the TYPE_CONTEXT attributes of the requested
+ ..._TYPE nodes. */
+ FOR_EACH_VEC_ELT (node->types, i, t)
+ {
+ TYPE_CONTEXT (t) = context;
+ }
+ processed = true;
+ }
+
+ /* If this node has been successfuly processed, remove it from the
+ queue. Then move to the next node. */
+ if (processed)
+ {
+ *it = node->next;
+ node->types.release ();
+ free (node);
+ }
+ else
+ it = &node->next;
+ }
+}
+
+
/* Return VALUE scaled by the biggest power-of-2 factor of EXPR. */
static unsigned int
@@ -4868,7 +5148,7 @@ gnat_write_global_declarations (void)
for example pointers to Taft amendment types, have their compilation
finalized in the right context. */
FOR_EACH_VEC_SAFE_ELT (global_decls, i, iter)
- if (TREE_CODE (iter) == TYPE_DECL)
+ if (TREE_CODE (iter) == TYPE_DECL && !DECL_IGNORED_P (iter))
debug_hooks->global_decl (iter);
/* Proceed to optimize and emit assembly. */
@@ -4880,7 +5160,7 @@ gnat_write_global_declarations (void)
{
timevar_push (TV_SYMOUT);
FOR_EACH_VEC_SAFE_ELT (global_decls, i, iter)
- if (TREE_CODE (iter) != TYPE_DECL)
+ if (TREE_CODE (iter) != TYPE_DECL && !DECL_IGNORED_P (iter))
debug_hooks->global_decl (iter);
timevar_pop (TV_SYMOUT);
}
diff --git a/gcc/ada/gcc-interface/utils2.c b/gcc/ada/gcc-interface/utils2.c
index 3e4a094..8297c06 100644
--- a/gcc/ada/gcc-interface/utils2.c
+++ b/gcc/ada/gcc-interface/utils2.c
@@ -2002,7 +2002,8 @@ build_simple_component_ref (tree record_variable, tree component, tree field,
/* Look through a conversion between original and packable version, but
the field needs to be adjusted in this case. */
- else if (TYPE_NAME (inner_type) == TYPE_NAME (record_type))
+ else if (RECORD_OR_UNION_TYPE_P (inner_type)
+ && TYPE_NAME (inner_type) == TYPE_NAME (record_type))
{
tree new_field;