elaborate_expression_1 (tree gnu_expr, Entity_Id gnat_entity, tree gnu_name,
bool definition, bool need_debug)
{
- /* Skip any conversions and simple arithmetics to see if the expression
- is a read-only variable.
- ??? This really should remain read-only, but we have to think about
- the typing of the tree here. */
- tree gnu_inner_expr
- = skip_simple_arithmetic (remove_conversions (gnu_expr, true));
- tree gnu_decl = NULL_TREE;
- bool expr_global = Is_Public (gnat_entity) || global_bindings_p ();
- bool expr_variable;
+ const bool expr_global_p = Is_Public (gnat_entity) || global_bindings_p ();
+ bool expr_variable_p;
+ tree gnu_decl;
/* In most cases, we won't see a naked FIELD_DECL because a discriminant
reference will have been replaced with a COMPONENT_REF when the type
build0 (PLACEHOLDER_EXPR, DECL_CONTEXT (gnu_expr)),
gnu_expr, NULL_TREE);
- /* If GNU_EXPR is neither a placeholder nor a constant, nor a variable
- that is read-only, make a variable that is initialized to contain the
- bound when the package containing the definition is elaborated. If
- this entity is defined at top level and a bound or discriminant value
- isn't a constant or a reference to a discriminant, replace the bound
- by the variable; otherwise use a SAVE_EXPR if needed. Note that we
- rely here on the fact that an expression cannot contain both the
- discriminant and some other variable. */
- expr_variable = (!CONSTANT_CLASS_P (gnu_expr)
- && !(TREE_CODE (gnu_inner_expr) == VAR_DECL
- && (TREE_READONLY (gnu_inner_expr)
- || DECL_READONLY_ONCE_ELAB (gnu_inner_expr)))
- && !CONTAINS_PLACEHOLDER_P (gnu_expr));
-
- /* If GNU_EXPR contains a discriminant, we can't elaborate a variable. */
- if (need_debug && CONTAINS_PLACEHOLDER_P (gnu_expr))
- need_debug = false;
+ /* If GNU_EXPR contains a placeholder, just return it. We rely on the fact
+ that an expression cannot contain both a discriminant and a variable. */
+ if (CONTAINS_PLACEHOLDER_P (gnu_expr))
+ return gnu_expr;
+
+ /* If GNU_EXPR is neither a constant nor based on a read-only variable, make
+ a variable that is initialized to contain the expression when the package
+ containing the definition is elaborated. If this entity is defined at top
+ level, replace the expression by the variable; otherwise use a SAVE_EXPR
+ if this is necessary. */
+ if (CONSTANT_CLASS_P (gnu_expr))
+ expr_variable_p = false;
+ else
+ {
+ /* Skip any conversions and simple arithmetics to see if the expression
+ is based on a read-only variable.
+ ??? This really should remain read-only, but we have to think about
+ the typing of the tree here. */
+ tree inner
+ = skip_simple_arithmetic (remove_conversions (gnu_expr, true));
+
+ if (handled_component_p (inner))
+ {
+ HOST_WIDE_INT bitsize, bitpos;
+ tree offset;
+ enum machine_mode mode;
+ int unsignedp, volatilep;
+
+ inner = get_inner_reference (inner, &bitsize, &bitpos, &offset,
+ &mode, &unsignedp, &volatilep, false);
+ /* If the offset is variable, err on the side of caution. */
+ if (offset)
+ inner = NULL_TREE;
+ }
+
+ expr_variable_p
+ = !(inner
+ && TREE_CODE (inner) == VAR_DECL
+ && (TREE_READONLY (inner) || DECL_READONLY_ONCE_ELAB (inner)));
+ }
/* Now create the variable if we need it. */
- if (need_debug || (expr_variable && expr_global))
+ if (need_debug || (expr_variable_p && expr_global_p))
gnu_decl
= create_var_decl (create_concat_name (gnat_entity,
IDENTIFIER_POINTER (gnu_name)),
NULL_TREE, TREE_TYPE (gnu_expr), gnu_expr,
!need_debug, Is_Public (gnat_entity),
- !definition, expr_global, NULL, gnat_entity);
+ !definition, expr_global_p, 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 (expr_global && expr_variable)
+ if (expr_global_p && expr_variable_p)
return gnu_decl;
- return expr_variable ? gnat_save_expr (gnu_expr) : gnu_expr;
+ return expr_variable_p ? gnat_save_expr (gnu_expr) : gnu_expr;
}
/* Similar, but take an alignment factor and make it explicit in the tree. */