- /* 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)));
+ }
+
+ /* We only need to use the variable if we are in a global context since GCC
+ can do the right thing in the local case. However, when not optimizing,
+ use it for bounds of loop iteration scheme to avoid code duplication. */
+ use_variable = expr_variable_p
+ && (expr_global_p
+ || (!optimize
+ && Is_Itype (gnat_entity)
+ && Nkind (Associated_Node_For_Itype (gnat_entity))
+ == N_Loop_Parameter_Specification));
+
+ /* Now create it, possibly only for debugging purposes. */
+ if (use_variable || need_debug)
+ {
+ tree gnu_decl
+ = create_var_decl_1
+ (create_concat_name (gnat_entity, IDENTIFIER_POINTER (gnu_name)),
+ NULL_TREE, TREE_TYPE (gnu_expr), gnu_expr, true, expr_public_p,
+ !definition, expr_global_p, !need_debug, NULL, gnat_entity);
+
+ if (use_variable)
+ return gnu_decl;
+ }