aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Kenner <kenner@vlsi1.ultra.nyu.edu>2004-04-12 21:25:55 +0000
committerRichard Kenner <kenner@gcc.gnu.org>2004-04-12 17:25:55 -0400
commit1c9766da11d71cb57f8962a2eb88833c1ca966f5 (patch)
treefc6c6b14412060a9d6d90d3f45c768a4648b7f4b
parent040e098a5de9115501bd76ce0ea7adc9a0eded21 (diff)
downloadgcc-1c9766da11d71cb57f8962a2eb88833c1ca966f5.zip
gcc-1c9766da11d71cb57f8962a2eb88833c1ca966f5.tar.gz
gcc-1c9766da11d71cb57f8962a2eb88833c1ca966f5.tar.bz2
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
-rw-r--r--gcc/ChangeLog16
-rw-r--r--gcc/c-decl.c8
-rw-r--r--gcc/c-semantics.c2
-rw-r--r--gcc/stmt.c9
-rw-r--r--gcc/stor-layout.c63
-rw-r--r--gcc/testsuite/ChangeLog4
-rw-r--r--gcc/testsuite/gcc.c-torture/execute/20040411-1.c23
-rw-r--r--gcc/tree-inline.c10
-rw-r--r--gcc/tree.c52
-rw-r--r--gcc/tree.h5
10 files changed, 160 insertions, 32 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index ac9f0c9..72ec5b5 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,19 @@
+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>
* simplify-rtx.c (simplify_binary_operation) <UDIV, DIV, UMOD, MOD>:
diff --git a/gcc/c-decl.c b/gcc/c-decl.c
index de96be3..8f19647 100644
--- a/gcc/c-decl.c
+++ b/gcc/c-decl.c
@@ -2979,7 +2979,13 @@ finish_decl (tree decl, tree init, tree asmspec_tree)
mark_referenced (DECL_ASSEMBLER_NAME (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
of types defined inside that declaration. There is no use
diff --git a/gcc/c-semantics.c b/gcc/c-semantics.c
index 17a301c..a8693f9 100644
--- a/gcc/c-semantics.c
+++ b/gcc/c-semantics.c
@@ -389,6 +389,8 @@ genrtl_decl_stmt (tree t)
else if (TREE_CODE (decl) == LABEL_DECL
&& C_DECLARED_LABEL_FLAG (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)
(*lang_expand_decl_stmt) (t);
}
diff --git a/gcc/stmt.c b/gcc/stmt.c
index aee5744..422fd05 100644
--- a/gcc/stmt.c
+++ b/gcc/stmt.c
@@ -4013,13 +4013,8 @@ expand_decl (tree decl)
do_pending_stack_adjust ();
save_stack_pointer ();
- /* In function-at-a-time mode, variable_size doesn't expand this,
- so do it now. */
- 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. */
+ /* Compute the variable's size, in bytes. This will expand any
+ needed SAVE_EXPRs for the first time. */
size = expand_expr (DECL_SIZE_UNIT (decl), NULL_RTX, VOIDmode, 0);
free_temp_slots ();
diff --git a/gcc/stor-layout.c b/gcc/stor-layout.c
index 2baa364..d19fc9f 100644
--- a/gcc/stor-layout.c
+++ b/gcc/stor-layout.c
@@ -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,
HOST_WIDE_INT, tree);
#endif
+static void force_type_save_exprs_1 (tree);
static unsigned int update_alignment_for_field (record_layout_info, tree,
unsigned int);
extern void debug_rli (record_layout_info);
@@ -146,12 +147,7 @@ variable_size (tree size)
|| CONTAINS_PLACEHOLDER_P (size))
return size;
- if (TREE_CODE (size) == MINUS_EXPR && integer_onep (TREE_OPERAND (size, 1)))
- /* 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);
+ size = save_expr (size);
/* If an array with a variable number of elements is declared, and
the elements require destruction, we will emit a cleanup for the
@@ -161,6 +157,7 @@ variable_size (tree size)
`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
places. */
+ save = skip_simple_arithmetic (size);
if (TREE_CODE (save) == SAVE_EXPR)
SAVE_EXPR_PERSISTENT_P (save) = 1;
@@ -185,6 +182,60 @@ variable_size (tree 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
#define MAX_FIXED_MODE_SIZE GET_MODE_BITSIZE (DImode)
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 040aac8..df7d2e1 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,7 @@
+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>
* gcc.dg/c90-intprom-1.c, gcc.dg/c99-intprom-1.c: New tests.
diff --git a/gcc/testsuite/gcc.c-torture/execute/20040411-1.c b/gcc/testsuite/gcc.c-torture/execute/20040411-1.c
new file mode 100644
index 0000000..8db4562
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/execute/20040411-1.c
@@ -0,0 +1,23 @@
+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;
+}
diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c
index d9aeefe..622ae18 100644
--- a/gcc/tree-inline.c
+++ b/gcc/tree-inline.c
@@ -271,6 +271,7 @@ remap_type (tree type, inline_data *id)
t = TYPE_MIN_VALUE (new);
if (t && TREE_CODE (t) != INTEGER_CST)
walk_tree (&TYPE_MIN_VALUE (new), copy_body_r, id, NULL);
+
t = TYPE_MAX_VALUE (new);
if (t && TREE_CODE (t) != INTEGER_CST)
walk_tree (&TYPE_MAX_VALUE (new), copy_body_r, id, NULL);
@@ -278,14 +279,14 @@ remap_type (tree type, inline_data *id)
case POINTER_TYPE:
TREE_TYPE (new) = t = remap_type (TREE_TYPE (new), id);
- if (TYPE_MODE (new) == ptr_mode)
- TYPE_POINTER_TO (t) = new;
+ TYPE_NEXT_PTR_TO (new) = TYPE_POINTER_TO (t);
+ TYPE_POINTER_TO (t) = new;
return new;
case REFERENCE_TYPE:
TREE_TYPE (new) = t = remap_type (TREE_TYPE (new), id);
- if (TYPE_MODE (new) == ptr_mode)
- TYPE_REFERENCE_TO (t) = new;
+ TYPE_NEXT_REF_TO (new) = TYPE_REFERENCE_TO (t);
+ TYPE_REFERENCE_TO (t) = new;
return new;
case METHOD_TYPE:
@@ -2082,6 +2083,7 @@ copy_tree_r (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
|| TREE_CODE_CLASS (code) == 'c'
|| code == TREE_LIST
|| code == TREE_VEC
+ || code == TYPE_DECL
|| lang_hooks.tree_inlining.tree_chain_matters_p (*tp))
{
/* Because the chain gets clobbered when we make a copy, we save it
diff --git a/gcc/tree.c b/gcc/tree.c
index d4dd3fe..0b301e2 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -4629,38 +4629,62 @@ variably_modified_type_p (tree type)
case POINTER_TYPE:
case REFERENCE_TYPE:
case ARRAY_TYPE:
- /* If TYPE is a pointer or reference, it is variably modified if
- the type pointed to is variably modified. Similarly for arrays;
- note that VLAs are handled by the TYPE_SIZE check above. */
- return variably_modified_type_p (TREE_TYPE (type));
+ case SET_TYPE:
+ case VECTOR_TYPE:
+ if (variably_modified_type_p (TREE_TYPE (type)))
+ return true;
+ break;
case FUNCTION_TYPE:
case METHOD_TYPE:
/* If TYPE is a function type, it is variably modified if any of the
parameters or the return type are variably modified. */
- {
- tree parm;
+ if (variably_modified_type_p (TREE_TYPE (type)))
+ 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;
- 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;
case INTEGER_TYPE:
+ case REAL_TYPE:
+ case ENUMERAL_TYPE:
+ case BOOLEAN_TYPE:
+ case CHAR_TYPE:
/* Scalar types are variably modified if their end points
aren't constant. */
t = TYPE_MIN_VALUE (type);
if (t && t != error_mark_node && TREE_CODE (t) != INTEGER_CST)
return true;
+
t = TYPE_MAX_VALUE (type);
if (t && t != error_mark_node && TREE_CODE (t) != INTEGER_CST)
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:
break;
diff --git a/gcc/tree.h b/gcc/tree.h
index 34e6f45..12dec42 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -2768,6 +2768,11 @@ extern tree substitute_placeholder_in_expr (tree, 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
but it can be used multiple times
and only evaluate the subexpressions once. */