2010-09-19 Eric Botcazou <ebotcazou@adacore.com>
+ * gcc-interface/gigi.h (get_elaboration_procedure): Declare.
+ (gnat_zaplevel): Likewise.
+ * gcc-interface/decl.c (gnat_to_gnu_entity): Do not force global
+ binding level for an external constant.
+ <E_Constant>: Force the local context and create a fake scope before
+ translating the defining expression of an external constant.
+ <object>: Treat external constants at the global level explicitly for
+ renaming declarations.
+ (elaborate_expression_1): Force the variable to be static if the
+ expression is global.
+ * gcc-interface/trans.c (get_elaboration_procedure): New function.
+ (call_to_gnu): Use it.
+ (gnat_to_gnu): Likewise.
+ <N_Object_Declaration>: Do not test Is_Public to force the creation of
+ an initialization variable.
+ (add_decl_expr): Discard the statement if the declaration is external.
+ * gcc-interface/utils.c (gnat_pushdecl): Do not put the declaration in
+ the current block if it is external.
+ (create_var_decl_1): Do not test Is_Public to set TREE_STATIC.
+ (gnat_zaplevel): New global function.
+
+2010-09-19 Eric Botcazou <ebotcazou@adacore.com>
+
* gcc-interface/decl.c (gnat_to_gnu_entity): Explicitly test _LEVEL
variables against zero in all cases.
(rest_of_type_decl_compilation): Likewise.
another compilation unit) public entities, show we are at global level
for the purpose of computing scopes. Don't do this for components or
discriminants since the relevant test is whether or not the record is
- being defined. */
+ being defined. Don't do this for constants either as we'll look into
+ their defining expression in the local context. */
if (!definition
&& kind != E_Component
&& kind != E_Discriminant
+ && kind != E_Constant
&& Is_Public (gnat_entity)
&& !Is_Statically_Allocated (gnat_entity))
force_global++, this_global = true;
&& Present (Expression (Declaration_Node (gnat_entity)))
&& Nkind (Expression (Declaration_Node (gnat_entity)))
!= N_Allocator)
- gnu_expr = gnat_to_gnu (Expression (Declaration_Node (gnat_entity)));
+ {
+ bool went_into_elab_proc = false;
+
+ /* The expression may contain N_Expression_With_Actions nodes and
+ thus object declarations from other units. In this case, even
+ though the expression will eventually be discarded since not a
+ constant, the declarations would be stuck either in the global
+ varpool or in the current scope. Therefore we force the local
+ context and create a fake scope that we'll zap at the end. */
+ if (!current_function_decl)
+ {
+ current_function_decl = get_elaboration_procedure ();
+ went_into_elab_proc = true;
+ }
+ gnat_pushlevel ();
+
+ gnu_expr = gnat_to_gnu (Expression (Declaration_Node (gnat_entity)));
+
+ gnat_zaplevel ();
+ if (went_into_elab_proc)
+ current_function_decl = NULL_TREE;
+ }
/* Ignore deferred constant definitions without address clause since
they are processed fully in the front-end. If No_Initialization
that for the renaming. At the global level, we can only do
this if we know no SAVE_EXPRs need be made, because the
expression we return might be used in arbitrary conditional
- branches so we must force the SAVE_EXPRs evaluation
- immediately and this requires a function context. */
+ branches so we must force the evaluation of the SAVE_EXPRs
+ immediately and this requires a proper function context.
+ Note that an external constant is at the global level. */
if (!Materialize_Entity (gnat_entity)
- && (!global_bindings_p ()
+ && (!((!definition && kind == E_Constant)
+ || global_bindings_p ())
|| (staticp (gnu_expr)
&& !TREE_SIDE_EFFECTS (gnu_expr))))
{
{
/* ??? No DECL_EXPR is created so we need to mark
the expression manually lest it is shared. */
- if (global_bindings_p ())
+ if ((!definition && kind == E_Constant)
+ || global_bindings_p ())
MARK_VISITED (maybe_stable_expr);
gnu_decl = maybe_stable_expr;
save_gnu_tree (gnat_entity, gnu_decl, true);
}
/* If this is a renaming pointer, attach the renamed object to it and
- register it if we are at top level. */
+ register it if we are at the global level. Note that an external
+ constant is at the global level. */
if (TREE_CODE (gnu_decl) == VAR_DECL && renamed_obj)
{
SET_DECL_RENAMED_OBJECT (gnu_decl, renamed_obj);
- if (global_bindings_p ())
+ if ((!definition && kind == E_Constant) || global_bindings_p ())
{
DECL_RENAMING_GLOBAL_P (gnu_decl) = 1;
record_global_renaming_pointer (gnu_decl);
IDENTIFIER_POINTER (gnu_name)),
NULL_TREE, TREE_TYPE (gnu_expr), gnu_expr,
!need_debug, Is_Public (gnat_entity),
- !definition, false, NULL, gnat_entity);
+ !definition, expr_global, NULL, gnat_entity);
/* We only need to use this variable if we are in global context since GCC
can do the right thing in the local case. */
if none. */
extern tree get_exception_label (char kind);
+/* Return the decl for the current elaboration procedure. */
+extern tree get_elaboration_procedure (void);
+
/* If nonzero, pretend we are allocating at global level. */
extern int force_global;
/* Enter and exit a new binding level. */
extern void gnat_pushlevel (void);
extern void gnat_poplevel (void);
+extern void gnat_zaplevel (void);
/* Set SUPERCONTEXT of the BLOCK for the current binding level to FNDECL
and point FNDECL to this BLOCK. */
so we can give them the scope of the elaboration routine at top level. */
else if (!current_function_decl)
{
- current_function_decl = VEC_last (tree, gnu_elab_proc_stack);
+ current_function_decl = get_elaboration_procedure ();
went_into_elab_proc = true;
}
|| kind == N_Handled_Sequence_Of_Statements
|| (IN (kind, N_Raise_xxx_Error) && Ekind (Etype (gnat_node)) == E_Void))
{
+ tree current_elab_proc = get_elaboration_procedure ();
+
/* If this is a statement and we are at top level, it must be part of
the elaboration procedure, so mark us as being in that procedure. */
if (!current_function_decl)
{
- current_function_decl = VEC_last (tree, gnu_elab_proc_stack);
+ current_function_decl = current_elab_proc;
went_into_elab_proc = true;
}
every nested real statement instead. This also avoids triggering
spurious errors on dummy (empty) sequences created by the front-end
for package bodies in some cases. */
- if (current_function_decl == VEC_last (tree, gnu_elab_proc_stack)
+ if (current_function_decl == current_elab_proc
&& kind != N_Handled_Sequence_Of_Statements)
Check_Elaboration_Code_Allowed (gnat_node);
}
is frozen. */
if (Present (Freeze_Node (gnat_temp)))
{
- bool public_flag = Is_Public (gnat_temp);
-
if (TREE_CONSTANT (gnu_expr))
;
- else if (public_flag || global_bindings_p ())
+ else if (global_bindings_p ())
gnu_expr
= create_var_decl (create_concat_name (gnat_temp, "init"),
NULL_TREE, TREE_TYPE (gnu_expr), gnu_expr,
- false, public_flag, false, false,
+ false, false, false, false,
NULL, gnat_temp);
else
gnu_expr = gnat_save_expr (gnu_expr);
|| TREE_CODE (type) == QUAL_UNION_TYPE))
MARK_VISITED (TYPE_ADA_SIZE (type));
}
- else
+ else if (!DECL_EXTERNAL (gnu_decl))
add_stmt_with_node (gnu_stmt, gnat_entity);
/* If this is a variable and an initializer is attached to it, it must be
return NULL_TREE;
}
+/* Return the decl for the current elaboration procedure. */
+
+tree
+get_elaboration_procedure (void)
+{
+ return VEC_last (tree, gnu_elab_proc_stack);
+}
+
#include "gt-ada-trans.h"
free_binding_level = level;
}
+/* Exit a binding level and discard the associated BLOCK. */
+
+void
+gnat_zaplevel (void)
+{
+ struct gnat_binding_level *level = current_binding_level;
+ tree block = level->block;
+
+ BLOCK_CHAIN (block) = free_block_chain;
+ free_block_chain = block;
+
+ /* Free this binding structure. */
+ current_binding_level = level->chain;
+ level->chain = free_binding_level;
+ free_binding_level = level;
+}
\f
/* Records a ..._DECL node DECL as belonging to the current lexical scope
and uses GNAT_NODE for location information and propagating flags. */
add_decl_expr (decl, gnat_node);
/* Put the declaration on the list. The list of declarations is in reverse
- order. The list will be reversed later. Put global variables in the
- globals list and builtin functions in a dedicated list to speed up
- further lookups. Don't put TYPE_DECLs for UNCONSTRAINED_ARRAY_TYPE into
- the list, as they will cause trouble with the debugger and aren't needed
- anyway. */
- if (TREE_CODE (decl) != TYPE_DECL
- || TREE_CODE (TREE_TYPE (decl)) != UNCONSTRAINED_ARRAY_TYPE)
+ order. The list will be reversed later. Put global declarations in the
+ globals list and local ones in the current block. But skip TYPE_DECLs
+ for UNCONSTRAINED_ARRAY_TYPE in both cases, as they will cause trouble
+ with the debugger and aren't needed anyway. */
+ if (!(TREE_CODE (decl) == TYPE_DECL
+ && TREE_CODE (TREE_TYPE (decl)) == UNCONSTRAINED_ARRAY_TYPE))
{
if (global_bindings_p ())
{
if (TREE_CODE (decl) == FUNCTION_DECL && DECL_BUILT_IN (decl))
VEC_safe_push (tree, gc, builtin_decls, decl);
}
- else
+ else if (!DECL_EXTERNAL (decl))
{
tree block;
/* Fake PARM_DECLs go into the topmost block of the function. */
&& !have_global_bss_p ())
DECL_COMMON (var_decl) = 1;
- /* If it's public and not external, always allocate storage for it.
- At the global binding level we need to allocate static storage for the
- variable if and only if it's not external. If we are not at the top level
- we allocate automatic storage unless requested not to. */
+ /* At the global binding level, we need to allocate static storage for the
+ variable if it isn't external. Otherwise, we allocate automatic storage
+ unless requested not to. */
TREE_STATIC (var_decl)
- = !extern_flag && (public_flag || static_flag || global_bindings_p ());
+ = !extern_flag && (static_flag || global_bindings_p ());
/* For an external constant whose initializer is not absolute, do not emit
debug info. In DWARF this would mean a global relocation in a read-only
2010-09-19 Eric Botcazou <ebotcazou@adacore.com>
+ * gnat.dg/const1.adb: Rename into...
+ * gnat.dg/constant1.adb: ...this.
+ * gnat.dg/constant2.adb: New test.
+ * gnat.dg/constant2_pkg1.ads: New helper.
+ * gnat.dg/constant2_pkg2.ad[sb]: Likewise.
+
+2010-09-19 Eric Botcazou <ebotcazou@adacore.com>
+
* gnat.dg/specs/constant1.ads: New test.
* gnat.dg/specs/constant1_pkg.ads: New helper.
-- { dg-do compile }
-procedure const1 is
+procedure Constant1 is
Def_Const : constant Integer;
pragma Import (Ada, Def_Const);
begin
null;
-end const1;
+end;
--- /dev/null
+-- { dg-do run }
+-- { dg-options "-gnatVa" }
+
+with Constant2_Pkg1; use Constant2_Pkg1;
+
+procedure Constant2 is
+begin
+ if Val then
+ raise Program_Error;
+ end if;
+end;
--- /dev/null
+with Constant2_Pkg2; use Constant2_Pkg2;
+
+package Constant2_Pkg1 is
+
+ Val : constant Boolean := F1 and then F2;
+
+end Constant2_Pkg1;
--- /dev/null
+package body Constant2_Pkg2 is
+
+ function F1 return Boolean is
+ begin
+ return False;
+ end;
+
+ function F2 return Boolean is
+ begin
+ return False;
+ end;
+
+end Constant2_Pkg2;
--- /dev/null
+package Constant2_Pkg2 is
+
+ function F1 return Boolean;
+ function F2 return Boolean;
+
+end Constant2_Pkg2;