Commit 5e61ef09 by Thomas Quinot Committed by Arnaud Charlet

decl.c: Factor common code to build a storage type for an unconstrained object from a...

2005-11-14  Thomas Quinot  <quinot@adacore.com>
	    Olivier Hainque  <hainque@adacore.com>
	    Eric Botcazou  <ebotcazou@adacore.com>

	* decl.c:
	Factor common code to build a storage type for an unconstrained object
	from a fat or thin pointer type and a constrained object type.
	(annotate_value): Handle BIT_AND_EXPR.
	(annotate_rep): Don't restrict the back annotation of inherited
	components to the type_annotate_only case.
	(gnat_to_gnu_entity) <E_Array_Type>: Do not invoke create_type_decl if
	we are not defining the type.
	<E_Record_Type>: Likewise.
	(gnat_to_gnu_entity) <object, renaming>: Adjust comments and structure
	to get advantage of the new maybe_stabilize_reference interface, to
	ensure that what we reference is indeed stabilized instead of relying
	on assumptions on what the stabilizer does.
	(gnat_to_gnu_entity) <E_Incomplete_Type>: If the entity is an incomplete
	type imported through a limited_with clause, use its non-limited view.
	(Has_Stdcall_Convention): New macro, to centralize the Windows vs others
	differentiation.
	(gnat_to_gnu_entity): Use Has_Stdcall_Convention instead of a spread mix
	of #if sections + explicit comparisons of convention identifiers.
	(gnat_to_gnu_entity) <E_Variable>: Decrement force_global if necessary
	before early-returning for certain types when code generation is
	disabled.
	(gnat_to_gnu_entity) <object>: Adjust comment attached to the
	nullification of gnu_expr we do for objects with address clause and
	that we are not defining.
	(elaborate_expression_1): Do not create constants when creating
	variables needed by the debug info: the dwarf2 writer considers that
	CONST_DECLs is used only to represent enumeration constants, and emits
	nothing for them.
	(gnat_to_gnu_entity) <object>: When turning a non-definition of an
	object with an address clause into an indirect reference, drop the
	initializing expression.
	Include "expr.h".
	(STACK_CHECK_BUILTIN): Delete.
	(STACK_CHECK_PROBE_INTERVAL): Likewise.
	(STACK_CHECK_MAX_FRAME_SIZE): Likewise.
	(STACK_CHECK_MAX_VAR_SIZE): Likewise.
	(gnat_to_gnu_entity): If gnat_entity is a renaming, do not mark the tree
	corresponding to the renamed object as ignored for debugging purposes.

	* trans.c (tree_transform, case N_Attribute_Reference, case Attr_Size &
	related): For a prefix that is a dereference of a fat or thin pointer,
	if there is an actual subtype provided by the front-end, use that
	subtype to build an actual type with bounds template.
	(tree_transform, case N_Free_Statement): If an Actual_Designated_Subtype
	is provided by the front-end, use that subtype to compute the size of
	the deallocated object.
	(gnat_to_gnu): When adding a statement into an elaboration procedure,
	check for a potential violation of a No_Elaboration_Code restriction.
	(maybe_stabilize_reference): New function, like gnat_stabilize_reference
	with extra arguments to control whether to recurse through non-values
	and to let the caller know if the stabilization has succeeded.
	(gnat_stabilize_reference): Now a simple wrapper around
	maybe_stabilize, for common uses without restriction on lvalues and
	without need to check for the success indication.
	(gnat_to_gnu, call_to_gnu): Adjust calls to gnat_stabilize_reference, to
	pass false instead of 0 as the FORCE argument which is a bool.
	(Identifier_to_gnu): Remove checks ensuring that an renamed object
	attached to a renaming pointer has been properly stabilized, as no such
	object is attached otherwise.
	(call_to_gnu): Invoke create_var_decl to create the temporary when the
	function uses the "target pointer" return mechanism.
	Reinstate conversion of the actual to the type of the formal
	parameter before any other specific treatment based on the passing
	mechanism. This turns out to be necessary in order for PLACEHOLDER
	substitution to work properly when the latter type is unconstrained.

	* gigi.h (build_unc_object_type_from_ptr): New subprogram, factoring a
	common pattern.
	(maybe_stabilize_reference): New function, like gnat_stabilize_reference
	with extra arguments to control whether to recurse through non-values
	and to let the caller know if the stabilization has succeeded.

	* utils2.c (gnat_build_constructor): Only sort the fields for possible
	static output of record constructor if all the components are constant.
	(gnat_build_constructor): For a record type, sort the list of field
	initializers in increasing bit position order.
	Factor common code to build a storage type for an unconstrained object
	from a fat or thin pointer type and a constrained object type.
	(build_unary_op) <ADDR_EXPR>: Always recurse down conversions between
	types variants, and process special cases of VIEW_CONVERT expressions
	as their NOP_EXPR counterpart to ensure we get to the
	CORRESPONDING_VARs associated with CONST_DECls.
	(build_binary_op) <MODIFY_EXPR>: Do not strip VIEW_CONVERT_EXPRs
	on the right-hand side.

	* utils.c (build_unc_object_type_from_ptr): New subprogram, factoring
	a common pattern.
	(convert) <VIEW_CONVERT_EXPR>: Return the inner operand directly if we
	are converting back to its original type.
	(convert) <JM input>: Fallthrough regular conversion code instead of
	extracting the object if converting to a type variant.
	(create_var_decl): When a variable has an initializer requiring code
	generation and we are at the top level, check for a potential violation
	of a No_Elaboration_Code restriction.
	(create_var_decl): call expand_decl for CONST_DECLs, to set MODE, ALIGN
	SIZE and SIZE_UNIT which we need for later back-annotations.
	* utils.c: (convert) <STRING_CST>: Remove obsolete code.
	<VIEW_CONVERT_EXPR>: Do not lift the conversion if the target type
	is an unchecked union.
	(pushdecl): Set DECL_NO_STATIC_CHAIN on imported nested functions.
	(convert) <VIEW_CONVERT_EXPR>: When the types have the same
	main variant, just replace the VIEW_CONVERT_EXPR.
	<UNION_TYPE>: Revert 2005-03-02 change.

	* repinfo.h, repinfo.ads: Add tcode for BIT_AND_EXPR.

	* repinfo.adb (Print_Expr, Rep_Value): Handle Bit_And_Expressions.

