c: minor fixes related to arrays of unspecified size

The patch for PR117145 and PR117245 also fixed PR100420 and PR116284 which
are bugs related to arrays of unspecified size.  Those are now represented
as variable size arrays with size (0, 0).  There are still some loose ends,
which are resolved here by

1. adding a testcase for PR116284,
2. moving code related to creation and detection of arrays of unspecified
sizes in their own functions,
3. preferring a specified size over an unspecified size when forming
a composite type as required by C99 (PR118391)
4. removing useless code in comptypes_internal and composite_type_internal.

	PR c/116284
	PR c/117391

gcc/c/ChangeLog:
	* c-tree.h (c_type_unspecified_p): New inline function.
	* c-typeck.cc (c_build_array_type_unspecified): New function.
	(comptypes_interal): Remove useless code.
	(composite_type_internal): Update.
	* c-decl.cc (grokdeclarator): Revise.

gcc/testsuite/ChangeLog:
	* gcc.dg/pr116284.c: New test.
	* gcc.dg/pr117391.c: New test.
This commit is contained in:
Martin Uecker 2024-11-01 10:15:44 +01:00 committed by Martin Uecker
parent 9c8f3d5e7d
commit 114abf075c
5 changed files with 72 additions and 24 deletions

View File

@ -7501,10 +7501,6 @@ grokdeclarator (const struct c_declarator *declarator,
/* C99 6.7.5.2p4 */ /* C99 6.7.5.2p4 */
if (decl_context == TYPENAME) if (decl_context == TYPENAME)
warning (0, "%<[*]%> not in a declaration"); warning (0, "%<[*]%> not in a declaration");
/* Array of unspecified size. */
tree upper = build2 (COMPOUND_EXPR, TREE_TYPE (size_zero_node),
integer_zero_node, size_zero_node);
itype = build_index_type (upper);
size_varies = true; size_varies = true;
} }
@ -7540,6 +7536,9 @@ grokdeclarator (const struct c_declarator *declarator,
if (!ADDR_SPACE_GENERIC_P (as) && as != TYPE_ADDR_SPACE (type)) if (!ADDR_SPACE_GENERIC_P (as) && as != TYPE_ADDR_SPACE (type))
type = c_build_qualified_type (type, type = c_build_qualified_type (type,
ENCODE_QUAL_ADDR_SPACE (as)); ENCODE_QUAL_ADDR_SPACE (as));
if (array_parm_vla_unspec_p)
type = c_build_array_type_unspecified (type);
else
type = c_build_array_type (type, itype); type = c_build_array_type (type, itype);
} }

View File

