Commit 1c9766da by Richard Kenner Committed by Richard Kenner

c-decl.c (finish_decl): Make a decl_stmt for a variable-sized TYPE_DECL.

	* c-decl.c (finish_decl): Make a decl_stmt for a variable-sized
	TYPE_DECL.
	* c-semantics.c (genrtl_decl_stmt): Handle TYPE_DECL.
	* stmt.c (expand_decl): Remove redundant expansion of TYPE_DOMAIN.
	* stor-layout.c (variable_size): Don't check for MINUS_EXPR.
	Use skip_simple_arithmetic to find SAVE_EXPR.
	(force_type_save_exprs, force_type_save_exprs_1): New functions.
	* tree-inline.c (remap_type, case POINTER_TYPE, case REFERENCE_TYPE):
	Properly chain multiple pointers.
	(copy_tree_r): Copy a TYPE_DECL.
	* tree.c (variably_modified_type_p): Add some missing tests and
	make some other minor changes.
	* tree.h (force_type_save_exprs): New declaration.
	* gcc.c-torture/execute/20040411-1.c: New test.

From-SVN: r80629
parent 040e098a
2004-04-12 Richard Kenner <kenner@vlsi1.ultra.nyu.edu>
* c-decl.c (finish_decl): Make a decl_stmt for a variable-sized
TYPE_DECL.
* c-semantics.c (genrtl_decl_stmt): Handle TYPE_DECL.
* stmt.c (expand_decl): Remove redundant expansion of TYPE_DOMAIN.
* stor-layout.c (variable_size): Don't check for MINUS_EXPR.
Use skip_simple_arithmetic to find SAVE_EXPR.
(force_type_save_exprs, force_type_save_exprs_1): New functions.
* tree-inline.c (remap_type, case POINTER_TYPE, case REFERENCE_TYPE):
Properly chain multiple pointers.
(copy_tree_r): Copy a TYPE_DECL.
* tree.c (variably_modified_type_p): Add some missing tests and
make some other minor changes.
* tree.h (force_type_save_exprs): New declaration.
2004-04-12 Roger Sayle <roger@eyesopen.com> 2004-04-12 Roger Sayle <roger@eyesopen.com>
* simplify-rtx.c (simplify_binary_operation) <UDIV, DIV, UMOD, MOD>: * simplify-rtx.c (simplify_binary_operation) <UDIV, DIV, UMOD, MOD>:
......
...@@ -2979,7 +2979,13 @@ finish_decl (tree decl, tree init, tree asmspec_tree) ...@@ -2979,7 +2979,13 @@ finish_decl (tree decl, tree init, tree asmspec_tree)
mark_referenced (DECL_ASSEMBLER_NAME (decl)); mark_referenced (DECL_ASSEMBLER_NAME (decl));
if (TREE_CODE (decl) == TYPE_DECL) if (TREE_CODE (decl) == TYPE_DECL)
rest_of_decl_compilation (decl, NULL, DECL_FILE_SCOPE_P (decl), 0); {
if (!DECL_FILE_SCOPE_P (decl)
&& variably_modified_type_p (TREE_TYPE (decl)))
add_decl_stmt (decl);
rest_of_decl_compilation (decl, NULL, DECL_FILE_SCOPE_P (decl), 0);
}
/* At the end of a declaration, throw away any variable type sizes /* At the end of a declaration, throw away any variable type sizes
of types defined inside that declaration. There is no use of types defined inside that declaration. There is no use
......
...@@ -389,6 +389,8 @@ genrtl_decl_stmt (tree t) ...@@ -389,6 +389,8 @@ genrtl_decl_stmt (tree t)
else if (TREE_CODE (decl) == LABEL_DECL else if (TREE_CODE (decl) == LABEL_DECL
&& C_DECLARED_LABEL_FLAG (decl)) && C_DECLARED_LABEL_FLAG (decl))
declare_nonlocal_label (decl); declare_nonlocal_label (decl);
else if (TREE_CODE (decl) == TYPE_DECL)
force_type_save_exprs (TREE_TYPE (decl));
else if (lang_expand_decl_stmt) else if (lang_expand_decl_stmt)
(*lang_expand_decl_stmt) (t); (*lang_expand_decl_stmt) (t);
} }
......
...@@ -4013,13 +4013,8 @@ expand_decl (tree decl) ...@@ -4013,13 +4013,8 @@ expand_decl (tree decl)
do_pending_stack_adjust (); do_pending_stack_adjust ();
save_stack_pointer (); save_stack_pointer ();
/* In function-at-a-time mode, variable_size doesn't expand this, /* Compute the variable's size, in bytes. This will expand any
so do it now. */ needed SAVE_EXPRs for the first time. */
if (TREE_CODE (type) == ARRAY_TYPE && TYPE_DOMAIN (type))
expand_expr (TYPE_MAX_VALUE (TYPE_DOMAIN (type)),
const0_rtx, VOIDmode, 0);
/* Compute the variable's size, in bytes. */
size = expand_expr (DECL_SIZE_UNIT (decl), NULL_RTX, VOIDmode, 0); size = expand_expr (DECL_SIZE_UNIT (decl), NULL_RTX, VOIDmode, 0);
free_temp_slots (); free_temp_slots ();
......
...@@ -66,6 +66,7 @@ static void place_union_field (record_layout_info, tree); ...@@ -66,6 +66,7 @@ static void place_union_field (record_layout_info, tree);
static int excess_unit_span (HOST_WIDE_INT, HOST_WIDE_INT, HOST_WIDE_INT, static int excess_unit_span (HOST_WIDE_INT, HOST_WIDE_INT, HOST_WIDE_INT,
HOST_WIDE_INT, tree); HOST_WIDE_INT, tree);
#endif #endif
static void force_type_save_exprs_1 (tree);
static unsigned int update_alignment_for_field (record_layout_info, tree, static unsigned int update_alignment_for_field (record_layout_info, tree,
unsigned int); unsigned int);
extern void debug_rli (record_layout_info); extern void debug_rli (record_layout_info);
...@@ -146,12 +147,7 @@ variable_size (tree size) ...@@ -146,12 +147,7 @@ variable_size (tree size)
|| CONTAINS_PLACEHOLDER_P (size)) || CONTAINS_PLACEHOLDER_P (size))
return size; return size;
if (TREE_CODE (size) == MINUS_EXPR && integer_onep (TREE_OPERAND (size, 1))) size = save_expr (size);
/* If this is the upper bound of a C array, leave the minus 1 outside
the SAVE_EXPR so it can be folded away. */
TREE_OPERAND (size, 0) = save = save_expr (TREE_OPERAND (size, 0));
else
size = save = save_expr (size);
/* If an array with a variable number of elements is declared, and /* If an array with a variable number of elements is declared, and
the elements require destruction, we will emit a cleanup for the the elements require destruction, we will emit a cleanup for the
...@@ -161,6 +157,7 @@ variable_size (tree size) ...@@ -161,6 +157,7 @@ variable_size (tree size)
`unsaved', i.e., all SAVE_EXPRs are recalculated. However, we do `unsaved', i.e., all SAVE_EXPRs are recalculated. However, we do
not wish to do that here; the array-size is the same in both not wish to do that here; the array-size is the same in both
places. */ places. */
save = skip_simple_arithmetic (size);
if (TREE_CODE (save) == SAVE_EXPR) if (TREE_CODE (save) == SAVE_EXPR)
SAVE_EXPR_PERSISTENT_P (save) = 1; SAVE_EXPR_PERSISTENT_P (save) = 1;
...@@ -185,6 +182,60 @@ variable_size (tree size) ...@@ -185,6 +182,60 @@ variable_size (tree size)
return size; return size;
} }
/* Given a type T, force elaboration of any SAVE_EXPRs used in the definition
of that type. */
void
force_type_save_exprs (tree t)
{
tree field;
switch (TREE_CODE (t))
{
case ERROR_MARK:
return;
case ARRAY_TYPE:
case SET_TYPE:
case VECTOR_TYPE:
/* It's probably overly-conservative to force elaboration of bounds and
also the sizes, but it's better to be safe than sorry. */
force_type_save_exprs_1 (TYPE_MIN_VALUE (TYPE_DOMAIN (t)));
force_type_save_exprs_1 (TYPE_MAX_VALUE (TYPE_DOMAIN (t)));
break;
case RECORD_TYPE:
case UNION_TYPE:
case QUAL_UNION_TYPE:
for (field = TYPE_FIELDS (t); field; field = TREE_CHAIN (field))
if (TREE_CODE (field) == FIELD_DECL)
{
force_type_save_exprs (TREE_TYPE (field));
force_type_save_exprs_1 (DECL_FIELD_OFFSET (field));
}
break;
default:
break;
}
force_type_save_exprs_1 (TYPE_SIZE (t));
force_type_save_exprs_1 (TYPE_SIZE_UNIT (t));
}
/* Utility routine of above, to verify that SIZE has been elaborated and
do so it it is a SAVE_EXPR and has not been. */
static void
force_type_save_exprs_1 (tree size)
{
if (size
&& (size = skip_simple_arithmetic (size))
&& TREE_CODE (size) == SAVE_EXPR
&& !SAVE_EXPR_RTL (size))
expand_expr (size, NULL_RTX, VOIDmode, 0);
}
#ifndef MAX_FIXED_MODE_SIZE #ifndef MAX_FIXED_MODE_SIZE
#define MAX_FIXED_MODE_SIZE GET_MODE_BITSIZE (DImode) #define MAX_FIXED_MODE_SIZE GET_MODE_BITSIZE (DImode)
......
2004-04-12 Richard Kenner <kenner@vlsi1.ultra.nyu.edu>
* gcc.c-torture/execute/20040411-1.c: New test.
2004-04-10 Joseph S. Myers <jsm@polyomino.org.uk> 2004-04-10 Joseph S. Myers <jsm@polyomino.org.uk>
* gcc.dg/c90-intprom-1.c, gcc.dg/c99-intprom-1.c: New tests. * gcc.dg/c90-intprom-1.c, gcc.dg/c99-intprom-1.c: New tests.
......
int
sub1 (int i, int j)
{
typedef int c[i+2];
int x[10], y[10];
if (j == 2)
{
memcpy (x, y, 10 * sizeof (int));
return sizeof (c);
}
else
return sizeof (c) * 3;
}
int
main ()
{
if (sub1 (20, 3) != 66 * sizeof (int))
abort ();
return 0;
}
...@@ -271,6 +271,7 @@ remap_type (tree type, inline_data *id) ...@@ -271,6 +271,7 @@ remap_type (tree type, inline_data *id)
t = TYPE_MIN_VALUE (new); t = TYPE_MIN_VALUE (new);
if (t && TREE_CODE (t) != INTEGER_CST) if (t && TREE_CODE (t) != INTEGER_CST)
walk_tree (&TYPE_MIN_VALUE (new), copy_body_r, id, NULL); walk_tree (&TYPE_MIN_VALUE (new), copy_body_r, id, NULL);
t = TYPE_MAX_VALUE (new); t = TYPE_MAX_VALUE (new);
if (t && TREE_CODE (t) != INTEGER_CST) if (t && TREE_CODE (t) != INTEGER_CST)
walk_tree (&TYPE_MAX_VALUE (new), copy_body_r, id, NULL); walk_tree (&TYPE_MAX_VALUE (new), copy_body_r, id, NULL);
...@@ -278,14 +279,14 @@ remap_type (tree type, inline_data *id) ...@@ -278,14 +279,14 @@ remap_type (tree type, inline_data *id)
case POINTER_TYPE: case POINTER_TYPE:
TREE_TYPE (new) = t = remap_type (TREE_TYPE (new), id); TREE_TYPE (new) = t = remap_type (TREE_TYPE (new), id);
if (TYPE_MODE (new) == ptr_mode) TYPE_NEXT_PTR_TO (new) = TYPE_POINTER_TO (t);
TYPE_POINTER_TO (t) = new; TYPE_POINTER_TO (t) = new;
return new; return new;
case REFERENCE_TYPE: case REFERENCE_TYPE:
TREE_TYPE (new) = t = remap_type (TREE_TYPE (new), id); TREE_TYPE (new) = t = remap_type (TREE_TYPE (new), id);
if (TYPE_MODE (new) == ptr_mode) TYPE_NEXT_REF_TO (new) = TYPE_REFERENCE_TO (t);
TYPE_REFERENCE_TO (t) = new; TYPE_REFERENCE_TO (t) = new;
return new; return new;
case METHOD_TYPE: case METHOD_TYPE:
...@@ -2082,6 +2083,7 @@ copy_tree_r (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED) ...@@ -2082,6 +2083,7 @@ copy_tree_r (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
|| TREE_CODE_CLASS (code) == 'c' || TREE_CODE_CLASS (code) == 'c'
|| code == TREE_LIST || code == TREE_LIST
|| code == TREE_VEC || code == TREE_VEC
|| code == TYPE_DECL
|| lang_hooks.tree_inlining.tree_chain_matters_p (*tp)) || lang_hooks.tree_inlining.tree_chain_matters_p (*tp))
{ {
/* Because the chain gets clobbered when we make a copy, we save it /* Because the chain gets clobbered when we make a copy, we save it
......
...@@ -4629,38 +4629,62 @@ variably_modified_type_p (tree type) ...@@ -4629,38 +4629,62 @@ variably_modified_type_p (tree type)
case POINTER_TYPE: case POINTER_TYPE:
case REFERENCE_TYPE: case REFERENCE_TYPE:
case ARRAY_TYPE: case ARRAY_TYPE:
/* If TYPE is a pointer or reference, it is variably modified if case SET_TYPE:
the type pointed to is variably modified. Similarly for arrays; case VECTOR_TYPE:
note that VLAs are handled by the TYPE_SIZE check above. */ if (variably_modified_type_p (TREE_TYPE (type)))
return variably_modified_type_p (TREE_TYPE (type)); return true;
break;
case FUNCTION_TYPE: case FUNCTION_TYPE:
case METHOD_TYPE: case METHOD_TYPE:
/* If TYPE is a function type, it is variably modified if any of the /* If TYPE is a function type, it is variably modified if any of the
parameters or the return type are variably modified. */ parameters or the return type are variably modified. */
{ if (variably_modified_type_p (TREE_TYPE (type)))
tree parm; return true;
if (variably_modified_type_p (TREE_TYPE (type))) for (t = TYPE_ARG_TYPES (type);
t && t != void_list_node;
t = TREE_CHAIN (t))
if (variably_modified_type_p (TREE_VALUE (t)))
return true; return true;
for (parm = TYPE_ARG_TYPES (type);
parm && parm != void_list_node;
parm = TREE_CHAIN (parm))
if (variably_modified_type_p (TREE_VALUE (parm)))
return true;
}
break; break;
case INTEGER_TYPE: case INTEGER_TYPE:
case REAL_TYPE:
case ENUMERAL_TYPE:
case BOOLEAN_TYPE:
case CHAR_TYPE:
/* Scalar types are variably modified if their end points /* Scalar types are variably modified if their end points
aren't constant. */ aren't constant. */
t = TYPE_MIN_VALUE (type); t = TYPE_MIN_VALUE (type);
if (t && t != error_mark_node && TREE_CODE (t) != INTEGER_CST) if (t && t != error_mark_node && TREE_CODE (t) != INTEGER_CST)
return true; return true;
t = TYPE_MAX_VALUE (type); t = TYPE_MAX_VALUE (type);
if (t && t != error_mark_node && TREE_CODE (t) != INTEGER_CST) if (t && t != error_mark_node && TREE_CODE (t) != INTEGER_CST)
return true; return true;
return false; break;
case RECORD_TYPE:
case UNION_TYPE:
case QUAL_UNION_TYPE:
/* We can't see if any of the field are variably-modified by the
definition we normally use, since that would produce infinite
recursion via pointers. */
/* This is variably modified if some field's type is. */
for (t = TYPE_FIELDS (type); t; t = TREE_CHAIN (t))
if (TREE_CODE (t) == FIELD_DECL)
{
tree t1 = DECL_FIELD_OFFSET (t);
if (t1 && t1 != error_mark_node && TREE_CODE (t1) != INTEGER_CST)
return true;
t1 = DECL_SIZE (t);
if (t1 && t1 != error_mark_node && TREE_CODE (t1) != INTEGER_CST)
return true;
}
break;
default: default:
break; break;
......
...@@ -2768,6 +2768,11 @@ extern tree substitute_placeholder_in_expr (tree, tree); ...@@ -2768,6 +2768,11 @@ extern tree substitute_placeholder_in_expr (tree, tree);
extern tree variable_size (tree); extern tree variable_size (tree);
/* Given a type T, force elaboration of any SAVE_EXPRs used in the definition
of that type. */
extern void force_type_save_exprs (tree);
/* stabilize_reference (EXP) returns a reference equivalent to EXP /* stabilize_reference (EXP) returns a reference equivalent to EXP
but it can be used multiple times but it can be used multiple times
and only evaluate the subexpressions once. */ and only evaluate the subexpressions once. */
......
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