Hi! v6:
- Note that support for 0-length arrays is slightly broken.
- Improve readability of is_top_array_vla(), without changing behavior.
- Doc: Clarify that both types and expressions are accepted, and
provide an example. [Joseph]
- Doc: Wording improvements. [Joseph, Jens]
- Tests: [Joseph, Martin]
- Remove unnecessary assignments where we're just interested in
the __lengthof__ expression.
- Add tests for arrays whose length is implicit: [] = {...}
- Add tests for 0-length arrays.
- Add tests for non-arrays.
- Add tests for undefined symbols.
- Add tests for the version without parentheses.
- Test whether some expressions are constant or variable.
- Use static_assert(3) instead of assert(3) where possible.
- CC: Add an LLVM developer: Timm.
Below is a range-diff against v5.
I've tested for regressions, and it seems there aren't (x86_64).
I've also replaced sizeof divisions in the C testsuite by __lengthof__,
to get broader testing, and it also worked well (those changes are not
included in this patch).
I've seen some internal compiler errors while running `make -j24 check`
that I haven't been able to reproduce consistently. However, they are
in parts of the repository that are unrelated to my changes, so I
suspect those are problems that existed before my patches. (I've
reported the ICE in an earlier subthread of this thread.)
Have a lovely day!
Alex
Alejandro Colomar (3):
gcc/: Rename array_type_nelts() => array_type_nelts_minus_one()
Merge definitions of array_type_nelts_top()
c: Add __lengthof__ operator
gcc/c-family/c-common.cc | 26 ++++
gcc/c-family/c-common.def | 3 +
gcc/c-family/c-common.h | 2 +
gcc/c/c-decl.cc | 30 +++--
gcc/c/c-fold.cc | 7 +-
gcc/c/c-parser.cc | 61 +++++++---
gcc/c/c-tree.h | 4 +
gcc/c/c-typeck.cc | 118 ++++++++++++++++++-
gcc/config/aarch64/aarch64.cc | 2 +-
gcc/config/i386/i386.cc | 2 +-
gcc/cp/cp-tree.h | 1 -
gcc/cp/decl.cc | 2 +-
gcc/cp/init.cc | 8 +-
gcc/cp/lambda.cc | 3 +-
gcc/cp/operators.def | 1 +
gcc/cp/tree.cc | 13 --
gcc/doc/extend.texi | 31 +++++
gcc/expr.cc | 8 +-
gcc/fortran/trans-array.cc | 2 +-
gcc/fortran/trans-openmp.cc | 4 +-
gcc/rust/backend/rust-tree.cc | 13 --
gcc/rust/backend/rust-tree.h | 2 -
gcc/target.h | 3 +
gcc/testsuite/gcc.dg/lengthof-compile.c | 115 ++++++++++++++++++
gcc/testsuite/gcc.dg/lengthof-vla.c | 46 ++++++++
gcc/testsuite/gcc.dg/lengthof.c | 150 ++++++++++++++++++++++++
gcc/tree.cc | 17 ++-
gcc/tree.h | 3 +-
28 files changed, 598 insertions(+), 79 deletions(-)
create mode 100644 gcc/testsuite/gcc.dg/lengthof-compile.c
create mode 100644 gcc/testsuite/gcc.dg/lengthof-vla.c
create mode 100644 gcc/testsuite/gcc.dg/lengthof.c
Range-diff against v5:
1: 73010cb4af6 = 1: 8b68e250503 gcc/: Rename array_type_nelts() =>
array_type_nelts_minus_one()
2: 9b835478721 = 2: 21433097103 Merge definitions of array_type_nelts_top()
3: af05d01e68d ! 3: 71fd2013967 c: Add __lengthof__ operator
@@ Commit message
FUTURE DIRECTIONS:
- We could make it work with array parameters to functions, and
- somehow magically return the length designator of the array,
- regardless of it being really a pointer.
+ - We should make it work with array parameters to functions,
+ and somehow magically return the length designator of the array,
+ regardless of it being really a pointer.
+
+ - Fix support for [0].
Cc: Joseph Myers <[email protected]>
Cc: Gabriel Ravier <[email protected]>
@@ Commit message
Cc: David Brown <[email protected]>
Cc: Florian Weimer <[email protected]>
Cc: Andreas Schwab <[email protected]>
+ Cc: Timm Baeder <[email protected]>
gcc/ChangeLog:
@@ Commit message
gcc/testsuite/ChangeLog:
* gcc.dg/lengthof-compile.c:
+ * gcc.dg/lengthof-vla.c:
* gcc.dg/lengthof.c: Add tests for __lengthof__ operator.
Link: https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2529.pdf
@@ gcc/c/c-typeck.cc: c_expr_sizeof_type (location_t loc, struct
c_type_name *t)
+static bool
+is_top_array_vla (tree type)
+{
-+ bool zero, var;
++ bool zero, star, var;
+ tree d;
+
+ if (TREE_CODE (type) != ARRAY_TYPE)
@@ gcc/c/c-typeck.cc: c_expr_sizeof_type (location_t loc, struct
c_type_name *t)
+
+ d = TYPE_DOMAIN (type);
+ zero = !TYPE_MAX_VALUE (d);
-+ var = (!zero
-+ && (TREE_CODE (TYPE_MIN_VALUE (d)) != INTEGER_CST
-+ || TREE_CODE (TYPE_MAX_VALUE (d)) != INTEGER_CST));
-+ var = var || (zero && C_TYPE_VARIABLE_SIZE (type));
++ star = (zero && C_TYPE_VARIABLE_SIZE (type));
++ if (star)
++ return true;
++ if (zero)
++ return false;
++
++ var = (TREE_CODE (TYPE_MIN_VALUE (d)) != INTEGER_CST
++ || TREE_CODE (TYPE_MAX_VALUE (d)) != INTEGER_CST);
+ return var;
+}
+
@@ gcc/doc/extend.texi: If the operand of the @code{__alignof__} expression
is a fu
+
+The keyword @code{__lengthof__} determines the length of an array operand,
+that is, the number of elements in the array.
-+Its syntax is just like @code{sizeof}.
-+The operand must be a complete array type.
++Its syntax is similar to @code{sizeof}.
++The operand must be a complete array type or an expression of that type.
++For example:
++
++@smallexample
++int a[n];
++__lengthof__ (a); // returns n
++__lengthof__ (int [7][3]); // returns 7
++@end smallexample
++
+The operand is not evaluated
+if the top-level length designator is an integer constant expression
-+(in this case, the operator results in a constant expression);
++(in this case, the operator results in an integer constant expression);
+and it is evaluated
+if the top-level length designator is not an integer constant expression
+(in this case, the operator results in a run-time value).
+For example:
+
+@smallexample
-+__lengthof__ (int [7][n++]); // constexpr
-+__lengthof__ (int [n++][7]); // run-time value
++__lengthof__ (int [7][n++]); // integer constant expression
++__lengthof__ (int [n++][7]); // run-time value; n++ is evaluated
+@end smallexample
+
@node Inline
@@ gcc/testsuite/gcc.dg/lengthof-compile.c (new)
+
+extern int x[];
+
++static int w[] = {1, 2, 3};
++
++static int z[0];
++static int y[__lengthof__(z)];
++
++void
++automatic(void)
++{
++ __lengthof__ (w);
++}
++
+void
+incomplete (int p[])
+{
-+ unsigned n;
-+
-+ n = __lengthof__ (x); /* { dg-error "incomplete" } */
++ __lengthof__ (x); /* { dg-error "incomplete" } */
+
+ /* We want to support the following one in the future,
+ but for now it should fail. */
-+ n = __lengthof__ (p); /* { dg-error "invalid" } */
++ __lengthof__ (p); /* { dg-error "invalid" } */
+}
+
+void
@@ gcc/testsuite/gcc.dg/lengthof-compile.c (new)
+ int x;
+ int fam[];
+ } s;
-+ unsigned n;
+
-+ n = __lengthof__ (s.fam); /* { dg-error "incomplete" } */
++ __lengthof__ (s.fam); /* { dg-error "incomplete" } */
+}
+
+void fix_fix (int i, char (*a)[3][5], int (*x)[__lengthof__ (*a)]);
@@ gcc/testsuite/gcc.dg/lengthof-compile.c (new)
+ fix_uns (5, &c35, &i3);
+ fix_uns (5, &c35, &i5); /* { dg-error "incompatible-pointer-types" } */
+}
++
++void
++non_arr(void)
++{
++ int x;
++ int *p;
++ struct s {
++ int x[3];
++ } s;
++
++ __lengthof__ (x); /* { dg-error "invalid" } */
++ __lengthof__ (int); /* { dg-error "invalid" } */
++ __lengthof__ (s); /* { dg-error "invalid" } */
++ __lengthof__ (struct s); /* { dg-error "invalid" } */
++ __lengthof__ (&x); /* { dg-error "invalid" } */
++ __lengthof__ (p); /* { dg-error "invalid" } */
++ __lengthof__ (int *); /* { dg-error "invalid" } */
++ __lengthof__ (&s.x); /* { dg-error "invalid" } */
++ __lengthof__ (int (*)[3]); /* { dg-error "invalid" } */
++}
++
++static int f1();
++static int f2(); /* { dg-warning "never defined" } */
++int a[10][10];
++int n;
++
++void
++syms(void)
++{
++ int b[n][n];
++
++ __lengthof__ (a[f1()]);
++ __lengthof__ (b[f2()]);
++}
++
++void
++no_parens(void)
++{
++ __lengthof__ a;
++ __lengthof__ *a;
++ __lengthof__ (int [3]) {};
++
++ __lengthof__ int [3]; /* { dg-error "expected expression before" } */
++}
++
++void
++const_expr(void)
++{
++ int n = 7;
++
++ _Static_assert (__lengthof__ (int [3][n]) == 3);
++ _Static_assert (__lengthof__ (int [n][3]) == 7); /* { dg-error "not
constant"} */
++ _Static_assert (__lengthof__ (int [0][3]) == 0);
++ _Static_assert (__lengthof__ (int [0]) == 0);
++
++ /* FIXME: lengthog(int [0][n]) should result in a constant expression.
*/
++ _Static_assert (__lengthof__ (int [0][n]) == 0); /* { dg-error "not
constant"} */
++}
+
+ ## gcc/testsuite/gcc.dg/lengthof-vla.c (new) ##
+@@
++/* { dg-do compile } */
++/* { dg-options "-Wno-pedantic -Wvla-parameter" } */
++
++void fix_fix (int i,
++ char (*a)[3][5],
++ int (*x)[__lengthof__ (*a)]);
++void fix_var (int i,
++ char (*a)[3][i], /* dg-warn "variable" */
++ int (*x)[__lengthof__ (*a)]);
++void fix_uns (int i,
++ char (*a)[3][*],
++ int (*x)[__lengthof__ (*a)]);
++
++void zro_fix (int i,
++ char (*a)[0][5],
++ int (*x)[__lengthof__ (*a)]);
++void zro_var (int i,
++ char (*a)[0][i], /* dg-warn "variable" */
++ int (*x)[__lengthof__ (*a)]);
++void zro_uns (int i,
++ char (*a)[0][*],
++ int (*x)[__lengthof__ (*a)]);
++
++void var_fix (int i,
++ char (*a)[i][5], /* dg-warn "variable" */
++ int (*x)[__lengthof__ (*a)]); /* dg-warn "variable" */
++void var_var (int i,
++ char (*a)[i][i], /* dg-warn "variable" */
++ int (*x)[__lengthof__ (*a)]); /* dg-warn "variable" */
++void var_uns (int i,
++ char (*a)[i][*], /* dg-warn "variable" */
++ int (*x)[__lengthof__ (*a)]); /* dg-warn "variable" */
++
++void uns_fix (int i,
++ char (*a)[*][5],
++ int (*x)[__lengthof__ (*a)]);
++void uns_var (int i,
++ char (*a)[*][i], /* dg-warn "variable" */
++ int (*x)[__lengthof__ (*a)]);
++void uns_uns (int i,
++ char (*a)[*][*],
++ int (*x)[__lengthof__ (*a)]);
++
++// Can't test due to bug:
<https://gcc.gnu.org/bugzilla/show_bug.cgi?id=116284>
++//static int z2[0];
++//static int y2[__lengthof__(z2)];
## gcc/testsuite/gcc.dg/lengthof.c (new) ##
@@
@@ gcc/testsuite/gcc.dg/lengthof.c (new)
+{
+ short a[7];
+
-+ assert (__lengthof__ (a) == 7);
-+ assert (__lengthof__ (long [0]) == 0);
-+ assert (__lengthof__ (unsigned [99]) == 99);
++ static_assert (__lengthof__ (a) == 7);
++ static_assert (__lengthof__ (long [0]) == 0);
++ static_assert (__lengthof__ (unsigned [99]) == 99);
++}
++
++void
++automatic(void)
++{
++ int a[] = {1, 2, 3};
++ int z[] = {};
++
++ static_assert (__lengthof__ (a) == 3);
++ static_assert (__lengthof__ (z) == 0);
+}
+
+void
@@ gcc/testsuite/gcc.dg/lengthof.c (new)
+ int a[8];
+ } s;
+
-+ assert (__lengthof__ (s.a) == 8);
++ static_assert (__lengthof__ (s.a) == 8);
+}
+
+void
@@ gcc/testsuite/gcc.dg/lengthof.c (new)
+ int i;
+
+ i = 3;
-+ assert (__lengthof__ (struct {int x[i++];}[3]) == 3);
++ static_assert (__lengthof__ (struct {int x[i++];}[3]) == 3);
+ assert (i == 3);
+}
+
@@ gcc/testsuite/gcc.dg/lengthof.c (new)
+ long (*p)[__lengthof__ (a)];
+
+ p = &a;
-+ assert (__lengthof__ (*p++) == 5);
++ static_assert (__lengthof__ (*p++) == 5);
+ assert (p == &a);
+}
+
@@ gcc/testsuite/gcc.dg/lengthof.c (new)
+{
+ int i;
+
-+ assert (__lengthof__ (int [0][4]) == 0);
++ static_assert (__lengthof__ (int [0][4]) == 0);
+ i = 3;
+ assert (__lengthof__ (int [0][i]) == 0);
+}
@@ gcc/testsuite/gcc.dg/lengthof.c (new)
+{
+ int i;
+
-+ assert (__lengthof__ (int [7][4]) == 7);
++ static_assert (__lengthof__ (int [7][4]) == 7);
+ i = 3;
-+ assert (__lengthof__ (int [7][i]) == 7);
++ static_assert (__lengthof__ (int [7][i]) == 7);
+}
+
+void
@@ gcc/testsuite/gcc.dg/lengthof.c (new)
+ assert (i == 9 + 1);
+}
+
++void
++no_parens(void)
++{
++ int n = 3;
++ int a[7];
++ int v[n];
++
++ static_assert (__lengthof__ a == 7);
++ assert (__lengthof__ v == 3);
++}
++
+int
+main (void)
+{
+ array ();
++ automatic ();
+ vla ();
+ member ();
+ vla_eval ();
@@ gcc/testsuite/gcc.dg/lengthof.c (new)
+ matrix_zero ();
+ matrix_fixed ();
+ matrix_vla ();
++ no_parens ();
+}
--
2.45.2
signature.asc
Description: PGP signature
