This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
fix c/20519
- From: Richard Henderson <rth at redhat dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Tue, 29 Mar 2005 17:45:25 -0800
- Subject: fix c/20519
This was way harder than I expected it to be, due to the very different
ways that initializers are handled between the C and C++ front ends...
The root problem was that we were modifying an existing type node, with
the consequences being that types propagated via __typeof may be modified
behind our back. Further, the a type's main variant would not necessarily
match.
Someone had found the later problem in the C++ front end, but had chosen
to fix the problem with even more type modification. I thought that pretty
questionable, so I've changed both front ends to use a bit of common code.
Tested on i686-linux.
r~
PR c/20519
* c-decl.c (c_finish_incomplete_decl): Update complete_array_type call.
(build_compound_literal): Likewise. Propagate decl type into the
initializer.
(finish_decl): Likewise. Use new return value from complete_array_type
for zero sized arrays.
(complete_array_type): Move ...
* c-common.c (complete_array_type): ... here. Change first argument
to pointer-to-type-node. Consistently use sizetype for the index
except for zero sized arrays. Detect zero sized arrays for pedantic
mode diagnostics. Create a new type node instead of modifying the
old node in place.
* c-tree.h (complete_array_type): Move decl ...
* c-common.h (complete_array_type): ... here.
cp/
* decl.c (cp_complete_array_type): Rename from complete_array_type.
Use the new complete_array_type in c-common.c. Update all callers.
* cp-tree.h (cp_complete_array_type): Update to match.
Index: gcc/c-common.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-common.c,v
retrieving revision 1.617
diff -u -p -d -r1.617 c-common.c
--- gcc/c-common.c 23 Mar 2005 01:35:00 -0000 1.617
+++ gcc/c-common.c 29 Mar 2005 22:54:42 -0000
@@ -5756,5 +5756,94 @@ lvalue_error (enum lvalue_use use)
gcc_unreachable ();
}
}
+
+/* *PTYPE is an incomplete array. Complete it with a domain based on
+ INITIAL_VALUE. If INITIAL_VALUE is not present, use 1 if DO_DEFAULT
+ is true. Return 0 if successful, 1 if INITIAL_VALUE can't be deciphered,
+ 2 if INITIAL_VALUE was NULL, and 3 if INITIAL_VALUE was empty. */
+
+int
+complete_array_type (tree *ptype, tree initial_value, bool do_default)
+{
+ tree maxindex, type, main_type, elt, unqual_elt;
+ int failure = 0, quals;
+
+ maxindex = size_zero_node;
+ if (initial_value)
+ {
+ if (TREE_CODE (initial_value) == STRING_CST)
+ {
+ int eltsize
+ = int_size_in_bytes (TREE_TYPE (TREE_TYPE (initial_value)));
+ maxindex = size_int (TREE_STRING_LENGTH (initial_value)/eltsize - 1);
+ }
+ else if (TREE_CODE (initial_value) == CONSTRUCTOR)
+ {
+ tree elts = CONSTRUCTOR_ELTS (initial_value);
+
+ if (elts == NULL)
+ {
+ if (pedantic)
+ failure = 3;
+ maxindex = integer_minus_one_node;
+ }
+ else
+ {
+ tree curindex;
+
+ if (TREE_PURPOSE (elts))
+ maxindex = fold_convert (sizetype, TREE_PURPOSE (elts));
+ curindex = maxindex;
+
+ for (elts = TREE_CHAIN (elts); elts; elts = TREE_CHAIN (elts))
+ {
+ if (TREE_PURPOSE (elts))
+ curindex = fold_convert (sizetype, TREE_PURPOSE (elts));
+ else
+ curindex = size_binop (PLUS_EXPR, curindex, size_one_node);
+
+ if (tree_int_cst_lt (maxindex, curindex))
+ maxindex = curindex;
+ }
+ }
+ }
+ else
+ {
+ /* Make an error message unless that happened already. */
+ if (initial_value != error_mark_node)
+ failure = 1;
+ }
+ }
+ else
+ {
+ failure = 2;
+ if (!do_default)
+ return failure;
+ }
+
+ type = *ptype;
+ elt = TREE_TYPE (type);
+ quals = TYPE_QUALS (strip_array_types (elt));
+ if (quals == 0)
+ unqual_elt = elt;
+ else
+ unqual_elt = c_build_qualified_type (elt, TYPE_UNQUALIFIED);
+
+ /* Using build_distinct_type_copy and modifying things afterward instead
+ of using build_array_type to create a new type preserves all of the
+ TYPE_LANG_FLAG_? bits that the front end may have set. */
+ main_type = build_distinct_type_copy (TYPE_MAIN_VARIANT (type));
+ TREE_TYPE (main_type) = unqual_elt;
+ TYPE_DOMAIN (main_type) = build_index_type (maxindex);
+ layout_type (main_type);
+
+ if (quals == 0)
+ type = main_type;
+ else
+ type = c_build_qualified_type (main_type, quals);
+
+ *ptype = type;
+ return failure;
+}
#include "gt-c-common.h"
Index: gcc/c-common.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-common.h,v
retrieving revision 1.279
diff -u -p -d -r1.279 c-common.h
--- gcc/c-common.h 23 Mar 2005 01:28:50 -0000 1.279
+++ gcc/c-common.h 29 Mar 2005 22:54:42 -0000
@@ -888,6 +888,8 @@ enum lvalue_use {
extern void lvalue_error (enum lvalue_use);
+extern int complete_array_type (tree *, tree, bool);
+
/* In c-gimplify.c */
extern void c_genericize (tree);
extern int c_gimplify_expr (tree *, tree *, tree *);
Index: gcc/c-decl.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-decl.c,v
retrieving revision 1.640
diff -u -p -d -r1.640 c-decl.c
--- gcc/c-decl.c 20 Mar 2005 15:23:47 -0000 1.640
+++ gcc/c-decl.c 29 Mar 2005 22:54:45 -0000
@@ -529,7 +529,7 @@ c_finish_incomplete_decl (tree decl)
{
warning ("%Jarray %qD assumed to have one element", decl, decl);
- complete_array_type (type, NULL_TREE, 1);
+ complete_array_type (&TREE_TYPE (decl), NULL_TREE, true);
layout_decl (decl, 0);
}
@@ -3168,14 +3168,15 @@ finish_decl (tree decl, tree init, tree
&& TYPE_DOMAIN (type) == 0
&& TREE_CODE (decl) != TYPE_DECL)
{
- int do_default
+ bool do_default
= (TREE_STATIC (decl)
/* Even if pedantic, an external linkage array
may have incomplete type at first. */
? pedantic && !TREE_PUBLIC (decl)
: !DECL_EXTERNAL (decl));
int failure
- = complete_array_type (type, DECL_INITIAL (decl), do_default);
+ = complete_array_type (&TREE_TYPE (decl), DECL_INITIAL (decl),
+ do_default);
/* Get the completed type made by complete_array_type. */
type = TREE_TYPE (decl);
@@ -3196,14 +3197,12 @@ finish_decl (tree decl, tree init, tree
else if (!pedantic && TREE_STATIC (decl) && !TREE_PUBLIC (decl))
DECL_EXTERNAL (decl) = 1;
}
-
- /* TYPE_MAX_VALUE is always one less than the number of elements
- in the array, because we start counting at zero. Therefore,
- warn only if the value is less than zero. */
- else if (pedantic && TYPE_DOMAIN (type) != 0
- && tree_int_cst_sgn (TYPE_MAX_VALUE (TYPE_DOMAIN (type))) < 0)
+ else if (failure == 3)
error ("%Jzero or negative size array %qD", decl, decl);
+ if (DECL_INITIAL (decl))
+ TREE_TYPE (DECL_INITIAL (decl)) = type;
+
layout_decl (decl, 0);
}
@@ -3491,17 +3490,19 @@ build_compound_literal (tree type, tree
if (TREE_CODE (type) == ARRAY_TYPE && !COMPLETE_TYPE_P (type))
{
- int failure = complete_array_type (type, DECL_INITIAL (decl), 1);
-
+ int failure = complete_array_type (&TREE_TYPE (decl),
+ DECL_INITIAL (decl), true);
gcc_assert (!failure);
+
+ type = TREE_TYPE (decl);
+ TREE_TYPE (DECL_INITIAL (decl)) = type;
}
- type = TREE_TYPE (decl);
if (type == error_mark_node || !COMPLETE_TYPE_P (type))
return error_mark_node;
stmt = build_stmt (DECL_EXPR, decl);
- complit = build1 (COMPOUND_LITERAL_EXPR, TREE_TYPE (decl), stmt);
+ complit = build1 (COMPOUND_LITERAL_EXPR, type, stmt);
TREE_SIDE_EFFECTS (complit) = 1;
layout_decl (decl, 0);
@@ -3527,73 +3528,6 @@ build_compound_literal (tree type, tree
return complit;
}
-/* Make TYPE a complete type based on INITIAL_VALUE.
- Return 0 if successful, 1 if INITIAL_VALUE can't be deciphered,
- 2 if there was no information (in which case assume 1 if DO_DEFAULT). */
-
-int
-complete_array_type (tree type, tree initial_value, int do_default)
-{
- tree maxindex = NULL_TREE;
- int value = 0;
-
- if (initial_value)
- {
- /* Note MAXINDEX is really the maximum index,
- one less than the size. */
- if (TREE_CODE (initial_value) == STRING_CST)
- {
- int eltsize
- = int_size_in_bytes (TREE_TYPE (TREE_TYPE (initial_value)));
- maxindex = build_int_cst (NULL_TREE,
- (TREE_STRING_LENGTH (initial_value)
- / eltsize) - 1);
- }
- else if (TREE_CODE (initial_value) == CONSTRUCTOR)
- {
- tree elts = CONSTRUCTOR_ELTS (initial_value);
- maxindex = build_int_cst (NULL_TREE, -1);
- for (; elts; elts = TREE_CHAIN (elts))
- {
- if (TREE_PURPOSE (elts))
- maxindex = TREE_PURPOSE (elts);
- else
- maxindex = fold (build2 (PLUS_EXPR, integer_type_node,
- maxindex, integer_one_node));
- }
- }
- else
- {
- /* Make an error message unless that happened already. */
- if (initial_value != error_mark_node)
- value = 1;
-
- /* Prevent further error messages. */
- maxindex = build_int_cst (NULL_TREE, 0);
- }
- }
-
- if (!maxindex)
- {
- if (do_default)
- maxindex = build_int_cst (NULL_TREE, 0);
- value = 2;
- }
-
- if (maxindex)
- {
- TYPE_DOMAIN (type) = build_index_type (maxindex);
-
- gcc_assert (TREE_TYPE (maxindex));
- }
-
- /* Lay out the type now that we can get the real answer. */
-
- layout_type (type);
-
- return value;
-}
-
/* Determine whether TYPE is a structure with a flexible array member,
or a union containing such a structure (possibly recursively). */
Index: gcc/c-tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-tree.h,v
retrieving revision 1.197
diff -u -p -d -r1.197 c-tree.h
--- gcc/c-tree.h 23 Mar 2005 01:28:50 -0000 1.197
+++ gcc/c-tree.h 29 Mar 2005 22:54:45 -0000
@@ -378,7 +378,6 @@ extern struct c_declarator *build_array_
extern tree build_enumerator (tree, tree);
extern void check_for_loop_decls (void);
extern void mark_forward_parm_decls (void);
-extern int complete_array_type (tree, tree, int);
extern void declare_parm_level (void);
extern void undeclared_variable (tree, location_t);
extern tree declare_label (tree);
Index: gcc/cp/cp-tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/cp-tree.h,v
retrieving revision 1.1113
diff -u -p -d -r1.1113 cp-tree.h
--- gcc/cp/cp-tree.h 23 Mar 2005 01:29:08 -0000 1.1113
+++ gcc/cp/cp-tree.h 29 Mar 2005 22:54:46 -0000
@@ -3787,7 +3787,7 @@ extern tree start_decl (const cp_decl
extern void start_decl_1 (tree);
extern void cp_finish_decl (tree, tree, tree, int);
extern void finish_decl (tree, tree, tree);
-extern int complete_array_type (tree, tree, int);
+extern int cp_complete_array_type (tree *, tree, bool);
extern tree build_ptrmemfunc_type (tree);
extern tree build_ptrmem_type (tree, tree);
/* the grokdeclarator prototype is in decl.h */
Index: gcc/cp/decl.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/decl.c,v
retrieving revision 1.1381
diff -u -p -d -r1.1381 decl.c
--- gcc/cp/decl.c 22 Mar 2005 15:06:52 -0000 1.1381
+++ gcc/cp/decl.c 29 Mar 2005 22:54:48 -0000
@@ -3913,7 +3913,8 @@ maybe_deduce_size_from_array_init (tree
But let's leave it here to ease the eventual merge. */
int do_default = !DECL_EXTERNAL (decl);
tree initializer = init ? init : DECL_INITIAL (decl);
- int failure = complete_array_type (type, initializer, do_default);
+ int failure = cp_complete_array_type (&TREE_TYPE (decl), initializer,
+ do_default);
if (failure == 1)
error ("initializer fails to determine size of %qD", decl);
@@ -5331,102 +5332,41 @@ expand_static_init (tree decl, tree init
3 if the initializer list is empty (in pedantic mode). */
int
-complete_array_type (tree type, tree initial_value, int do_default)
+cp_complete_array_type (tree *ptype, tree initial_value, bool do_default)
{
- tree maxindex = NULL_TREE;
- int value = 0;
+ int failure;
+ tree type, elt_type;
if (initial_value)
{
/* An array of character type can be initialized from a
brace-enclosed string constant. */
- if (char_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (type)))
+ if (char_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (*ptype)))
&& TREE_CODE (initial_value) == CONSTRUCTOR
&& CONSTRUCTOR_ELTS (initial_value)
&& (TREE_CODE (TREE_VALUE (CONSTRUCTOR_ELTS (initial_value)))
== STRING_CST)
&& TREE_CHAIN (CONSTRUCTOR_ELTS (initial_value)) == NULL_TREE)
initial_value = TREE_VALUE (CONSTRUCTOR_ELTS (initial_value));
-
- /* Note MAXINDEX is really the maximum index, one less than the
- size. */
- if (TREE_CODE (initial_value) == STRING_CST)
- {
- int eltsize
- = int_size_in_bytes (TREE_TYPE (TREE_TYPE (initial_value)));
- maxindex = build_int_cst (NULL_TREE,
- (TREE_STRING_LENGTH (initial_value)
- / eltsize) - 1);
- }
- else if (TREE_CODE (initial_value) == CONSTRUCTOR)
- {
- tree elts = CONSTRUCTOR_ELTS (initial_value);
-
- maxindex = ssize_int (-1);
- for (; elts; elts = TREE_CHAIN (elts))
- {
- if (TREE_PURPOSE (elts))
- maxindex = TREE_PURPOSE (elts);
- else
- maxindex = size_binop (PLUS_EXPR, maxindex, ssize_int (1));
- }
-
- if (pedantic && tree_int_cst_equal (maxindex, ssize_int (-1)))
- value = 3;
- }
- else
- {
- /* Make an error message unless that happened already. */
- if (initial_value != error_mark_node)
- value = 1;
- else
- initial_value = NULL_TREE;
-
- /* Prevent further error messages. */
- maxindex = build_int_cst (NULL_TREE, 0);
- }
}
- if (!maxindex)
- {
- if (do_default)
- maxindex = build_int_cst (NULL_TREE, 0);
- value = 2;
- }
+ failure = complete_array_type (ptype, initial_value, do_default);
- if (maxindex)
+ /* We can create the array before the element type is complete, which
+ means that we didn't have these two bits set in the original type
+ either. In completing the type, we are expected to propagate these
+ bits. See also complete_type which does the same thing for arrays
+ of fixed size. */
+ type = *ptype;
+ if (TYPE_DOMAIN (type))
{
- tree itype;
- tree domain;
- tree elt_type;
-
- domain = build_index_type (maxindex);
- TYPE_DOMAIN (type) = domain;
-
- if (initial_value)
- itype = TREE_TYPE (initial_value);
- else
- itype = NULL;
- if (itype && !TYPE_DOMAIN (itype))
- TYPE_DOMAIN (itype) = domain;
- /* The type of the main variant should never be used for arrays
- of different sizes. It should only ever be completed with the
- size of the array. */
- if (! TYPE_DOMAIN (TYPE_MAIN_VARIANT (type)))
- TYPE_DOMAIN (TYPE_MAIN_VARIANT (type)) = domain;
-
elt_type = TREE_TYPE (type);
- TYPE_NEEDS_CONSTRUCTING (type)
- = TYPE_NEEDS_CONSTRUCTING (TYPE_MAIN_VARIANT (elt_type));
+ TYPE_NEEDS_CONSTRUCTING (type) = TYPE_NEEDS_CONSTRUCTING (elt_type);
TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type)
- = TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TYPE_MAIN_VARIANT (elt_type));
+ = TYPE_HAS_NONTRIVIAL_DESTRUCTOR (elt_type);
}
- /* Lay out the type now that we can get the real answer. */
-
- layout_type (type);
-
- return value;
+ return failure;
}
/* Return zero if something is declared to be a member of type
Index: gcc/cp/semantics.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/semantics.c,v
retrieving revision 1.465
diff -u -p -d -r1.465 semantics.c
--- gcc/cp/semantics.c 21 Mar 2005 11:49:32 -0000 1.465
+++ gcc/cp/semantics.c 29 Mar 2005 22:54:48 -0000
@@ -1996,7 +1996,8 @@ finish_compound_literal (tree type, tree
implies that the array has two elements. */
if (TREE_CODE (type) == ARRAY_TYPE && !COMPLETE_TYPE_P (type))
- complete_array_type (type, compound_literal, 1);
+ cp_complete_array_type (&TREE_TYPE (compound_literal),
+ compound_literal, 1);
}
return compound_literal;
Index: gcc/cp/typeck2.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/typeck2.c,v
retrieving revision 1.182
diff -u -p -d -r1.182 typeck2.c
--- gcc/cp/typeck2.c 18 Jan 2005 11:45:39 -0000 1.182
+++ gcc/cp/typeck2.c 29 Mar 2005 22:54:49 -0000
@@ -1123,7 +1123,7 @@ process_init_constructor (tree type, tre
result = build_constructor (type, nreverse (members));
if (TREE_CODE (type) == ARRAY_TYPE && TYPE_DOMAIN (type) == NULL_TREE)
- complete_array_type (type, result, /*do_default=*/0);
+ cp_complete_array_type (&TREE_TYPE (result), result, /*do_default=*/0);
if (init)
TREE_HAS_CONSTRUCTOR (result) = TREE_HAS_CONSTRUCTOR (init);
if (allconstant)