On Sat, 2 Nov 2024, Martin Uecker wrote:
> 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. 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/ChangeLog:
> * c/c-tree.h (c_type_unspecified_p): New inline function.
> * c/c-typeck.cc (c_build_array_type_unspecified): New function.
> (comptypes_interal): Remove useless code.
> (composite_type_internal): Update.
> * c/c-decl.cc (grokdeclarator): Revise.
These should go in gcc/c/ChangeLog without the c/ prefix.
>
> gcc/testsuite/ChangeLog:
> * gcc.dg/pr116284.c: New test.
> * gcc.dg/pr117391.c: New test.
The patch is OK with the above ChangeLog entry fix.
@@ -7501,10 +7501,6 @@ grokdeclarator (const struct c_declarator *declarator,
/* C99 6.7.5.2p4 */
if (decl_context == TYPENAME)
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;
}
@@ -7540,7 +7536,10 @@ grokdeclarator (const struct c_declarator *declarator,
if (!ADDR_SPACE_GENERIC_P (as) && as != TYPE_ADDR_SPACE (type))
type = c_build_qualified_type (type,
ENCODE_QUAL_ADDR_SPACE (as));
- type = c_build_array_type (type, itype);
+ if (array_parm_vla_unspec_p)
+ type = c_build_array_type_unspecified (type);
+ else
+ type = c_build_array_type (type, itype);
}
if (type != error_mark_node)
@@ -776,12 +776,22 @@ extern struct c_switch *c_switch_stack;
extern bool null_pointer_constant_p (const_tree);
-inline
-bool c_type_variably_modified_p (tree t)
+inline bool
+c_type_variably_modified_p (tree 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 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_pointer_type (tree type);
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_pointer_type_for_mode (tree type, machine_mode mode, bool m);
-
/* Set to 0 at beginning of a function definition, set to 1 if
a return statement that specifies a return value is seen. */
@@ -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
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
@@ -490,6 +490,17 @@ c_build_array_type (tree type, tree domain)
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
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
&& (TREE_CODE (TYPE_MIN_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. */
- if (elt == TREE_TYPE (t1) && TYPE_DOMAIN (t1)
- && (d2_variable || d2_zero || !d1_variable))
+ if (elt == TREE_TYPE (t1) && use1)
return c_build_type_attribute_variant (t1, attributes);
- if (elt == TREE_TYPE (t2) && TYPE_DOMAIN (t2)
- && (d1_variable || d1_zero || !d2_variable))
+ if (elt == TREE_TYPE (t2) && use2)
return c_build_type_attribute_variant (t2, attributes);
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. */
quals = TYPE_QUALS (strip_array_types (elt));
unqual_elt = c_build_qualified_type (elt, TYPE_UNQUALIFIED);
- t1 = c_build_array_type (unqual_elt,
- TYPE_DOMAIN ((TYPE_DOMAIN (t1)
- && (d2_variable
- || d2_zero
- || !d1_variable))
- ? t1
- : t2));
+ t1 = c_build_array_type (unqual_elt, TYPE_DOMAIN (use1 ? t1 : t2));
/* Check that a type which has a varying outermost dimension
got marked has having a variable size. */
@@ -1658,8 +1671,6 @@ comptypes_internal (const_tree type1, const_tree type2,
d2_variable = (!d2_zero
&& (TREE_CODE (TYPE_MIN_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)
data->different_types_p = true;
new file mode 100644
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+
+// 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];
+
+
new file mode 100644
@@ -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'" } */
+}
+