@ -776,12 +776,22 @@ extern struct c_switch *c_switch_stack;
extern bool null_pointer_constant_p (const_tree); extern bool null_pointer_constant_p (const_tree);
inline inline bool
bool c_type_variably_modified_p (tree t) c_type_variably_modified_p (tree t)
{ {
return error_mark_node != t && C_TYPE_VARIABLY_MODIFIED (t); return error_mark_node != t && C_TYPE_VARIABLY_MODIFIED (t);
} }
inline bool
c_type_unspecified_p (tree t)
{
return error_mark_node != t
&& C_TYPE_VARIABLE_SIZE (t) && TREE_CODE (t) == ARRAY_TYPE
&& TYPE_DOMAIN (t) && TYPE_MAX_VALUE (TYPE_DOMAIN (t))
&& TREE_CODE (TYPE_MAX_VALUE (TYPE_DOMAIN (t))) == COMPOUND_EXPR
&& integer_zerop (TREE_OPERAND (TYPE_MAX_VALUE (TYPE_DOMAIN (t)), 0))
&& integer_zerop (TREE_OPERAND (TYPE_MAX_VALUE (TYPE_DOMAIN (t)), 1));
}
extern bool char_type_p (tree); extern bool char_type_p (tree);
extern tree c_objc_common_truthvalue_conversion (location_t, tree, extern tree c_objc_common_truthvalue_conversion (location_t, tree,
@ -883,10 +893,10 @@ extern tree c_reconstruct_complex_type (tree, tree);
extern tree c_build_type_attribute_variant (tree ntype, tree attrs); extern tree c_build_type_attribute_variant (tree ntype, tree attrs);
extern tree c_build_pointer_type (tree type); extern tree c_build_pointer_type (tree type);
extern tree c_build_array_type (tree type, tree domain); extern tree c_build_array_type (tree type, tree domain);
extern tree c_build_array_type_unspecified (tree type);
extern tree c_build_function_type (tree type, tree args, bool no = false); extern tree c_build_function_type (tree type, tree args, bool no = false);
extern tree c_build_pointer_type_for_mode (tree type, machine_mode mode, bool m); extern tree c_build_pointer_type_for_mode (tree type, machine_mode mode, bool m);
/* Set to 0 at beginning of a function definition, set to 1 if /* Set to 0 at beginning of a function definition, set to 1 if
a return statement that specifies a return value is seen. */ a return statement that specifies a return value is seen. */

View File

@ -358,7 +358,7 @@ qualify_type (tree type, tree like)
} }
/* Check consistency of type TYP.E For derived types, we test that /* Check consistency of type TYPE. For derived types, we test that
C_TYPE_VARIABLE_SIZE and C_TYPE_VARIABLY_MODIFIED are consistent with C_TYPE_VARIABLE_SIZE and C_TYPE_VARIABLY_MODIFIED are consistent with
the requirements of the base type. We also check that arrays with a the requirements of the base type. We also check that arrays with a
non-constant length are marked with C_TYPE_VARIABLE_SIZE. If any non-constant length are marked with C_TYPE_VARIABLE_SIZE. If any
@ -490,6 +490,17 @@ c_build_array_type (tree type, tree domain)
return c_set_type_bits (ret, type); return c_set_type_bits (ret, type);
} }
/* Build an array type of unspecified size. */
tree
c_build_array_type_unspecified (tree type)
{
tree upper = build2 (COMPOUND_EXPR, TREE_TYPE (size_zero_node),
integer_zero_node, size_zero_node);
return c_build_array_type (type, build_index_type (upper));
}
tree tree
c_build_type_attribute_qual_variant (tree type, tree attrs, int quals) c_build_type_attribute_qual_variant (tree type, tree attrs, int quals)
{ {
@ -660,15 +671,23 @@ composite_type_internal (tree t1, tree t2, struct composite_cache* cache)
d2_variable = (!d2_zero d2_variable = (!d2_zero
&& (TREE_CODE (TYPE_MIN_VALUE (d2)) != INTEGER_CST && (TREE_CODE (TYPE_MIN_VALUE (d2)) != INTEGER_CST
|| TREE_CODE (TYPE_MAX_VALUE (d2)) != INTEGER_CST)); || TREE_CODE (TYPE_MAX_VALUE (d2)) != INTEGER_CST));
d1_variable = d1_variable || (d1_zero && C_TYPE_VARIABLE_SIZE (t1));
d2_variable = d2_variable || (d2_zero && C_TYPE_VARIABLE_SIZE (t2)); bool use1 = TYPE_DOMAIN (t1)
&& (d2_variable || d2_zero || !d1_variable);
bool use2 = TYPE_DOMAIN (t2)
&& (d1_variable || d1_zero || !d2_variable);
/* If the first is an unspecified size pick the other one. */
if (d2_variable && c_type_unspecified_p (t1))
{
gcc_assert (use1 && use2);
use1 = false;
}
/* Save space: see if the result is identical to one of the args. */ /* Save space: see if the result is identical to one of the args. */
if (elt == TREE_TYPE (t1) && TYPE_DOMAIN (t1) if (elt == TREE_TYPE (t1) && use1)
&& (d2_variable || d2_zero || !d1_variable))
return c_build_type_attribute_variant (t1, attributes); return c_build_type_attribute_variant (t1, attributes);
if (elt == TREE_TYPE (t2) && TYPE_DOMAIN (t2) if (elt == TREE_TYPE (t2) && use2)
&& (d1_variable || d1_zero || !d2_variable))
return c_build_type_attribute_variant (t2, attributes); return c_build_type_attribute_variant (t2, attributes);
if (elt == TREE_TYPE (t1) && !TYPE_DOMAIN (t2) && !TYPE_DOMAIN (t1)) if (elt == TREE_TYPE (t1) && !TYPE_DOMAIN (t2) && !TYPE_DOMAIN (t1))
@ -683,13 +702,7 @@ composite_type_internal (tree t1, tree t2, struct composite_cache* cache)
back at the end. */ back at the end. */
quals = TYPE_QUALS (strip_array_types (elt)); quals = TYPE_QUALS (strip_array_types (elt));
unqual_elt = c_build_qualified_type (elt, TYPE_UNQUALIFIED); unqual_elt = c_build_qualified_type (elt, TYPE_UNQUALIFIED);
t1 = c_build_array_type (unqual_elt, t1 = c_build_array_type (unqual_elt, TYPE_DOMAIN (use1 ? t1 : t2));
TYPE_DOMAIN ((TYPE_DOMAIN (t1)
&& (d2_variable
|| d2_zero
|| !d1_variable))
? t1
: t2));
/* Check that a type which has a varying outermost dimension /* Check that a type which has a varying outermost dimension
got marked has having a variable size. */ got marked has having a variable size. */
@ -1658,8 +1671,6 @@ comptypes_internal (const_tree type1, const_tree type2,
d2_variable = (!d2_zero d2_variable = (!d2_zero
&& (TREE_CODE (TYPE_MIN_VALUE (d2)) != INTEGER_CST && (TREE_CODE (TYPE_MIN_VALUE (d2)) != INTEGER_CST
|| TREE_CODE (TYPE_MAX_VALUE (d2)) != INTEGER_CST)); || TREE_CODE (TYPE_MAX_VALUE (d2)) != INTEGER_CST));
d1_variable = d1_variable || (d1_zero && C_TYPE_VARIABLE_SIZE (t1));
d2_variable = d2_variable || (d2_zero && C_TYPE_VARIABLE_SIZE (t2));
if (d1_variable != d2_variable) if (d1_variable != d2_variable)
data->different_types_p = true; data->different_types_p = true;

View File

@ -0,0 +1,14 @@
/* { dg-do compile } */
/* { dg-options "-std=gnu23" } */
// There should be no warning about variably-modified types
static int a[0];
static int b[sizeof a];
void foo(int (*x)[*]);
static int c[0];
static int d[sizeof c];

View File

@ -0,0 +1,14 @@
/* { dg-do compile } */
/* { dg-options "-std=c99" } */
int foo(int n, char (*buf)[*]);
int bar(int n, char (*buf)[n]);
void test()
{
(1 ? foo : bar)(0); /* { dg-error "too few arguments to function '\\\(int \\\(\\\*\\\)\\\(int, char \\\(\\\*\\\)\\\[n]\\\)\\\)&foo'" } */
(0 ? bar : foo)(0); /* { dg-error "too few arguments to function '\\\(int \\\(\\\*\\\)\\\(int, char \\\(\\\*\\\)\\\[n]\\\)\\\)&foo'" } */
(0 ? foo : bar)(0); /* { dg-error "too few arguments to function 'bar'" } */
(1 ? bar : foo)(0); /* { dg-error "too few arguments to function 'bar'" } */
}