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 <josmy...@redhat.com> Cc: Gabriel Ravier <gabrav...@gmail.com> @@ Commit message Cc: David Brown <david.br...@hesbynett.no> Cc: Florian Weimer <fwei...@redhat.com> Cc: Andreas Schwab <sch...@linux-m68k.org> + Cc: Timm Baeder <tbae...@redhat.com> 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