This changes the C FE to use the same representation for zero-sized
arrays as the C++ FE. After recent patches, this is relatively
straight-forward and mostly removes special code for such types.
But there is certainly some residual risk that there are unexpected
consequences. There is also some minor semantic change, i.e. see
gcc.dg/gnu-zero-array.c, where the two types would be incompatible
(and this also caused two types to be generated in the ctf-array-2.c
test), but the new behavior seems more correct to me and is also what
clang does.
The explicit language test in gimple-array-bounds.cc seems unfortunate,
but preserves the existing differences in behavior for C vs C++ for
the code. This now just becomes more obvious. I did not have time to
look at this in more detail, but I hope this can be cleaned up in
the future.
Bootstrapped and regression tested on x86_64.
Change the representation of zero-sized array to [0, -1] as in the
the C++ FE. Special cases can then be removed for ubsan, and the error
message for ubsan is changed [*] to the more correct [0]. The patch
avoids regressions for -Wzero-size-arrays in gimple-array-bounds.cc
by removing the upper bound for such arrays for C. Unfortunately,
doing this unconditionally (also for C++) would cause regressions in
the other direction, so the existing discrepancies between C and C++
for this warning code are not yet resolved.
gcc/c-family/
* c-attribs.cc (build_attr_access_from_parms): Adapt.
* c-ubsan.cc (ubsan_instrument_bounds): Remove special code.
gcc/c/
* c-decl.cc (zero_length_array_type_p): Adapt.
* (grokdeclarator): Remove special code.
(c_build_array_type_zero_size): Adapt.
gcc/
* gimple-array-bounds.cc (array_bounds_checker::check_array_ref):
Set upper bounds to zero for zero-sized C arrays.
gcc/testsuite/
* gcc.dg/debug/ctf/ctf-array-2.c: Types are now identical.
* gcc.dg/ubsan/bounds-4.c: Adapt.
* gcc.dg/ubsan/bounds-4b.c: Adapt.
* gcc.dg/ubsan/bounds-4b.c: Adapt.
* gcc.dg/ubsan/bounds-4c.c: Adapt.
* gcc.dg/ubsan/bounds-4d.c: Adapt.
* gcc.dg/gnu-zero-size.c: New test.
diff --git a/gcc/c-family/c-attribs.cc b/gcc/c-family/c-attribs.cc
index d668ab96630..4a8a4ea8c74 100644
--- a/gcc/c-family/c-attribs.cc
+++ b/gcc/c-family/c-attribs.cc
@@ -6112,7 +6112,9 @@ build_attr_access_from_parms (tree parms, bool
skip_voidptr)
if (mval && TREE_CODE (mval) == INTEGER_CST)
{
char buf[40];
- unsigned HOST_WIDE_INT n = tree_to_uhwi (mval) + 1;
+ unsigned HOST_WIDE_INT n = 0;
+ if (!integer_all_onesp (mval))
+ n = tree_to_uhwi (mval) + 1;
sprintf (buf, HOST_WIDE_INT_PRINT_UNSIGNED, n);
spec += buf;
}
diff --git a/gcc/c-family/c-ubsan.cc b/gcc/c-family/c-ubsan.cc
index c70d4781bcf..1e21982ce7e 100644
--- a/gcc/c-family/c-ubsan.cc
+++ b/gcc/c-family/c-ubsan.cc
@@ -434,13 +434,7 @@ ubsan_instrument_bounds (location_t loc, tree array, tree
*index,
tree bound = TYPE_MAX_VALUE (domain);
if (!bound)
{
- /* Handle C [0] arrays, which have TYPE_MAX_VALUE NULL, like
- C++ [0] arrays which have TYPE_MIN_VALUE 0 TYPE_MAX_VALUE -1. */
- if (!c_dialect_cxx ()
- && COMPLETE_TYPE_P (type)
- && integer_zerop (TYPE_SIZE (type)))
- bound = build_int_cst (TREE_TYPE (TYPE_MIN_VALUE (domain)), -1);
- else if (INDIRECT_REF_P (array)
+ if (INDIRECT_REF_P (array)
&& is_access_with_size_p ((TREE_OPERAND (array, 0))))
{
bound = get_bound_from_access_with_size ((TREE_OPERAND (array, 0)));
@@ -486,26 +480,17 @@ ubsan_instrument_bounds (location_t loc, tree array, tree
*index,
if (TYPE_DOMAIN (type2) != NULL_TREE)
{
tree max = TYPE_MAX_VALUE (TYPE_DOMAIN (type2));
- if (max == NULL_TREE)
+ if (TREE_CODE (max) == INTEGER_CST)
{
- /* C [0] */
- if (COMPLETE_TYPE_P (type2)
- && integer_zerop (TYPE_SIZE (type2))
- && l == 3)
- next = TREE_OPERAND (cref, 1);
- }
- else if (TREE_CODE (max) == INTEGER_CST)
- {
- if (c_dialect_cxx ()
- && integer_all_onesp (max))
+ if (integer_all_onesp (max))
{
- /* C++ [0] */
+ /* [0] */
if (l == 3)
next = TREE_OPERAND (cref, 1);
}
else if (integer_zerop (max))
{
- /* C/C++ [1] */
+ /* [1] */
if (l >= 2)
next = TREE_OPERAND (cref, 1);
}
diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 42d35a87a17..db8d6904584 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -5542,9 +5542,8 @@ zero_length_array_type_p (const_tree type)
{
if (TREE_CODE (type) == ARRAY_TYPE
&& COMPLETE_TYPE_P (type)
- && TYPE_DOMAIN (type) != NULL_TREE
- && (TYPE_MAX_VALUE (TYPE_DOMAIN (type)) == NULL_TREE
- || integer_all_onesp (TYPE_MAX_VALUE (TYPE_DOMAIN (type)))))
+ && integer_zerop (TYPE_SIZE (type))
+ && integer_all_onesp (TYPE_MAX_VALUE (TYPE_DOMAIN (type))))
return true;
return false;
}
@@ -7467,15 +7466,7 @@ grokdeclarator (const struct c_declarator *declarator,
}
}
- if (integer_zerop (size) && !this_size_varies)
- {
- /* A zero-length array cannot be represented with
- an unsigned index type, which is what we'll
- get with build_index_type. Create an
- open-ended range instead. */
- itype = build_index_type (NULL_TREE);
- }
- else
+ if (!integer_zerop (size) || this_size_varies)
{
/* Arrange for the SAVE_EXPR on the inside of the
MINUS_EXPR, which allows the -1 to get folded
@@ -7549,7 +7540,8 @@ grokdeclarator (const struct c_declarator *declarator,
"support flexible array members");
/* ISO C99 Flexible array members are effectively
- identical to GCC's zero-length array extension. */
+ similar to GCC's zero-length array extension,
+ but encoded with an empty upper bound. */
if (flexible_array_member)
itype = build_index_type (NULL_TREE);
}
@@ -7578,9 +7570,7 @@ grokdeclarator (const struct c_declarator *declarator,
/* When itype is NULL, a shared incomplete array type is
returned for all array of a given type. Elsewhere we
make sure we don't complete that type before copying
- it, but here we want to make sure we don't ever
- modify the shared type, so we gcc_assert (itype)
- below. */
+ it. */
{
addr_space_t as = DECODE_QUAL_ADDR_SPACE (type_quals);
if (!ADDR_SPACE_GENERIC_P (as) && as != TYPE_ADDR_SPACE (type))
diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index 5199a352ecc..928f90ba086 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -542,15 +542,9 @@ c_build_array_type_unspecified (tree type)
tree
c_build_array_type_zero_size (tree type)
{
- /* The GCC extension for zero-length arrays differs from
- ISO flexible array members in that sizeof yields
- zero. */
- type = c_build_array_type (type, build_index_type (NULL_TREE));
- type = build_distinct_type_copy (TYPE_MAIN_VARIANT (type));
- TYPE_SIZE (type) = bitsize_zero_node;
- TYPE_SIZE_UNIT (type) = size_zero_node;
- SET_TYPE_STRUCTURAL_EQUALITY (type);
- return type;
+ return c_build_array_type (type, build_range_type (ssizetype,
+ ssize_int (0),
+ ssize_int (-1)));
}
tree
diff --git a/gcc/gimple-array-bounds.cc b/gcc/gimple-array-bounds.cc
index 4038b4030c4..58a7e27fd72 100644
--- a/gcc/gimple-array-bounds.cc
+++ b/gcc/gimple-array-bounds.cc
@@ -41,6 +41,7 @@ along with GCC; see the file COPYING3. If not see
#include "attribs.h"
#include "tree-pass.h"
#include "gimple-range.h"
+#include "langhooks.h"
// Always use the current range query for the bounds checker.
array_bounds_checker::array_bounds_checker (struct function *func)
@@ -353,6 +354,15 @@ array_bounds_checker::check_array_ref (location_t
location, tree ref,
tree up_bound = array_ref_up_bound (ref);
tree up_bound_p1 = NULL_TREE;
+ /* FIXME: The C FE used to represent zero-length arrays as arrays without
+ upper bound. To avoid regressions where -Wzero-length-bounds would then
+ become a -Warray-bound warning, remove the bound here. Unfortunately,
+ also doing this for C++ causes regressions where -Warray-bounds become
+ -Wzero-length-bounds. */
+ if (up_bound != NULL_TREE && integer_all_onesp (up_bound)
+ && !lang_GNU_CXX ())
+ up_bound = NULL_TREE;
+
/* Referenced decl if one can be determined. */
tree decl = NULL_TREE;
diff --git a/gcc/testsuite/gcc.dg/debug/ctf/ctf-array-2.c
b/gcc/testsuite/gcc.dg/debug/ctf/ctf-array-2.c
index 8bceb7a8377..7b83b802d83 100644
--- a/gcc/testsuite/gcc.dg/debug/ctf/ctf-array-2.c
+++ b/gcc/testsuite/gcc.dg/debug/ctf/ctf-array-2.c
@@ -21,9 +21,8 @@
/* { dg-do compile } */
/* { dg-options "-O0 -gctf -dA" } */
-/* { dg-final { scan-assembler-times "0x12000000\[\t \]+\[^\n\]*ctt_info" 2 }
} */
-
-/* { dg-final { scan-assembler-times "\[\t \]0\[\t \]+\[^\n\]*cta_nelems" 2 }
} */
+/* { dg-final { scan-assembler-times "0x12000000\[\t \]+\[^\n\]*ctt_info" 1 }
} */
+/* { dg-final { scan-assembler-times "\[\t \]0\[\t \]+\[^\n\]*cta_nelems" 1 }
} */
static int b1[] = {};
diff --git a/gcc/testsuite/gcc.dg/gnu-zero-array.c
b/gcc/testsuite/gcc.dg/gnu-zero-array.c
new file mode 100644
index 00000000000..4481abf5b9a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/gnu-zero-array.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-Wall -std=gnu23" } */
+
+int a[] = { };
+int b[0];
+
+// should be compatible types
+extern typeof(a) *p;
+extern typeof(b) *p;
+
diff --git a/gcc/testsuite/gcc.dg/ubsan/bounds-4.c
b/gcc/testsuite/gcc.dg/ubsan/bounds-4.c
index d1580d36d13..0c5292de8e1 100644
--- a/gcc/testsuite/gcc.dg/ubsan/bounds-4.c
+++ b/gcc/testsuite/gcc.dg/ubsan/bounds-4.c
@@ -2,7 +2,7 @@
/* { dg-do run } */
/* { dg-options "-fsanitize=bounds -fsanitize-recover=bounds" } */
/* { dg-output "index 15 out of bounds for type 'int
\\\[15\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*index 0 out of bounds for type 'int
\\\[\\\*\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*index 0 out of bounds for type 'int
\\\[0\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*index 16 out of bounds for type 'int \\\[15\\\]'" } */
struct A { int a; int b[]; };
diff --git a/gcc/testsuite/gcc.dg/ubsan/bounds-4a.c
b/gcc/testsuite/gcc.dg/ubsan/bounds-4a.c
index 412e5fd0445..b245b143064 100644
--- a/gcc/testsuite/gcc.dg/ubsan/bounds-4a.c
+++ b/gcc/testsuite/gcc.dg/ubsan/bounds-4a.c
@@ -2,7 +2,7 @@
/* { dg-do run } */
/* { dg-options "-fsanitize=bounds -fsanitize-recover=bounds
-fstrict-flex-arrays=0" } */
/* { dg-output "index 15 out of bounds for type 'int
\\\[15\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*index 0 out of bounds for type 'int
\\\[\\\*\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*index 0 out of bounds for type 'int
\\\[0\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*index 16 out of bounds for type 'int \\\[15\\\]'" } */
#include "bounds-4.c"
diff --git a/gcc/testsuite/gcc.dg/ubsan/bounds-4b.c
b/gcc/testsuite/gcc.dg/ubsan/bounds-4b.c
index 3ca4106c10b..e77f3987af2 100644
--- a/gcc/testsuite/gcc.dg/ubsan/bounds-4b.c
+++ b/gcc/testsuite/gcc.dg/ubsan/bounds-4b.c
@@ -3,7 +3,7 @@
/* { dg-options "-fsanitize=bounds -fsanitize-recover=bounds
-fstrict-flex-arrays=1" } */
/* { dg-output "index 15 out of bounds for type 'int
\\\[15\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*index 2 out of bounds for type 'int
\\\[2\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*index 0 out of bounds for type 'int
\\\[\\\*\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*index 0 out of bounds for type 'int
\\\[0\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*index 16 out of bounds for type 'int \\\[15\\\]'" } */
#include "bounds-4.c"
diff --git a/gcc/testsuite/gcc.dg/ubsan/bounds-4c.c
b/gcc/testsuite/gcc.dg/ubsan/bounds-4c.c
index 8f846d60011..5a770c9aede 100644
--- a/gcc/testsuite/gcc.dg/ubsan/bounds-4c.c
+++ b/gcc/testsuite/gcc.dg/ubsan/bounds-4c.c
@@ -4,7 +4,7 @@
/* { dg-output "index 15 out of bounds for type 'int
\\\[15\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*index 1 out of bounds for type 'int
\\\[1\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*index 2 out of bounds for type 'int
\\\[2\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*index 0 out of bounds for type 'int
\\\[\\\*\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*index 0 out of bounds for type 'int
\\\[0\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*index 16 out of bounds for type 'int \\\[15\\\]'" } */
#include "bounds-4.c"
diff --git a/gcc/testsuite/gcc.dg/ubsan/bounds-4d.c
b/gcc/testsuite/gcc.dg/ubsan/bounds-4d.c
index b2d979fe8c1..d25cbd6c7bf 100644
--- a/gcc/testsuite/gcc.dg/ubsan/bounds-4d.c
+++ b/gcc/testsuite/gcc.dg/ubsan/bounds-4d.c
@@ -2,10 +2,10 @@
/* { dg-do run } */
/* { dg-options "-fsanitize=bounds -fsanitize-recover=bounds
-fstrict-flex-arrays=3" } */
/* { dg-output "index 15 out of bounds for type 'int
\\\[15\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*index 0 out of bounds for type 'int
\\\[\\\*\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*index 0 out of bounds for type 'int
\\\[0\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*index 1 out of bounds for type 'int
\\\[1\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*index 2 out of bounds for type 'int
\\\[2\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*index 0 out of bounds for type 'int
\\\[\\\*\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*index 0 out of bounds for type 'int
\\\[0\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
/* { dg-output "\[^\n\r]*index 16 out of bounds for type 'int \\\[15\\\]'" } */
#include "bounds-4.c"