From-SVN: r106961
parent fda5d6d4
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
#include "ggc.h" #include "ggc.h"
#include "obstack.h" #include "obstack.h"
#include "target.h" #include "target.h"
#include "expr.h"
#include "ada.h" #include "ada.h"
#include "types.h" #include "types.h"
...@@ -52,21 +53,14 @@ ...@@ -52,21 +53,14 @@
#include "ada-tree.h" #include "ada-tree.h"
#include "gigi.h" #include "gigi.h"
/* Provide default values for the macros controlling stack checking. /* Convention_Stdcall should be processed in a specific way on Windows targets
This is copied from GCC's expr.h. */ only. The macro below is a helper to avoid having to check for a Windows
specific attribute throughout this unit. */
#ifndef STACK_CHECK_BUILTIN #if TARGET_DLLIMPORT_DECL_ATTRIBUTES
#define STACK_CHECK_BUILTIN 0 #define Has_Stdcall_Convention(E) (Convention (E) == Convention_Stdcall)
#endif #else
#ifndef STACK_CHECK_PROBE_INTERVAL #define Has_Stdcall_Convention(E) (0)
#define STACK_CHECK_PROBE_INTERVAL 4096
#endif
#ifndef STACK_CHECK_MAX_FRAME_SIZE
#define STACK_CHECK_MAX_FRAME_SIZE \
(STACK_CHECK_PROBE_INTERVAL - UNITS_PER_WORD)
#endif
#ifndef STACK_CHECK_MAX_VAR_SIZE
#define STACK_CHECK_MAX_VAR_SIZE (STACK_CHECK_MAX_FRAME_SIZE / 100)
#endif #endif
/* These two variables are used to defer recursively expanding incomplete /* These two variables are used to defer recursively expanding incomplete
...@@ -531,6 +525,8 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition) ...@@ -531,6 +525,8 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition)
|| TREE_CODE (gnu_type) == VOID_TYPE) || TREE_CODE (gnu_type) == VOID_TYPE)
{ {
gcc_assert (type_annotate_only); gcc_assert (type_annotate_only);
if (this_global)
force_global--;
return error_mark_node; return error_mark_node;
} }
...@@ -670,11 +666,9 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition) ...@@ -670,11 +666,9 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition)
{ {
tree gnu_fat tree gnu_fat
= TREE_TYPE (gnat_to_gnu_type (Base_Type (Etype (gnat_entity)))); = TREE_TYPE (gnat_to_gnu_type (Base_Type (Etype (gnat_entity))));
tree gnu_temp_type
= TREE_TYPE (TREE_TYPE (TREE_CHAIN (TYPE_FIELDS (gnu_fat))));
gnu_type gnu_type
= build_unc_object_type (gnu_temp_type, gnu_type, = build_unc_object_type_from_ptr (gnu_fat, gnu_type,
concat_id_with_name (gnu_entity_id, concat_id_with_name (gnu_entity_id,
"UNC")); "UNC"));
} }
...@@ -729,18 +723,18 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition) ...@@ -729,18 +723,18 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition)
(TYPE_SIZE (TREE_TYPE (TYPE_FIELDS (gnu_type))))))) (TYPE_SIZE (TREE_TYPE (TYPE_FIELDS (gnu_type)))))))
gnu_expr = convert (gnu_type, gnu_expr); gnu_expr = convert (gnu_type, gnu_expr);
/* See if this is a renaming. If this is a constant renaming, treat /* See if this is a renaming, and handle appropriately depending on
it as a normal variable whose initial value is what is being what is renamed and in which context. There are three major
renamed. We cannot do this if the type is unconstrained or cases:
class-wide.
1/ This is a constant renaming and we can just make an object
with what is renamed as its initial value,
Otherwise, if what we are renaming is a reference, we can simply 2/ We can reuse a stabilized version of what is renamed in place
return a stabilized version of that reference, after forcing any of the renaming,
SAVE_EXPRs to be evaluated. But, if this is at global level, we
can only do this if we know no SAVE_EXPRs will be made.
Otherwise, make this into a constant pointer to the object we are 3/ If neither 1 or 2 applies, we make the renaming entity a constant
to rename. */ pointer to what is being renamed. */
if (Present (Renamed_Object (gnat_entity))) if (Present (Renamed_Object (gnat_entity)))
{ {
...@@ -756,6 +750,9 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition) ...@@ -756,6 +750,9 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition)
gnu_type = TREE_TYPE (gnu_expr); gnu_type = TREE_TYPE (gnu_expr);
} }
/* Case 1: If this is a constant renaming, treat it as a normal
object whose initial value is what is being renamed. We cannot
do this if the type is unconstrained or class-wide. */
if (const_flag if (const_flag
&& !TREE_SIDE_EFFECTS (gnu_expr) && !TREE_SIDE_EFFECTS (gnu_expr)
&& TREE_CODE (gnu_type) != UNCONSTRAINED_ARRAY_TYPE && TREE_CODE (gnu_type) != UNCONSTRAINED_ARRAY_TYPE
...@@ -764,49 +761,100 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition) ...@@ -764,49 +761,100 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition)
&& !Is_Array_Type (Etype (gnat_entity))) && !Is_Array_Type (Etype (gnat_entity)))
; ;
/* If this is a declaration or reference that we can stabilize, /* Otherwise, see if we can proceed with a stabilized version of
just use that declaration or reference as this entity unless the renamed entity or if we need to make a pointer. */
the latter has to be materialized. */
else if ((DECL_P (gnu_expr) || REFERENCE_CLASS_P (gnu_expr))
&& !Materialize_Entity (gnat_entity)
&& (!global_bindings_p ()
|| (staticp (gnu_expr)
&& !TREE_SIDE_EFFECTS (gnu_expr))))
{
gnu_decl = gnat_stabilize_reference (gnu_expr, true);
save_gnu_tree (gnat_entity, gnu_decl, true);
saved = true;
break;
}
/* Otherwise, make this into a constant pointer to the object we
are to rename and attach the object to the pointer. We need
to stabilize too since the renaming evaluation may directly
reference the renamed object instead of the pointer we will
attach it to. We don't want variables in the expression to
be evaluated every time the renaming is used, since their
value may change in between. */
else else
{ {
bool has_side_effects = TREE_SIDE_EFFECTS (gnu_expr); bool stabilized;
inner_const_flag = TREE_READONLY (gnu_expr); tree maybe_stable_expr = NULL_TREE;
const_flag = true;
gnu_type = build_reference_type (gnu_type); /* Case 2: If the renaming entity need not be materialized and
renamed_obj = gnat_stabilize_reference (gnu_expr, true); the renamed expression is something we can stabilize, use
gnu_expr = build_unary_op (ADDR_EXPR, gnu_type, renamed_obj); that for the renaming after forcing the evaluation of any
SAVE_EXPR. At the global level, we can only do this if we
if (!global_bindings_p ()) know no SAVE_EXPRs will be made. */
if (!Materialize_Entity (gnat_entity)
&& (!global_bindings_p ()
|| (staticp (gnu_expr)
&& !TREE_SIDE_EFFECTS (gnu_expr))))
{ {
/* If the original expression had side effects, put a maybe_stable_expr
SAVE_EXPR around this whole thing. */ = maybe_stabilize_reference (gnu_expr, true, false,
if (has_side_effects) &stabilized);
gnu_expr = save_expr (gnu_expr);
if (stabilized)
{
gnu_decl = maybe_stable_expr;
save_gnu_tree (gnat_entity, gnu_decl, true);
saved = true;
break;
}
add_stmt (gnu_expr); /* The stabilization failed. Keep maybe_stable_expr
untouched here to let the pointer case below know
about that failure. */
} }
gnu_size = NULL_TREE; /* Case 3: Make this into a constant pointer to the object we
used_by_ref = true; are to rename and attach the object to the pointer if it is
an lvalue that can be stabilized.
From the proper scope, attached objects will be referenced
directly instead of indirectly via the pointer to avoid
subtle aliasing problems with non addressable entities.
They have to be stable because we must not evaluate the
variables in the expression every time the renaming is used.
They also have to be lvalues because the context in which
they are reused sometimes requires so. We call pointers
with an attached object "renaming" pointers.
In the rare cases where we cannot stabilize the renamed
object, we just make a "bare" pointer, and the renamed
entity is always accessed indirectly through it. */
{
bool has_side_effects = TREE_SIDE_EFFECTS (gnu_expr);
inner_const_flag = TREE_READONLY (gnu_expr);
const_flag = true;
gnu_type = build_reference_type (gnu_type);
/* If a previous attempt at unrestricted
stabilization failed, there is no point trying
again and we can reuse the result without
attaching it to the pointer. */
if (maybe_stable_expr)
;
/* Otherwise, try to stabilize now, restricting to
lvalues only, and attach the expression to the pointer
if the stabilization succeeds. */
else
{
maybe_stable_expr
= maybe_stabilize_reference (gnu_expr, true, true,
&stabilized);
if (stabilized)
renamed_obj = maybe_stable_expr;
/* Attaching is actually performed downstream, as soon
as we have a DECL for the pointer we make. */
}
gnu_expr
= build_unary_op (ADDR_EXPR, gnu_type, maybe_stable_expr);
if (!global_bindings_p ())
{
/* If the original expression had side effects, put a
SAVE_EXPR around this whole thing. */
if (has_side_effects)
gnu_expr = save_expr (gnu_expr);
add_stmt (gnu_expr);
}
gnu_size = NULL_TREE;
used_by_ref = true;
}
} }
} }
...@@ -894,10 +942,15 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition) ...@@ -894,10 +942,15 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition)
imported. */ imported. */
if ((!definition && Present (Address_Clause (gnat_entity))) if ((!definition && Present (Address_Clause (gnat_entity)))
|| (Is_Imported (gnat_entity) || (Is_Imported (gnat_entity)
&& Convention (gnat_entity) == Convention_Stdcall)) && Has_Stdcall_Convention (gnat_entity)))
{ {
gnu_type = build_reference_type (gnu_type); gnu_type = build_reference_type (gnu_type);
gnu_size = NULL_TREE; gnu_size = NULL_TREE;
gnu_expr = NULL_TREE;
/* No point in taking the address of an initializing expression
that isn't going to be used. */
used_by_ref = true; used_by_ref = true;
} }
...@@ -1495,19 +1548,11 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition) ...@@ -1495,19 +1548,11 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition)
TYPE_READONLY (gnu_template_type) = 1; TYPE_READONLY (gnu_template_type) = 1;
/* Make a node for the array. If we are not defining the array /* Make a node for the array. If we are not defining the array
suppress expanding incomplete types and save the node as the type suppress expanding incomplete types. */
for GNAT_ENTITY. */
gnu_type = make_node (UNCONSTRAINED_ARRAY_TYPE); gnu_type = make_node (UNCONSTRAINED_ARRAY_TYPE);
if (!definition) if (!definition)
{ defer_incomplete_level++, this_deferred = true;
defer_incomplete_level++;
this_deferred = this_made_decl = true;
gnu_decl = create_type_decl (gnu_entity_id, gnu_type, attr_list,
!Comes_From_Source (gnat_entity),
debug_info_p, gnat_entity);
save_gnu_tree (gnat_entity, gnu_decl, false);
saved = true;
}
/* Build the fat pointer type. Use a "void *" object instead of /* Build the fat pointer type. Use a "void *" object instead of
a pointer to the array type since we don't have the array type a pointer to the array type since we don't have the array type
...@@ -2310,9 +2355,9 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition) ...@@ -2310,9 +2355,9 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition)
} }
/* Make a node for the record. If we are not defining the record, /* Make a node for the record. If we are not defining the record,
suppress expanding incomplete types and save the node as the type suppress expanding incomplete types. We use the same RECORD_TYPE
for GNAT_ENTITY. We use the same RECORD_TYPE as for a dummy type as for a dummy type and reset TYPE_DUMMY_P to show it's no longer
and reset TYPE_DUMMY_P to show it's no longer a dummy. a dummy.
It is very tempting to delay resetting this bit until we are done It is very tempting to delay resetting this bit until we are done
with completing the type, e.g. to let possible intermediate with completing the type, e.g. to let possible intermediate
...@@ -2335,15 +2380,7 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition) ...@@ -2335,15 +2380,7 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition)
TYPE_PACKED (gnu_type) = packed || has_rep; TYPE_PACKED (gnu_type) = packed || has_rep;
if (!definition) if (!definition)
{ defer_incomplete_level++, this_deferred = true;
defer_incomplete_level++;
this_deferred = true;
gnu_decl = create_type_decl (gnu_entity_id, gnu_type, attr_list,
!Comes_From_Source (gnat_entity),
debug_info_p, gnat_entity);
save_gnu_tree (gnat_entity, gnu_decl, false);
this_made_decl = saved = true;
}
/* If both a size and rep clause was specified, put the size in /* If both a size and rep clause was specified, put the size in
the record type now so that it can get the proper mode. */ the record type now so that it can get the proper mode. */
...@@ -3642,8 +3679,7 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition) ...@@ -3642,8 +3679,7 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition)
if (list_length (gnu_return_list) == 1) if (list_length (gnu_return_list) == 1)
gnu_return_type = TREE_TYPE (TREE_PURPOSE (gnu_return_list)); gnu_return_type = TREE_TYPE (TREE_PURPOSE (gnu_return_list));
#ifdef TARGET_DLLIMPORT_DECL_ATTRIBUTES if (Has_Stdcall_Convention (gnat_entity))
if (Convention (gnat_entity) == Convention_Stdcall)
{ {
struct attrib *attr struct attrib *attr
= (struct attrib *) xmalloc (sizeof (struct attrib)); = (struct attrib *) xmalloc (sizeof (struct attrib));
...@@ -3655,7 +3691,6 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition) ...@@ -3655,7 +3691,6 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition)
attr->error_point = gnat_entity; attr->error_point = gnat_entity;
attr_list = attr; attr_list = attr;
} }
#endif
/* Both lists ware built in reverse. */ /* Both lists ware built in reverse. */
gnu_param_list = nreverse (gnu_param_list); gnu_param_list = nreverse (gnu_param_list);
...@@ -3766,14 +3801,23 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition) ...@@ -3766,14 +3801,23 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition)
compiling, then just get the type from its Etype. */ compiling, then just get the type from its Etype. */
if (No (Full_View (gnat_entity))) if (No (Full_View (gnat_entity)))
{ {
/* If this is an incomplete type with no full view, it must /* If this is an incomplete type with no full view, it must be
be a Taft Amendement type, so just return a dummy type. */ either a limited view brought in by a limited_with clause, in
which case we use the non-limited view, or a Taft Amendement
type, in which case we just return a dummy type. */
if (kind == E_Incomplete_Type) if (kind == E_Incomplete_Type)
gnu_type = make_dummy_type (gnat_entity); {
if (From_With_Type (gnat_entity)
&& Present (Non_Limited_View (gnat_entity)))
gnu_decl = gnat_to_gnu_entity (Non_Limited_View (gnat_entity),
NULL_TREE, 0);
else
gnu_type = make_dummy_type (gnat_entity);
}
else if (Present (Underlying_Full_View (gnat_entity))) else if (Present (Underlying_Full_View (gnat_entity)))
gnu_decl = gnat_to_gnu_entity (Underlying_Full_View (gnat_entity), gnu_decl = gnat_to_gnu_entity (Underlying_Full_View (gnat_entity),
NULL_TREE, 0); NULL_TREE, 0);
else else
{ {
gnu_decl = gnat_to_gnu_entity (Etype (gnat_entity), gnu_decl = gnat_to_gnu_entity (Etype (gnat_entity),
...@@ -4087,7 +4131,8 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition) ...@@ -4087,7 +4131,8 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition)
DECL_ARTIFICIAL (gnu_decl) = 1; DECL_ARTIFICIAL (gnu_decl) = 1;
if (!debug_info_p && DECL_P (gnu_decl) if (!debug_info_p && DECL_P (gnu_decl)
&& TREE_CODE (gnu_decl) != FUNCTION_DECL) && TREE_CODE (gnu_decl) != FUNCTION_DECL
&& No (Renamed_Object (gnat_entity)))
DECL_IGNORED_P (gnu_decl) = 1; DECL_IGNORED_P (gnu_decl) = 1;
/* If we haven't already, associate the ..._DECL node that we just made with /* If we haven't already, associate the ..._DECL node that we just made with
...@@ -4703,9 +4748,9 @@ elaborate_expression_1 (Node_Id gnat_expr, Entity_Id gnat_entity, ...@@ -4703,9 +4748,9 @@ elaborate_expression_1 (Node_Id gnat_expr, Entity_Id gnat_entity,
gnu_decl gnu_decl
= create_var_decl (create_concat_name (gnat_entity, = create_var_decl (create_concat_name (gnat_entity,
IDENTIFIER_POINTER (gnu_name)), IDENTIFIER_POINTER (gnu_name)),
NULL_TREE, TREE_TYPE (gnu_expr), gnu_expr, true, NULL_TREE, TREE_TYPE (gnu_expr), gnu_expr,
Is_Public (gnat_entity), !definition, false, NULL, !need_debug, Is_Public (gnat_entity),
gnat_entity); !definition, false, NULL, gnat_entity);
/* We only need to use this variable if we are in global context since GCC /* We only need to use this variable if we are in global context since GCC
can do the right thing in the local case. */ can do the right thing in the local case. */
...@@ -5812,6 +5857,7 @@ annotate_value (tree gnu_size) ...@@ -5812,6 +5857,7 @@ annotate_value (tree gnu_size)
case TRUTH_OR_EXPR: tcode = Truth_Or_Expr; break; case TRUTH_OR_EXPR: tcode = Truth_Or_Expr; break;
case TRUTH_XOR_EXPR: tcode = Truth_Xor_Expr; break; case TRUTH_XOR_EXPR: tcode = Truth_Xor_Expr; break;
case TRUTH_NOT_EXPR: tcode = Truth_Not_Expr; break; case TRUTH_NOT_EXPR: tcode = Truth_Not_Expr; break;
case BIT_AND_EXPR: tcode = Bit_And_Expr; break;
case LT_EXPR: tcode = Lt_Expr; break; case LT_EXPR: tcode = Lt_Expr; break;
case LE_EXPR: tcode = Le_Expr; break; case LE_EXPR: tcode = Le_Expr; break;
case GT_EXPR: tcode = Gt_Expr; break; case GT_EXPR: tcode = Gt_Expr; break;
...@@ -5898,8 +5944,7 @@ annotate_rep (Entity_Id gnat_entity, tree gnu_type) ...@@ -5898,8 +5944,7 @@ annotate_rep (Entity_Id gnat_entity, tree gnu_type)
Set_Esize (gnat_field, Set_Esize (gnat_field,
annotate_value (DECL_SIZE (TREE_PURPOSE (gnu_entry)))); annotate_value (DECL_SIZE (TREE_PURPOSE (gnu_entry))));
} }
else if (type_annotate_only else if (Is_Tagged_Type (gnat_entity)
&& Is_Tagged_Type (gnat_entity)
&& Is_Derived_Type (gnat_entity)) && Is_Derived_Type (gnat_entity))
{ {
/* If there is no gnu_entry, this is an inherited component whose /* If there is no gnu_entry, this is an inherited component whose
...@@ -6638,32 +6683,28 @@ rm_size (tree gnu_type) ...@@ -6638,32 +6683,28 @@ rm_size (tree gnu_type)
tree tree
create_concat_name (Entity_Id gnat_entity, const char *suffix) create_concat_name (Entity_Id gnat_entity, const char *suffix)
{ {
Entity_Kind kind = Ekind (gnat_entity);
const char *str = (!suffix ? "" : suffix); const char *str = (!suffix ? "" : suffix);
String_Template temp = {1, strlen (str)}; String_Template temp = {1, strlen (str)};
Fat_Pointer fp = {str, &temp}; Fat_Pointer fp = {str, &temp};
Get_External_Name_With_Suffix (gnat_entity, fp); Get_External_Name_With_Suffix (gnat_entity, fp);
#ifdef TARGET_DLLIMPORT_DECL_ATTRIBUTES
/* A variable using the Stdcall convention (meaning we are running /* A variable using the Stdcall convention (meaning we are running
on a Windows box) live in a DLL. Here we adjust its name to use on a Windows box) live in a DLL. Here we adjust its name to use
the jump-table, the _imp__NAME contains the address for the NAME the jump-table, the _imp__NAME contains the address for the NAME
variable. */ variable. */
{ if ((kind == E_Variable || kind == E_Constant)
Entity_Kind kind = Ekind (gnat_entity); && Has_Stdcall_Convention (gnat_entity))
const char *prefix = "_imp__"; {
int plen = strlen (prefix); const char *prefix = "_imp__";
int k, plen = strlen (prefix);
if ((kind == E_Variable || kind == E_Constant) for (k = 0; k <= Name_Len; k++)
&& Convention (gnat_entity) == Convention_Stdcall) Name_Buffer [Name_Len - k + plen] = Name_Buffer [Name_Len - k];
{ strncpy (Name_Buffer, prefix, plen);
int k; }
for (k = 0; k <= Name_Len; k++)
Name_Buffer [Name_Len - k + plen] = Name_Buffer [Name_Len - k];
strncpy (Name_Buffer, prefix, plen);
}
}
#endif
return get_identifier (Name_Buffer); return get_identifier (Name_Buffer);
} }
......
...@@ -248,9 +248,21 @@ extern void init_code_table (void); ...@@ -248,9 +248,21 @@ extern void init_code_table (void);
called. */ called. */
extern Node_Id error_gnat_node; extern Node_Id error_gnat_node;
/* This is equivalent to stabilize_reference in GCC's tree.c, but we know /* This is equivalent to stabilize_reference in GCC's tree.c, but we know how
how to handle our new nodes and we take an extra argument that says to handle our new nodes and we take extra arguments.
whether to force evaluation of everything. */
FORCE says whether to force evaluation of everything,
SUCCESS we set to true unless we walk through something we don't
know how to stabilize, or through something which is not an lvalue
and LVALUES_ONLY is true, in which cases we set to false. */
extern tree maybe_stabilize_reference (tree ref, bool force, bool lvalues_only,
bool *success);
/* Wrapper around maybe_stabilize_reference, for common uses without
lvalue restrictions and without need to examine the success
indication. */
extern tree gnat_stabilize_reference (tree ref, bool force); extern tree gnat_stabilize_reference (tree ref, bool force);
/* Highest number in the front-end node table. */ /* Highest number in the front-end node table. */
...@@ -612,6 +624,11 @@ extern tree build_vms_descriptor (tree type, Mechanism_Type mech, ...@@ -612,6 +624,11 @@ extern tree build_vms_descriptor (tree type, Mechanism_Type mech,
extern tree build_unc_object_type (tree template_type, tree object_type, extern tree build_unc_object_type (tree template_type, tree object_type,
tree name); tree name);
/* Same as build_unc_object_type, but taking a thin or fat pointer type
instead of the template type. */
extern tree build_unc_object_type_from_ptr (tree thin_fat_ptr_type,
tree object_type, tree name);
/* Update anything previously pointing to OLD_TYPE to point to NEW_TYPE. In /* Update anything previously pointing to OLD_TYPE to point to NEW_TYPE. In
the normal case this is just two adjustments, but we have more to do the normal case this is just two adjustments, but we have more to do
if NEW is an UNCONSTRAINED_ARRAY_TYPE. */ if NEW is an UNCONSTRAINED_ARRAY_TYPE. */
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
-- -- -- --
-- B o d y -- -- B o d y --
-- -- -- --
-- Copyright (C) 1999-2004 Free Software Foundation, Inc. -- -- Copyright (C) 1999-2005 Free Software Foundation, Inc. --
-- -- -- --
-- GNAT is free software; you can redistribute it and/or modify it under -- -- GNAT is free software; you can redistribute it and/or modify it under --
-- terms of the GNU General Public License as published by the Free Soft- -- -- terms of the GNU General Public License as published by the Free Soft- --
...@@ -48,6 +48,8 @@ with Table; use Table; ...@@ -48,6 +48,8 @@ with Table; use Table;
with Uname; use Uname; with Uname; use Uname;
with Urealp; use Urealp; with Urealp; use Urealp;
with Ada.Unchecked_Conversion;
package body Repinfo is package body Repinfo is
SSU : constant := 8; SSU : constant := 8;
...@@ -61,17 +63,16 @@ package body Repinfo is ...@@ -61,17 +63,16 @@ package body Repinfo is
-- Representation of gcc Expressions -- -- Representation of gcc Expressions --
--------------------------------------- ---------------------------------------
-- This table is used only if Frontend_Layout_On_Target is False, -- This table is used only if Frontend_Layout_On_Target is False, so that
-- so that gigi lays out dynamic size/offset fields using encoded -- gigi lays out dynamic size/offset fields using encoded gcc
-- gcc expressions. -- expressions.
-- A table internal to this unit is used to hold the values of -- A table internal to this unit is used to hold the values of back
-- back annotated expressions. This table is written out by -gnatt -- annotated expressions. This table is written out by -gnatt and read
-- and read back in for ASIS processing. -- back in for ASIS processing.
-- Node values are stored as Uint values which are the negative of -- Node values are stored as Uint values using the negative of the node
-- the node index in this table. Constants appear as non-negative -- index in this table. Constants appear as non-negative Uint values.
-- Uint values.
type Exp_Node is record type Exp_Node is record
Expr : TCode; Expr : TCode;
...@@ -104,28 +105,27 @@ package body Repinfo is ...@@ -104,28 +105,27 @@ package body Repinfo is
-- Identifier casing for current unit -- Identifier casing for current unit
Need_Blank_Line : Boolean; Need_Blank_Line : Boolean;
-- Set True if a blank line is needed before outputting any -- Set True if a blank line is needed before outputting any information for
-- information for the current entity. Set True when a new -- the current entity. Set True when a new entity is processed, and false
-- entity is processed, and false when the blank line is output. -- when the blank line is output.
----------------------- -----------------------
-- Local Subprograms -- -- Local Subprograms --
----------------------- -----------------------
function Back_End_Layout return Boolean; function Back_End_Layout return Boolean;
-- Test for layout mode, True = back end, False = front end. This -- Test for layout mode, True = back end, False = front end. This function
-- function is used rather than checking the configuration parameter -- is used rather than checking the configuration parameter because we do
-- because we do not want Repinfo to depend on Targparm (for ASIS) -- not want Repinfo to depend on Targparm (for ASIS)
procedure Blank_Line; procedure Blank_Line;
-- Called before outputting anything for an entity. Ensures that -- Called before outputting anything for an entity. Ensures that
-- a blank line precedes the output for a particular entity. -- a blank line precedes the output for a particular entity.
procedure List_Entities (Ent : Entity_Id); procedure List_Entities (Ent : Entity_Id);
-- This procedure lists the entities associated with the entity E, -- This procedure lists the entities associated with the entity E, starting
-- starting with the First_Entity and using the Next_Entity link. -- with the First_Entity and using the Next_Entity link. If a nested
-- If a nested package is found, entities within the package are -- package is found, entities within the package are recursively processed.
-- recursively processed.
procedure List_Name (Ent : Entity_Id); procedure List_Name (Ent : Entity_Id);
-- List name of entity Ent in appropriate case. The name is listed with -- List name of entity Ent in appropriate case. The name is listed with
...@@ -135,8 +135,8 @@ package body Repinfo is ...@@ -135,8 +135,8 @@ package body Repinfo is
-- List representation info for array type Ent -- List representation info for array type Ent
procedure List_Mechanisms (Ent : Entity_Id); procedure List_Mechanisms (Ent : Entity_Id);
-- List mechanism information for parameters of Ent, which is a -- List mechanism information for parameters of Ent, which is subprogram,
-- subprogram, subprogram type, or an entry or entry family. -- subprogram type, or an entry or entry family.
procedure List_Object_Info (Ent : Entity_Id); procedure List_Object_Info (Ent : Entity_Id);
-- List representation info for object Ent -- List representation info for object Ent
...@@ -155,12 +155,11 @@ package body Repinfo is ...@@ -155,12 +155,11 @@ package body Repinfo is
-- Output given number of spaces -- Output given number of spaces
procedure Write_Info_Line (S : String); procedure Write_Info_Line (S : String);
-- Routine to write a line to Repinfo output file. This routine is -- Routine to write a line to Repinfo output file. This routine is passed
-- passed as a special output procedure to Output.Set_Special_Output. -- as a special output procedure to Output.Set_Special_Output. Note that
-- Note that Write_Info_Line is called with an EOL character at the -- Write_Info_Line is called with an EOL character at the end of each line,
-- end of each line, as per the Output spec, but the internal call -- as per the Output spec, but the internal call to the appropriate routine
-- to the appropriate routine in Osint requires that the end of line -- in Osint requires that the end of line sequence be stripped off.
-- sequence be stripped off.
procedure Write_Mechanism (M : Mechanism_Type); procedure Write_Mechanism (M : Mechanism_Type);
-- Writes symbolic string for mechanism represented by M -- Writes symbolic string for mechanism represented by M
...@@ -168,8 +167,8 @@ package body Repinfo is ...@@ -168,8 +167,8 @@ package body Repinfo is
procedure Write_Val (Val : Node_Ref_Or_Val; Paren : Boolean := False); procedure Write_Val (Val : Node_Ref_Or_Val; Paren : Boolean := False);
-- Given a representation value, write it out. No_Uint values or values -- Given a representation value, write it out. No_Uint values or values
-- dependent on discriminants are written as two question marks. If the -- dependent on discriminants are written as two question marks. If the
-- flag Paren is set, then the output is surrounded in parentheses if -- flag Paren is set, then the output is surrounded in parentheses if it is
-- it is other than a simple value. -- other than a simple value.
--------------------- ---------------------
-- Back_End_Layout -- -- Back_End_Layout --
...@@ -177,8 +176,8 @@ package body Repinfo is ...@@ -177,8 +176,8 @@ package body Repinfo is
function Back_End_Layout return Boolean is function Back_End_Layout return Boolean is
begin begin
-- We have back end layout if the back end has made any entries in -- We have back end layout if the back end has made any entries in the
-- the table of GCC expressions, otherwise we have front end layout. -- table of GCC expressions, otherwise we have front end layout.
return Rep_Table.Last > 0; return Rep_Table.Last > 0;
end Back_End_Layout; end Back_End_Layout;
...@@ -350,10 +349,10 @@ package body Repinfo is ...@@ -350,10 +349,10 @@ package body Repinfo is
while Present (E) loop while Present (E) loop
Need_Blank_Line := True; Need_Blank_Line := True;
-- We list entities that come from source (excluding private -- We list entities that come from source (excluding private or
-- or incomplete types or deferred constants, where we will -- incomplete types or deferred constants, where we will list the
-- list the info for the full view). If debug flag A is set, -- info for the full view). If debug flag A is set, then all
-- then all entities are listed -- entities are listed
if (Comes_From_Source (E) if (Comes_From_Source (E)
and then not Is_Incomplete_Or_Private_Type (E) and then not Is_Incomplete_Or_Private_Type (E)
...@@ -402,10 +401,9 @@ package body Repinfo is ...@@ -402,10 +401,9 @@ package body Repinfo is
end if; end if;
-- Recurse into nested package, but not if they are -- Recurse into nested package, but not if they are package
-- package renamings (in particular renamings of the -- renamings (in particular renamings of the enclosing package,
-- enclosing package, as for some Java bindings and -- as for some Java bindings and for generic instances).
-- for generic instances).
if Ekind (E) = E_Package then if Ekind (E) = E_Package then
if No (Renamed_Object (E)) then if No (Renamed_Object (E)) then
...@@ -438,10 +436,10 @@ package body Repinfo is ...@@ -438,10 +436,10 @@ package body Repinfo is
E := Next_Entity (E); E := Next_Entity (E);
end loop; end loop;
-- For a package body, the entities of the visible subprograms -- For a package body, the entities of the visible subprograms are
-- are declared in the corresponding spec. Iterate over its -- declared in the corresponding spec. Iterate over its entities in
-- entities in order to handle properly the subprogram bodies. -- order to handle properly the subprogram bodies. Skip bodies in
-- Skip bodies in subunits, which are listed independently. -- subunits, which are listed independently.
if Ekind (Ent) = E_Package_Body if Ekind (Ent) = E_Package_Body
and then Present (Corresponding_Spec (Find_Declaration (Ent))) and then Present (Corresponding_Spec (Find_Declaration (Ent)))
...@@ -583,6 +581,9 @@ package body Repinfo is ...@@ -583,6 +581,9 @@ package body Repinfo is
Write_Str ("not "); Write_Str ("not ");
Print_Expr (Node.Op1); Print_Expr (Node.Op1);
when Bit_And_Expr =>
Binop (" & ");
when Lt_Expr => when Lt_Expr =>
Binop (" < "); Binop (" < ");
...@@ -801,9 +802,9 @@ package body Repinfo is ...@@ -801,9 +802,9 @@ package body Repinfo is
UI_Image (Sunit); UI_Image (Sunit);
end if; end if;
-- If the record is not packed, then we know that all -- If the record is not packed, then we know that all fields whose
-- fields whose position is not specified have a starting -- position is not specified have a starting normalized bit
-- normalized bit position of zero -- position of zero
if Unknown_Normalized_First_Bit (Comp) if Unknown_Normalized_First_Bit (Comp)
and then not Is_Packed (Ent) and then not Is_Packed (Ent)
...@@ -885,11 +886,11 @@ package body Repinfo is ...@@ -885,11 +886,11 @@ package body Repinfo is
UI_Write (Fbit); UI_Write (Fbit);
Write_Str (" .. "); Write_Str (" .. ");
-- Allowing Uint_0 here is a kludge, really this should be -- Allowing Uint_0 here is a kludge, really this should be a
-- a fine Esize value but currently it means unknown, except -- fine Esize value but currently it means unknown, except that
-- that we know after gigi has back annotated that a size of -- we know after gigi has back annotated that a size of zero is
-- zero is real, since otherwise gigi back annotates using -- real, since otherwise gigi back annotates using No_Uint as
-- No_Uint as the value to indicate unknown). -- the value to indicate unknown).
if (Esize (Comp) = Uint_0 or else Known_Static_Esize (Comp)) if (Esize (Comp) = Uint_0 or else Known_Static_Esize (Comp))
and then Known_Static_Normalized_First_Bit (Comp) and then Known_Static_Normalized_First_Bit (Comp)
...@@ -916,8 +917,8 @@ package body Repinfo is ...@@ -916,8 +917,8 @@ package body Repinfo is
Write_Val (Esiz, Paren => True); Write_Val (Esiz, Paren => True);
-- If in front end layout mode, then dynamic size is -- If in front end layout mode, then dynamic size is stored
-- stored in storage units, so renormalize for output -- in storage units, so renormalize for output
if not Back_End_Layout then if not Back_End_Layout then
Write_Str (" * "); Write_Str (" * ");
...@@ -1019,8 +1020,8 @@ package body Repinfo is ...@@ -1019,8 +1020,8 @@ package body Repinfo is
Write_Line (";"); Write_Line (";");
-- For now, temporary case, to be removed when gigi properly back -- For now, temporary case, to be removed when gigi properly back
-- annotates RM_Size, if RM_Size is not set, then list Esize as -- annotates RM_Size, if RM_Size is not set, then list Esize as Size.
-- Size. This avoids odd Object_Size output till we fix things??? -- This avoids odd Object_Size output till we fix things???
elsif Unknown_RM_Size (Ent) then elsif Unknown_RM_Size (Ent) then
Write_Str ("for "); Write_Str ("for ");
...@@ -1086,6 +1087,14 @@ package body Repinfo is ...@@ -1086,6 +1087,14 @@ package body Repinfo is
function V (Val : Node_Ref_Or_Val) return Uint; function V (Val : Node_Ref_Or_Val) return Uint;
-- Internal recursive routine to evaluate tree -- Internal recursive routine to evaluate tree
function W (Val : Uint) return Word;
-- Convert Val to Word, assuming Val is always in the Int range. This is
-- a helper function for the evaluation of bitwise expressions like
-- Bit_And_Expr, for which there is no direct support in uintp. Uint
-- values out of the Int range are expected to be seen in such
-- expressions only with overflowing byte sizes around, introducing
-- inherent unreliabilties in computations anyway.
------- -------
-- B -- -- B --
------- -------
...@@ -1113,6 +1122,23 @@ package body Repinfo is ...@@ -1113,6 +1122,23 @@ package body Repinfo is
end T; end T;
------- -------
-- W --
-------
-- We use an unchecked conversion to map Int values to their Word
-- bitwise equivalent, which we could not achieve with a normal type
-- conversion for negative Ints. We want bitwise equivalents because W
-- is used as a helper for bit operators like Bit_And_Expr, and can be
-- called for negative Ints in the context of aligning expressions like
-- X+Align & -Align.
function W (Val : Uint) return Word is
function To_Word is new Ada.Unchecked_Conversion (Int, Word);
begin
return To_Word (UI_To_Int (Val));
end W;
-------
-- V -- -- V --
------- -------
...@@ -1203,6 +1229,11 @@ package body Repinfo is ...@@ -1203,6 +1229,11 @@ package body Repinfo is
when Truth_Not_Expr => when Truth_Not_Expr =>
return B (not T (Node.Op1)); return B (not T (Node.Op1));
when Bit_And_Expr =>
L := V (Node.Op1);
R := V (Node.Op2);
return UI_From_Int (Int (W (L) and W (R)));
when Lt_Expr => when Lt_Expr =>
return B (V (Node.Op1) < V (Node.Op2)); return B (V (Node.Op1) < V (Node.Op2));
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
-- -- -- --
-- S p e c -- -- S p e c --
-- -- -- --
-- Copyright (C) 1999-2005 Free Software Foundation, Inc. -- -- Copyright (C) 1999-2005, Free Software Foundation, Inc. --
-- -- -- --
-- GNAT is free software; you can redistribute it and/or modify it under -- -- GNAT is free software; you can redistribute it and/or modify it under --
-- terms of the GNU General Public License as published by the Free Soft- -- -- terms of the GNU General Public License as published by the Free Soft- --
...@@ -35,7 +35,7 @@ ...@@ -35,7 +35,7 @@
-- tree to fill in representation information, and also the routine used -- tree to fill in representation information, and also the routine used
-- by -gnatR to print this information. This unit is used both in the -- by -gnatR to print this information. This unit is used both in the
-- compiler and in ASIS (it is used in ASIS as part of the implementation -- compiler and in ASIS (it is used in ASIS as part of the implementation
-- of the data decomposition annex. -- of the data decomposition annex).
with Types; use Types; with Types; use Types;
with Uintp; use Uintp; with Uintp; use Uintp;
...@@ -128,7 +128,7 @@ package Repinfo is ...@@ -128,7 +128,7 @@ package Repinfo is
-- Subtype used for values that can either be a Node_Ref (negative) -- Subtype used for values that can either be a Node_Ref (negative)
-- or a value (non-negative) -- or a value (non-negative)
type TCode is range 0 .. 27; type TCode is range 0 .. 28;
-- Type used on Ada side to represent DEFTREECODE values defined in -- Type used on Ada side to represent DEFTREECODE values defined in
-- tree.def. Only a subset of these tree codes can actually appear. -- tree.def. Only a subset of these tree codes can actually appear.
-- The names are the names from tree.def in Ada casing. -- The names are the names from tree.def in Ada casing.
...@@ -162,6 +162,7 @@ package Repinfo is ...@@ -162,6 +162,7 @@ package Repinfo is
Ge_Expr : constant TCode := 25; -- comparision >= 2 Ge_Expr : constant TCode := 25; -- comparision >= 2
Eq_Expr : constant TCode := 26; -- comparision = 2 Eq_Expr : constant TCode := 26; -- comparision = 2
Ne_Expr : constant TCode := 27; -- comparision /= 2 Ne_Expr : constant TCode := 27; -- comparision /= 2
Bit_And_Expr : constant TCode := 28; -- Binary and 2
-- The following entry is used to represent a discriminant value in -- The following entry is used to represent a discriminant value in
-- the tree. It has a special tree code that does not correspond -- the tree. It has a special tree code that does not correspond
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* * * *
* C Header File * * C Header File *
* * * *
* Copyright (C) 1999-2002 Free Software Foundation, Inc. * * Copyright (C) 1999-2005 Free Software Foundation, Inc. *
* * * *
* GNAT is free software; you can redistribute it and/or modify it under * * GNAT is free software; you can redistribute it and/or modify it under *
* terms of the GNU General Public License as published by the Free Soft- * * terms of the GNU General Public License as published by the Free Soft- *
...@@ -67,6 +67,7 @@ typedef char TCode; ...@@ -67,6 +67,7 @@ typedef char TCode;
#define Ge_Expr 25 #define Ge_Expr 25
#define Eq_Expr 26 #define Eq_Expr 26
#define Ne_Expr 27 #define Ne_Expr 27
#define Bit_And_Expr 28
/* Creates a node using the tree code defined by Expr and from 1-3 /* Creates a node using the tree code defined by Expr and from 1-3
operands as required (unused operands set as shown to No_Uint) Note operands as required (unused operands set as shown to No_Uint) Note
......
...@@ -408,13 +408,7 @@ Identifier_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p) ...@@ -408,13 +408,7 @@ Identifier_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p)
else if (TREE_CODE (gnu_result) == VAR_DECL else if (TREE_CODE (gnu_result) == VAR_DECL
&& (renamed_obj = DECL_RENAMED_OBJECT (gnu_result)) != 0 && (renamed_obj = DECL_RENAMED_OBJECT (gnu_result)) != 0
&& (! DECL_RENAMING_GLOBAL_P (gnu_result) && (! DECL_RENAMING_GLOBAL_P (gnu_result)
|| global_bindings_p ()) || global_bindings_p ()))
/* Make sure it's an lvalue like INDIRECT_REF. */
&& (DECL_P (renamed_obj)
|| REFERENCE_CLASS_P (renamed_obj)
|| (TREE_CODE (renamed_obj) == VIEW_CONVERT_EXPR
&& (DECL_P (TREE_OPERAND (renamed_obj, 0))
|| REFERENCE_CLASS_P (TREE_OPERAND (renamed_obj,0))))))
gnu_result = renamed_obj; gnu_result = renamed_obj;
else else
gnu_result = build_unary_op (INDIRECT_REF, NULL_TREE, gnu_result = build_unary_op (INDIRECT_REF, NULL_TREE,
...@@ -719,6 +713,21 @@ Attribute_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, int attribute) ...@@ -719,6 +713,21 @@ Attribute_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, int attribute)
= size_binop (MAX_EXPR, gnu_result, = size_binop (MAX_EXPR, gnu_result,
DECL_SIZE (TREE_OPERAND (gnu_expr, 1))); DECL_SIZE (TREE_OPERAND (gnu_expr, 1)));
} }
else if (Nkind (Prefix (gnat_node)) == N_Explicit_Dereference)
{
Node_Id gnat_deref = Prefix (gnat_node);
Node_Id gnat_actual_subtype = Actual_Designated_Subtype (gnat_deref);
tree gnu_ptr_type = TREE_TYPE (gnat_to_gnu (Prefix (gnat_deref)));
if (TYPE_FAT_OR_THIN_POINTER_P (gnu_ptr_type)
&& Present (gnat_actual_subtype))
{
tree gnu_actual_obj_type = gnat_to_gnu_type (gnat_actual_subtype);
gnu_type = build_unc_object_type_from_ptr (gnu_ptr_type,
gnu_actual_obj_type, get_identifier ("SIZE"));
}
gnu_result = TYPE_SIZE (gnu_type);
}
else else
gnu_result = TYPE_SIZE (gnu_type); gnu_result = TYPE_SIZE (gnu_type);
} }
...@@ -1564,8 +1573,15 @@ call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target) ...@@ -1564,8 +1573,15 @@ call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target)
0, Etype (Name (gnat_node)), "PAD", false, 0, Etype (Name (gnat_node)), "PAD", false,
false, false); false, false);
gnu_target = create_tmp_var_raw (gnu_obj_type, "LR"); /* ??? We may be about to create a static temporary if we happen to
gnat_pushdecl (gnu_target, gnat_node); be at the global binding level. That's a regression from what
the 3.x back-end would generate in the same situation, but we
don't have a mechanism in Gigi for creating automatic variables
in the elaboration routines. */
gnu_target
= create_var_decl (create_tmp_var_name ("LR"), NULL, gnu_obj_type,
NULL, false, false, false, false, NULL,
gnat_node);
} }
gnu_actual_list gnu_actual_list
...@@ -1602,6 +1618,7 @@ call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target) ...@@ -1602,6 +1618,7 @@ call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target)
tree gnu_formal tree gnu_formal
= (present_gnu_tree (gnat_formal) = (present_gnu_tree (gnat_formal)
? get_gnu_tree (gnat_formal) : NULL_TREE); ? get_gnu_tree (gnat_formal) : NULL_TREE);
tree gnu_formal_type = gnat_to_gnu_type (Etype (gnat_formal));
/* We treat a conversion between aggregate types as if it is an /* We treat a conversion between aggregate types as if it is an
unchecked conversion. */ unchecked conversion. */
bool unchecked_convert_p bool unchecked_convert_p
...@@ -1613,7 +1630,6 @@ call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target) ...@@ -1613,7 +1630,6 @@ call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target)
tree gnu_name = gnat_to_gnu (gnat_name); tree gnu_name = gnat_to_gnu (gnat_name);
tree gnu_name_type = gnat_to_gnu_type (Etype (gnat_name)); tree gnu_name_type = gnat_to_gnu_type (Etype (gnat_name));
tree gnu_actual; tree gnu_actual;
tree gnu_formal_type;
/* If it's possible we may need to use this expression twice, make sure /* If it's possible we may need to use this expression twice, make sure
than any side-effects are handled via SAVE_EXPRs. Likewise if we need than any side-effects are handled via SAVE_EXPRs. Likewise if we need
...@@ -1626,6 +1642,7 @@ call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target) ...@@ -1626,6 +1642,7 @@ call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target)
if (Ekind (gnat_formal) != E_In_Parameter) if (Ekind (gnat_formal) != E_In_Parameter)
{ {
gnu_name = gnat_stabilize_reference (gnu_name, true); gnu_name = gnat_stabilize_reference (gnu_name, true);
if (!addressable_p (gnu_name) if (!addressable_p (gnu_name)
&& gnu_formal && gnu_formal
&& (DECL_BY_REF_P (gnu_formal) && (DECL_BY_REF_P (gnu_formal)
...@@ -1741,6 +1758,9 @@ call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target) ...@@ -1741,6 +1758,9 @@ call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target)
gnu_actual = convert (gnat_to_gnu_type (Etype (gnat_actual)), gnu_actual = convert (gnat_to_gnu_type (Etype (gnat_actual)),
gnu_actual); gnu_actual);
if (TREE_CODE (gnu_actual) != SAVE_EXPR)
gnu_actual = convert (gnu_formal_type, gnu_actual);
/* If we have not saved a GCC object for the formal, it means it is an /* If we have not saved a GCC object for the formal, it means it is an
OUT parameter not passed by reference and that does not need to be OUT parameter not passed by reference and that does not need to be
copied in. Otherwise, look at the PARM_DECL to see if it is passed by copied in. Otherwise, look at the PARM_DECL to see if it is passed by
...@@ -1989,7 +2009,7 @@ call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target) ...@@ -1989,7 +2009,7 @@ call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target)
&& TREE_CONSTANT (TYPE_SIZE (TREE_TYPE (gnu_result))))) && TREE_CONSTANT (TYPE_SIZE (TREE_TYPE (gnu_result)))))
gnu_result = convert (TREE_TYPE (gnu_actual), gnu_result); gnu_result = convert (TREE_TYPE (gnu_actual), gnu_result);
} }
gnu_result = build_binary_op (MODIFY_EXPR, NULL_TREE, gnu_result = build_binary_op (MODIFY_EXPR, NULL_TREE,
gnu_actual, gnu_result); gnu_actual, gnu_result);
annotate_with_node (gnu_result, gnat_actual); annotate_with_node (gnu_result, gnat_actual);
...@@ -2497,25 +2517,40 @@ gnat_to_gnu (Node_Id gnat_node) ...@@ -2497,25 +2517,40 @@ gnat_to_gnu (Node_Id gnat_node)
return build1 (NULL_EXPR, get_unpadded_type (Etype (gnat_node)), return build1 (NULL_EXPR, get_unpadded_type (Etype (gnat_node)),
build_call_raise (CE_Range_Check_Failed)); build_call_raise (CE_Range_Check_Failed));
/* If this is a Statement and we are at top level, it must be part of /* If this is a Statement and we are at top level, it must be part of the
the elaboration procedure, so mark us as being in that procedure elaboration procedure, so mark us as being in that procedure and push our
and push our context. */ context.
if (!current_function_decl
&& ((IN (Nkind (gnat_node), N_Statement_Other_Than_Procedure_Call) If we are in the elaboration procedure, check if we are violating a a
&& Nkind (gnat_node) != N_Null_Statement) No_Elaboration_Code restriction by having a statement there. */
|| Nkind (gnat_node) == N_Procedure_Call_Statement if ((IN (Nkind (gnat_node), N_Statement_Other_Than_Procedure_Call)
|| Nkind (gnat_node) == N_Label && Nkind (gnat_node) != N_Null_Statement)
|| Nkind (gnat_node) == N_Implicit_Label_Declaration || Nkind (gnat_node) == N_Procedure_Call_Statement
|| Nkind (gnat_node) == N_Handled_Sequence_Of_Statements || Nkind (gnat_node) == N_Label
|| ((Nkind (gnat_node) == N_Raise_Constraint_Error || Nkind (gnat_node) == N_Implicit_Label_Declaration
|| Nkind (gnat_node) == N_Raise_Storage_Error || Nkind (gnat_node) == N_Handled_Sequence_Of_Statements
|| Nkind (gnat_node) == N_Raise_Program_Error) || ((Nkind (gnat_node) == N_Raise_Constraint_Error
&& (Ekind (Etype (gnat_node)) == E_Void)))) || Nkind (gnat_node) == N_Raise_Storage_Error
|| Nkind (gnat_node) == N_Raise_Program_Error)
&& (Ekind (Etype (gnat_node)) == E_Void)))
{ {
current_function_decl = TREE_VALUE (gnu_elab_proc_stack); if (!current_function_decl)
start_stmt_group (); {
gnat_pushlevel (); current_function_decl = TREE_VALUE (gnu_elab_proc_stack);
went_into_elab_proc = true; start_stmt_group ();
gnat_pushlevel ();
went_into_elab_proc = true;
}
/* Don't check for a possible No_Elaboration_Code restriction violation
on N_Handled_Sequence_Of_Statements, as we want to signal an error on
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 == TREE_VALUE (gnu_elab_proc_stack)
&& Nkind (gnat_node) != N_Handled_Sequence_Of_Statements)
Check_Elaboration_Code_Allowed (gnat_node);
} }
switch (Nkind (gnat_node)) switch (Nkind (gnat_node))
...@@ -2982,7 +3017,7 @@ gnat_to_gnu (Node_Id gnat_node) ...@@ -2982,7 +3017,7 @@ gnat_to_gnu (Node_Id gnat_node)
? Designated_Type (Etype ? Designated_Type (Etype
(Prefix (gnat_node))) (Prefix (gnat_node)))
: Etype (Prefix (gnat_node)))) : Etype (Prefix (gnat_node))))
gnu_prefix = gnat_stabilize_reference (gnu_prefix, 0); gnu_prefix = gnat_stabilize_reference (gnu_prefix, false);
gnu_result gnu_result
= build_component_ref (gnu_prefix, NULL_TREE, gnu_field, = build_component_ref (gnu_prefix, NULL_TREE, gnu_field,
...@@ -3427,7 +3462,7 @@ gnat_to_gnu (Node_Id gnat_node) ...@@ -3427,7 +3462,7 @@ gnat_to_gnu (Node_Id gnat_node)
/* If the type has a size that overflows, convert this into raise of /* If the type has a size that overflows, convert this into raise of
Storage_Error: execution shouldn't have gotten here anyway. */ Storage_Error: execution shouldn't have gotten here anyway. */
if (TREE_CODE (TYPE_SIZE_UNIT (TREE_TYPE (gnu_lhs))) == INTEGER_CST if (TREE_CODE (TYPE_SIZE_UNIT (TREE_TYPE (gnu_lhs))) == INTEGER_CST
&& TREE_OVERFLOW (TYPE_SIZE_UNIT (TREE_TYPE (gnu_lhs)))) && TREE_OVERFLOW (TYPE_SIZE_UNIT (TREE_TYPE (gnu_lhs))))
gnu_result = build_call_raise (SE_Object_Too_Large); gnu_result = build_call_raise (SE_Object_Too_Large);
else if (Nkind (Expression (gnat_node)) == N_Function_Call else if (Nkind (Expression (gnat_node)) == N_Function_Call
&& !Do_Range_Check (Expression (gnat_node))) && !Do_Range_Check (Expression (gnat_node)))
...@@ -3927,7 +3962,9 @@ gnat_to_gnu (Node_Id gnat_node) ...@@ -3927,7 +3962,9 @@ gnat_to_gnu (Node_Id gnat_node)
if (!type_annotate_only) if (!type_annotate_only)
{ {
tree gnu_ptr = gnat_to_gnu (Expression (gnat_node)); tree gnu_ptr = gnat_to_gnu (Expression (gnat_node));
tree gnu_ptr_type = TREE_TYPE (gnu_ptr);
tree gnu_obj_type; tree gnu_obj_type;
tree gnu_actual_obj_type = 0;
tree gnu_obj_size; tree gnu_obj_size;
int align; int align;
...@@ -3952,7 +3989,21 @@ gnat_to_gnu (Node_Id gnat_node) ...@@ -3952,7 +3989,21 @@ gnat_to_gnu (Node_Id gnat_node)
gnu_ptr); gnu_ptr);
gnu_obj_type = TREE_TYPE (TREE_TYPE (gnu_ptr)); gnu_obj_type = TREE_TYPE (TREE_TYPE (gnu_ptr));
gnu_obj_size = TYPE_SIZE_UNIT (gnu_obj_type);
if (Present (Actual_Designated_Subtype (gnat_node)))
{
gnu_actual_obj_type = gnat_to_gnu_type (Actual_Designated_Subtype (gnat_node));
if (TYPE_FAT_OR_THIN_POINTER_P (gnu_ptr_type))
gnu_actual_obj_type
= build_unc_object_type_from_ptr (gnu_ptr_type,
gnu_actual_obj_type,
get_identifier ("DEALLOC"));
}
else
gnu_actual_obj_type = gnu_obj_type;
gnu_obj_size = TYPE_SIZE_UNIT (gnu_actual_obj_type);
align = TYPE_ALIGN (gnu_obj_type); align = TYPE_ALIGN (gnu_obj_type);
if (TREE_CODE (gnu_obj_type) == RECORD_TYPE if (TREE_CODE (gnu_obj_type) == RECORD_TYPE
...@@ -4106,7 +4157,7 @@ gnat_to_gnu (Node_Id gnat_node) ...@@ -4106,7 +4157,7 @@ gnat_to_gnu (Node_Id gnat_node)
if (TREE_SIDE_EFFECTS (gnu_result) if (TREE_SIDE_EFFECTS (gnu_result)
&& (TREE_CODE (gnu_result_type) == UNCONSTRAINED_ARRAY_TYPE && (TREE_CODE (gnu_result_type) == UNCONSTRAINED_ARRAY_TYPE
|| CONTAINS_PLACEHOLDER_P (TYPE_SIZE (gnu_result_type)))) || CONTAINS_PLACEHOLDER_P (TYPE_SIZE (gnu_result_type))))
gnu_result = gnat_stabilize_reference (gnu_result, 0); gnu_result = gnat_stabilize_reference (gnu_result, false);
/* Now convert the result to the proper type. If the type is void or if /* Now convert the result to the proper type. If the type is void or if
we have no result, return error_mark_node to show we have no result. we have no result, return error_mark_node to show we have no result.
...@@ -5709,17 +5760,26 @@ protect_multiple_eval (tree exp) ...@@ -5709,17 +5760,26 @@ protect_multiple_eval (tree exp)
exp))); exp)));
} }
/* This is equivalent to stabilize_reference in GCC's tree.c, but we know /* This is equivalent to stabilize_reference in GCC's tree.c, but we know how
how to handle our new nodes and we take an extra argument that says to handle our new nodes and we take extra arguments:
whether to force evaluation of everything. */
FORCE says whether to force evaluation of everything,
SUCCESS we set to true unless we walk through something we don't know how
to stabilize, or through something which is not an lvalue and LVALUES_ONLY
is true, in which cases we set to false. */
tree tree
gnat_stabilize_reference (tree ref, bool force) maybe_stabilize_reference (tree ref, bool force, bool lvalues_only,
bool *success)
{ {
tree type = TREE_TYPE (ref); tree type = TREE_TYPE (ref);
enum tree_code code = TREE_CODE (ref); enum tree_code code = TREE_CODE (ref);
tree result; tree result;
/* Assume we'll success unless proven otherwise. */
*success = true;
switch (code) switch (code)
{ {
case VAR_DECL: case VAR_DECL:
...@@ -5728,6 +5788,15 @@ gnat_stabilize_reference (tree ref, bool force) ...@@ -5728,6 +5788,15 @@ gnat_stabilize_reference (tree ref, bool force)
/* No action is needed in this case. */ /* No action is needed in this case. */
return ref; return ref;
case ADDR_EXPR:
/* A standalone ADDR_EXPR is never an lvalue, and this one can't
be nested inside an outer INDIRECT_REF, since INDIREC_REF goes
straight to stabilize_1. */
if (lvalues_only)
goto failure;
/* ... Fallthru ... */
case NOP_EXPR: case NOP_EXPR:
case CONVERT_EXPR: case CONVERT_EXPR:
case FLOAT_EXPR: case FLOAT_EXPR:
...@@ -5736,10 +5805,10 @@ gnat_stabilize_reference (tree ref, bool force) ...@@ -5736,10 +5805,10 @@ gnat_stabilize_reference (tree ref, bool force)
case FIX_ROUND_EXPR: case FIX_ROUND_EXPR:
case FIX_CEIL_EXPR: case FIX_CEIL_EXPR:
case VIEW_CONVERT_EXPR: case VIEW_CONVERT_EXPR:
case ADDR_EXPR:
result result
= build1 (code, type, = build1 (code, type,
gnat_stabilize_reference (TREE_OPERAND (ref, 0), force)); maybe_stabilize_reference (TREE_OPERAND (ref, 0), force,
lvalues_only, success));
break; break;
case INDIRECT_REF: case INDIRECT_REF:
...@@ -5750,15 +5819,16 @@ gnat_stabilize_reference (tree ref, bool force) ...@@ -5750,15 +5819,16 @@ gnat_stabilize_reference (tree ref, bool force)
break; break;
case COMPONENT_REF: case COMPONENT_REF:
result = build3 (COMPONENT_REF, type, result = build3 (COMPONENT_REF, type,
gnat_stabilize_reference (TREE_OPERAND (ref, 0), maybe_stabilize_reference (TREE_OPERAND (ref, 0), force,
force), lvalues_only, success),
TREE_OPERAND (ref, 1), NULL_TREE); TREE_OPERAND (ref, 1), NULL_TREE);
break; break;
case BIT_FIELD_REF: case BIT_FIELD_REF:
result = build3 (BIT_FIELD_REF, type, result = build3 (BIT_FIELD_REF, type,
gnat_stabilize_reference (TREE_OPERAND (ref, 0), force), maybe_stabilize_reference (TREE_OPERAND (ref, 0), force,
lvalues_only, success),
gnat_stabilize_reference_1 (TREE_OPERAND (ref, 1), gnat_stabilize_reference_1 (TREE_OPERAND (ref, 1),
force), force),
gnat_stabilize_reference_1 (TREE_OPERAND (ref, 2), gnat_stabilize_reference_1 (TREE_OPERAND (ref, 2),
...@@ -5768,7 +5838,8 @@ gnat_stabilize_reference (tree ref, bool force) ...@@ -5768,7 +5838,8 @@ gnat_stabilize_reference (tree ref, bool force)
case ARRAY_REF: case ARRAY_REF:
case ARRAY_RANGE_REF: case ARRAY_RANGE_REF:
result = build4 (code, type, result = build4 (code, type,
gnat_stabilize_reference (TREE_OPERAND (ref, 0), force), maybe_stabilize_reference (TREE_OPERAND (ref, 0), force,
lvalues_only, success),
gnat_stabilize_reference_1 (TREE_OPERAND (ref, 1), gnat_stabilize_reference_1 (TREE_OPERAND (ref, 1),
force), force),
NULL_TREE, NULL_TREE); NULL_TREE, NULL_TREE);
...@@ -5778,17 +5849,21 @@ gnat_stabilize_reference (tree ref, bool force) ...@@ -5778,17 +5849,21 @@ gnat_stabilize_reference (tree ref, bool force)
result = build2 (COMPOUND_EXPR, type, result = build2 (COMPOUND_EXPR, type,
gnat_stabilize_reference_1 (TREE_OPERAND (ref, 0), gnat_stabilize_reference_1 (TREE_OPERAND (ref, 0),
force), force),
gnat_stabilize_reference (TREE_OPERAND (ref, 1), maybe_stabilize_reference (TREE_OPERAND (ref, 1), force,
force)); lvalues_only, success));
break; break;
case ERROR_MARK:
ref = error_mark_node;
/* ... Fallthru to failure ... */
/* If arg isn't a kind of lvalue we recognize, make no change. /* If arg isn't a kind of lvalue we recognize, make no change.
Caller should recognize the error for an invalid lvalue. */ Caller should recognize the error for an invalid lvalue. */
default: default:
failure:
*success = false;
return ref; return ref;
case ERROR_MARK:
return error_mark_node;
} }
TREE_READONLY (result) = TREE_READONLY (ref); TREE_READONLY (result) = TREE_READONLY (ref);
...@@ -5808,6 +5883,17 @@ gnat_stabilize_reference (tree ref, bool force) ...@@ -5808,6 +5883,17 @@ gnat_stabilize_reference (tree ref, bool force)
return result; return result;
} }
/* Wrapper around maybe_stabilize_reference, for common uses without
lvalue restrictions and without need to examine the success
indication. */
tree
gnat_stabilize_reference (tree ref, bool force)
{
bool stabilized;
return maybe_stabilize_reference (ref, force, false, &stabilized);
}
/* Similar to stabilize_reference_1 in tree.c, but supports an extra /* Similar to stabilize_reference_1 in tree.c, but supports an extra
arg to force a SAVE_EXPR for everything. */ arg to force a SAVE_EXPR for everything. */
......
...@@ -324,7 +324,13 @@ gnat_pushdecl (tree decl, Node_Id gnat_node) ...@@ -324,7 +324,13 @@ gnat_pushdecl (tree decl, Node_Id gnat_node)
if (global_bindings_p () && TREE_CODE (decl) != PARM_DECL) if (global_bindings_p () && TREE_CODE (decl) != PARM_DECL)
DECL_CONTEXT (decl) = 0; DECL_CONTEXT (decl) = 0;
else else
DECL_CONTEXT (decl) = current_function_decl; {
DECL_CONTEXT (decl) = current_function_decl;
/* Functions imported in another function are not really nested. */
if (TREE_CODE (decl) == FUNCTION_DECL && TREE_PUBLIC (decl))
DECL_NO_STATIC_CHAIN (decl) = 1;
}
TREE_NO_WARNING (decl) = (gnat_node == Empty || Warnings_Off (gnat_node)); TREE_NO_WARNING (decl) = (gnat_node == Empty || Warnings_Off (gnat_node));
...@@ -1277,6 +1283,12 @@ create_var_decl (tree var_name, tree asm_name, tree type, tree var_init, ...@@ -1277,6 +1283,12 @@ create_var_decl (tree var_name, tree asm_name, tree type, tree var_init,
|| (type_annotate_only && var_init && !TREE_CONSTANT (var_init))) || (type_annotate_only && var_init && !TREE_CONSTANT (var_init)))
var_init = NULL_TREE; var_init = NULL_TREE;
/* At the global level, an initializer requiring code to be generated
produces elaboration statements. Check that such statements are allowed,
that is, not violating a No_Elaboration_Code restriction. */
if (global_bindings_p () && var_init != 0 && ! init_const)
Check_Elaboration_Code_Allowed (gnat_node);
/* Ada doesn't feature Fortran-like COMMON variables so we shouldn't /* Ada doesn't feature Fortran-like COMMON variables so we shouldn't
try to fiddle with DECL_COMMON. However, on platforms that don't try to fiddle with DECL_COMMON. However, on platforms that don't
support global BSS sections, uninitialized global variables would support global BSS sections, uninitialized global variables would
...@@ -1313,6 +1325,10 @@ create_var_decl (tree var_name, tree asm_name, tree type, tree var_init, ...@@ -1313,6 +1325,10 @@ create_var_decl (tree var_name, tree asm_name, tree type, tree var_init,
if (TREE_CODE (var_decl) != CONST_DECL) if (TREE_CODE (var_decl) != CONST_DECL)
rest_of_decl_compilation (var_decl, global_bindings_p (), 0); rest_of_decl_compilation (var_decl, global_bindings_p (), 0);
else
/* expand CONST_DECLs to set their MODE, ALIGN, SIZE and SIZE_UNIT,
which we need for later back-annotations. */
expand_decl (var_decl);
return var_decl; return var_decl;
} }
...@@ -1607,7 +1623,7 @@ potential_alignment_gap (tree prev_field, tree curr_field, tree offset) ...@@ -1607,7 +1623,7 @@ potential_alignment_gap (tree prev_field, tree curr_field, tree offset)
% DECL_ALIGN (curr_field) != 0); % DECL_ALIGN (curr_field) != 0);
/* If both the position and size of the previous field are multiples /* If both the position and size of the previous field are multiples
of the current field alignment, there can not be any gap. */ of the current field alignment, there cannot be any gap. */
if (value_factor_p (bit_position (prev_field), DECL_ALIGN (curr_field)) if (value_factor_p (bit_position (prev_field), DECL_ALIGN (curr_field))
&& value_factor_p (DECL_SIZE (prev_field), DECL_ALIGN (curr_field))) && value_factor_p (DECL_SIZE (prev_field), DECL_ALIGN (curr_field)))
return false; return false;
...@@ -2444,6 +2460,22 @@ build_unc_object_type (tree template_type, tree object_type, tree name) ...@@ -2444,6 +2460,22 @@ build_unc_object_type (tree template_type, tree object_type, tree name)
return type; return type;
} }
/* Same, taking a thin or fat pointer type instead of a template type. */
tree
build_unc_object_type_from_ptr (tree thin_fat_ptr_type, tree object_type, tree name)
{
tree template_type;
gcc_assert (TYPE_FAT_OR_THIN_POINTER_P (thin_fat_ptr_type));
template_type
= (TYPE_FAT_POINTER_P (thin_fat_ptr_type)
? TREE_TYPE (TREE_TYPE (TREE_CHAIN (TYPE_FIELDS (thin_fat_ptr_type))))
: TREE_TYPE (TYPE_FIELDS (TREE_TYPE (thin_fat_ptr_type))));
return build_unc_object_type (template_type, object_type, name);
}
/* Update anything previously pointing to OLD_TYPE to point to NEW_TYPE. In /* Update anything previously pointing to OLD_TYPE to point to NEW_TYPE. In
the normal case this is just two adjustments, but we have more to do the normal case this is just two adjustments, but we have more to do
...@@ -2755,11 +2787,15 @@ convert (tree type, tree expr) ...@@ -2755,11 +2787,15 @@ convert (tree type, tree expr)
expr)), expr)),
TYPE_MIN_VALUE (etype)))); TYPE_MIN_VALUE (etype))));
/* If the input is a justified modular type, we need to extract /* If the input is a justified modular type, we need to extract the actual
the actual object before converting it to any other type with the object before converting it to any other type with the exceptions of an
exception of an unconstrained array. */ unconstrained array or of a mere type variant. It is useful to avoid the
extraction and conversion in the type variant case because it could end
up replacing a VAR_DECL expr by a constructor and we might be about the
take the address of the result. */
if (ecode == RECORD_TYPE && TYPE_JUSTIFIED_MODULAR_P (etype) if (ecode == RECORD_TYPE && TYPE_JUSTIFIED_MODULAR_P (etype)
&& code != UNCONSTRAINED_ARRAY_TYPE) && code != UNCONSTRAINED_ARRAY_TYPE
&& TYPE_MAIN_VARIANT (type) != TYPE_MAIN_VARIANT (etype))
return convert (type, build_component_ref (expr, NULL_TREE, return convert (type, build_component_ref (expr, NULL_TREE,
TYPE_FIELDS (etype), false)); TYPE_FIELDS (etype), false));
...@@ -2804,9 +2840,7 @@ convert (tree type, tree expr) ...@@ -2804,9 +2840,7 @@ convert (tree type, tree expr)
just make a new one in the proper type. */ just make a new one in the proper type. */
if (code == ecode && AGGREGATE_TYPE_P (etype) if (code == ecode && AGGREGATE_TYPE_P (etype)
&& !(TREE_CODE (TYPE_SIZE (etype)) == INTEGER_CST && !(TREE_CODE (TYPE_SIZE (etype)) == INTEGER_CST
&& TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST) && TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST))
&& (TREE_CODE (expr) == STRING_CST
|| get_alias_set (etype) == get_alias_set (type)))
{ {
expr = copy_node (expr); expr = copy_node (expr);
TREE_TYPE (expr) = type; TREE_TYPE (expr) = type;
...@@ -2826,9 +2860,40 @@ convert (tree type, tree expr) ...@@ -2826,9 +2860,40 @@ convert (tree type, tree expr)
break; break;
case VIEW_CONVERT_EXPR: case VIEW_CONVERT_EXPR:
if (AGGREGATE_TYPE_P (type) && AGGREGATE_TYPE_P (etype) {
&& !TYPE_FAT_POINTER_P (type) && !TYPE_FAT_POINTER_P (etype)) /* GCC 4.x is very sensitive to type consistency overall, and view
return convert (type, TREE_OPERAND (expr, 0)); conversions thus are very frequent. Eventhough just "convert"ing
the inner operand to the output type is fine in most cases, it
might expose unexpected input/output type mismatches in special
circumstances so we avoid such recursive calls when we can. */
tree op0 = TREE_OPERAND (expr, 0);
/* If we are converting back to the original type, we can just
lift the input conversion. This is a common occurence with
switches back-and-forth amongst type variants. */
if (type == TREE_TYPE (op0))
return op0;
/* Otherwise, if we're converting between two aggregate types, we
might be allowed to substitute the VIEW_CONVERT target type in
place or to just convert the inner expression. */
if (AGGREGATE_TYPE_P (type) && AGGREGATE_TYPE_P (etype))
{
/* If we are converting between type variants, we can just
substitute the VIEW_CONVERT in place. */
if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (etype))
return build1 (VIEW_CONVERT_EXPR, type, op0);
/* Otherwise, we may just bypass the input view conversion unless
one of the types is a fat pointer, or we're converting to an
unchecked union type. Both are handled by specialized code
below and the latter relies on exact type matching. */
else if (!TYPE_FAT_POINTER_P (type) && !TYPE_FAT_POINTER_P (etype)
&& !(code == UNION_TYPE && TYPE_UNCHECKED_UNION_P (type)))
return convert (type, op0);
}
}
break; break;
case INDIRECT_REF: case INDIRECT_REF:
...@@ -2957,13 +3022,10 @@ convert (tree type, tree expr) ...@@ -2957,13 +3022,10 @@ convert (tree type, tree expr)
{ {
if (TREE_TYPE (tem) == etype) if (TREE_TYPE (tem) == etype)
return build1 (CONVERT_EXPR, type, expr); return build1 (CONVERT_EXPR, type, expr);
else if (TREE_CODE (TREE_TYPE (tem)) == RECORD_TYPE
/* Accept slight type variations. */ && (TYPE_JUSTIFIED_MODULAR_P (TREE_TYPE (tem))
if (TREE_TYPE (tem) == TYPE_MAIN_VARIANT (etype) || TYPE_IS_PADDING_P (TREE_TYPE (tem)))
|| (TREE_CODE (TREE_TYPE (tem)) == RECORD_TYPE && TREE_TYPE (TYPE_FIELDS (TREE_TYPE (tem))) == etype)
&& (TYPE_JUSTIFIED_MODULAR_P (TREE_TYPE (tem))
|| TYPE_IS_PADDING_P (TREE_TYPE (tem)))
&& TREE_TYPE (TYPE_FIELDS (TREE_TYPE (tem))) == etype))
return build1 (CONVERT_EXPR, type, return build1 (CONVERT_EXPR, type,
convert (TREE_TYPE (tem), expr)); convert (TREE_TYPE (tem), expr));
} }
......
...@@ -170,7 +170,7 @@ known_alignment (tree exp) ...@@ -170,7 +170,7 @@ known_alignment (tree exp)
case NON_LVALUE_EXPR: case NON_LVALUE_EXPR:
/* Conversions between pointers and integers don't change the alignment /* Conversions between pointers and integers don't change the alignment
of the underlying object. */ of the underlying object. */
this_alignment = known_alignment (TREE_OPERAND (exp, 0)); this_alignment = known_alignment (TREE_OPERAND (exp, 0));
break; break;
case PLUS_EXPR: case PLUS_EXPR:
...@@ -656,40 +656,6 @@ build_binary_op (enum tree_code op_code, tree result_type, ...@@ -656,40 +656,6 @@ build_binary_op (enum tree_code op_code, tree result_type,
if (!operation_type) if (!operation_type)
operation_type = left_type; operation_type = left_type;
/* If the RHS has a conversion between record and array types and
an inner type is no worse, use it. Note we cannot do this for
modular types or types with TYPE_ALIGN_OK, since the latter
might indicate a conversion between a root type and a class-wide
type, which we must not remove. */
while (TREE_CODE (right_operand) == VIEW_CONVERT_EXPR
&& (((TREE_CODE (right_type) == RECORD_TYPE
|| TREE_CODE (right_type) == UNION_TYPE)
&& !TYPE_JUSTIFIED_MODULAR_P (right_type)
&& !TYPE_ALIGN_OK (right_type)
&& !TYPE_IS_FAT_POINTER_P (right_type))
|| TREE_CODE (right_type) == ARRAY_TYPE)
&& ((((TREE_CODE (TREE_TYPE (TREE_OPERAND (right_operand, 0)))
== RECORD_TYPE)
|| (TREE_CODE (TREE_TYPE (TREE_OPERAND (right_operand, 0)))
== UNION_TYPE))
&& !(TYPE_JUSTIFIED_MODULAR_P
(TREE_TYPE (TREE_OPERAND (right_operand, 0))))
&& !(TYPE_ALIGN_OK
(TREE_TYPE (TREE_OPERAND (right_operand, 0))))
&& !(TYPE_IS_FAT_POINTER_P
(TREE_TYPE (TREE_OPERAND (right_operand, 0)))))
|| (TREE_CODE (TREE_TYPE (TREE_OPERAND (right_operand, 0)))
== ARRAY_TYPE))
&& (0 == (best_type
= find_common_type (right_type,
TREE_TYPE (TREE_OPERAND
(right_operand, 0))))
|| right_type != best_type))
{
right_operand = TREE_OPERAND (right_operand, 0);
right_type = TREE_TYPE (right_operand);
}
/* If we are copying one array or record to another, find the best type /* If we are copying one array or record to another, find the best type
to use. */ to use. */
if (((TREE_CODE (left_type) == ARRAY_TYPE if (((TREE_CODE (left_type) == ARRAY_TYPE
...@@ -1159,12 +1125,18 @@ build_unary_op (enum tree_code op_code, tree result_type, tree operand) ...@@ -1159,12 +1125,18 @@ build_unary_op (enum tree_code op_code, tree result_type, tree operand)
return build_unary_op (ADDR_EXPR, result_type, return build_unary_op (ADDR_EXPR, result_type,
TREE_OPERAND (operand, 0)); TREE_OPERAND (operand, 0));
/* If this NOP_EXPR doesn't change the mode, get the result type /* ... fallthru ... */
from this type and go down. We need to do this in case
this is a conversion of a CONST_DECL. */ case VIEW_CONVERT_EXPR:
if (TYPE_MODE (type) != BLKmode /* If this just a variant conversion or if the conversion doesn't
&& (TYPE_MODE (type) change the mode, get the result type from this type and go down.
== TYPE_MODE (TREE_TYPE (TREE_OPERAND (operand, 0))))) This is needed for conversions of CONST_DECLs, to eventually get
to the address of their CORRESPONDING_VARs. */
if ((TYPE_MAIN_VARIANT (type)
== TYPE_MAIN_VARIANT (TREE_TYPE (TREE_OPERAND (operand, 0))))
|| (TYPE_MODE (type) != BLKmode
&& (TYPE_MODE (type)
== TYPE_MODE (TREE_TYPE (TREE_OPERAND (operand, 0))))))
return build_unary_op (ADDR_EXPR, return build_unary_op (ADDR_EXPR,
(result_type ? result_type (result_type ? result_type
: build_pointer_type (type)), : build_pointer_type (type)),
...@@ -1409,7 +1381,7 @@ build_return_expr (tree result_decl, tree ret_val) ...@@ -1409,7 +1381,7 @@ build_return_expr (tree result_decl, tree ret_val)
build_binary_op with the additional guarantee that the type build_binary_op with the additional guarantee that the type
cannot involve a placeholder, since otherwise the function cannot involve a placeholder, since otherwise the function
would use the "target pointer" return mechanism. */ would use the "target pointer" return mechanism. */
if (operation_type != TREE_TYPE (ret_val)) if (operation_type != TREE_TYPE (ret_val))
ret_val = convert (operation_type, ret_val); ret_val = convert (operation_type, ret_val);
...@@ -1493,17 +1465,41 @@ build_call_raise (int msg) ...@@ -1493,17 +1465,41 @@ build_call_raise (int msg)
build_int_cst (NULL_TREE, input_line)); build_int_cst (NULL_TREE, input_line));
} }
/* qsort comparer for the bit positions of two constructor elements
for record components. */
static int
compare_elmt_bitpos (const PTR rt1, const PTR rt2)
{
tree elmt1 = * (tree *) rt1;
tree elmt2 = * (tree *) rt2;
tree pos_field1 = bit_position (TREE_PURPOSE (elmt1));
tree pos_field2 = bit_position (TREE_PURPOSE (elmt2));
if (tree_int_cst_equal (pos_field1, pos_field2))
return 0;
else if (tree_int_cst_lt (pos_field1, pos_field2))
return -1;
else
return 1;
}
/* Return a CONSTRUCTOR of TYPE whose list is LIST. */ /* Return a CONSTRUCTOR of TYPE whose list is LIST. */
tree tree
gnat_build_constructor (tree type, tree list) gnat_build_constructor (tree type, tree list)
{ {
tree elmt; tree elmt;
int n_elmts;
bool allconstant = (TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST); bool allconstant = (TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST);
bool side_effects = false; bool side_effects = false;
tree result; tree result;
for (elmt = list; elmt; elmt = TREE_CHAIN (elmt)) /* Scan the elements to see if they are all constant or if any has side
effects, to let us set global flags on the resulting constructor. Count
the elements along the way for possible sorting purposes below. */
for (n_elmts = 0, elmt = list; elmt; elmt = TREE_CHAIN (elmt), n_elmts ++)
{ {
if (!TREE_CONSTANT (TREE_VALUE (elmt)) if (!TREE_CONSTANT (TREE_VALUE (elmt))
|| (TREE_CODE (type) == RECORD_TYPE || (TREE_CODE (type) == RECORD_TYPE
...@@ -1525,26 +1521,30 @@ gnat_build_constructor (tree type, tree list) ...@@ -1525,26 +1521,30 @@ gnat_build_constructor (tree type, tree list)
return build1 (NULL_EXPR, type, TREE_OPERAND (result, 0)); return build1 (NULL_EXPR, type, TREE_OPERAND (result, 0));
} }
/* If TYPE is a RECORD_TYPE and the fields are not in the /* For record types with constant components only, sort field list
same order as their bit position, don't treat this as constant by increasing bit position. This is necessary to ensure the
since varasm.c can't handle it. */ constructor can be output as static data, which the gimplifier
if (allconstant && TREE_CODE (type) == RECORD_TYPE) might force in various circumstances. */
if (allconstant && TREE_CODE (type) == RECORD_TYPE && n_elmts > 1)
{ {
tree last_pos = bitsize_zero_node; /* Fill an array with an element tree per index, and ask qsort to order
tree field; them according to what a bitpos comparison function says. */
for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field)) tree *gnu_arr = (tree *) alloca (sizeof (tree) * n_elmts);
{ int i;
tree this_pos = bit_position (field);
if (TREE_CODE (this_pos) != INTEGER_CST for (i = 0, elmt = list; elmt; elmt = TREE_CHAIN (elmt), i++)
|| tree_int_cst_lt (this_pos, last_pos)) gnu_arr[i] = elmt;
{
allconstant = false; qsort (gnu_arr, n_elmts, sizeof (tree), compare_elmt_bitpos);
break;
}
last_pos = this_pos; /* Then reconstruct the list from the sorted array contents. */
list = NULL_TREE;
for (i = n_elmts - 1; i >= 0; i--)
{
TREE_CHAIN (gnu_arr[i]) = list;
list = gnu_arr[i];
} }
} }
...@@ -1821,13 +1821,10 @@ build_allocator (tree type, tree init, tree result_type, Entity_Id gnat_proc, ...@@ -1821,13 +1821,10 @@ build_allocator (tree type, tree init, tree result_type, Entity_Id gnat_proc,
fill in the parts that are known. */ fill in the parts that are known. */
else if (TYPE_FAT_OR_THIN_POINTER_P (result_type)) else if (TYPE_FAT_OR_THIN_POINTER_P (result_type))
{ {
tree template_type
= (TYPE_FAT_POINTER_P (result_type)
? TREE_TYPE (TREE_TYPE (TREE_CHAIN (TYPE_FIELDS (result_type))))
: TREE_TYPE (TYPE_FIELDS (TREE_TYPE (result_type))));
tree storage_type tree storage_type
= build_unc_object_type (template_type, type, = build_unc_object_type_from_ptr (result_type, type,
get_identifier ("ALLOC")); get_identifier ("ALLOC"));
tree template_type = TREE_TYPE (TYPE_FIELDS (storage_type));
tree storage_ptr_type = build_pointer_type (storage_type); tree storage_ptr_type = build_pointer_type (storage_type);
tree storage; tree storage;
tree template_cons = NULL_TREE; tree template_cons = NULL_TREE;
......
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