On Tue, Aug 06, 2024 at 02:22:38PM GMT, Alejandro Colomar wrote: > Hi! > > v4: > > - Only evaluate the operand if the top array is VLA. Inner VLAs are > ignored. [Joseph, Martin] > This proved very useful for compile-time diagnostics, since we have > more cases that are constant expressions. > - Document the evaluation rules, which are unique to this operator > (similar to sizeof, but we ignore inner VLAs). > - Add tests to the testsuite. [Joseph] > - Swap diagnostic cases preference, to give more meaningful > diagnostics. [Martin] > - Document that Xavier was the first one to suggest this feature, and > provide a link to the mail thread where that happened. > BTW, while reading that discussion from 2 years ago, I see that it
Self-correction: s/2/4/ > was questioned the value of this operator. Below is a rationale to > defend it. > - Document that Martin's help has been crucial for implementing this, > with 'Co-developed-by'. Would you mind confirming that I can use > that tag? > - CC += Kees, Qing, Jens > > Rationale: > > - While compiler extensions already allow implementing ARRAY_SIZE() > (<https://stackoverflow.com/a/57537491/6872717>), there's still no > way to get the length of a function parameter which uses array > notation. While this first implementation doesn't support those yet > (because there are some issues that need to be fixed first), the plan > is to add support to those. This would be a huge step towards arrays > being first-class citizens in C. In those cases, it would reduce the > chance of programmer errors. See for example > <https://lkml.org/lkml/2015/9/3/428>. That entire class of bugs > would be over, _and_ programs would become simpler. > > Some specific questions or concerns: > > - The tests seem to work as expected if I compile them manually, and > run (the one that should be run) as a normal program. The one that > should not be run also gives the expected diagnostics. > Can anyone give advice of why it's not running well under the test > suite? > > - I don't like the fact that [*][n] is internally implemented exactly > like [0][n], which makes them indistinguishable. All other cases of > [0] return a constent expression of value 0, but [0][n] must return a > variable 0, to keep support for [*][n]. > Could you please change the way [*][n] (and thus [*]) is represented > internally so that it can be differentiated from [0]? > Do you have in mind any other way that would be a viable > implementation of [*] that would allow distinguishing [0][n] and > [*][n]? Maybe making it to have one node instead of zero and mark > that node specially? > > At the bottom of this email is a range-diff against v3. > > And below is a test program I used while developing the feature. It is > quite similar to what's on the test suite (patch 4/4), since those are > based on this one. > > It has comments where I'd like more diagnostics, but those are not > responsibility of this feature. Some are fault of the representation > for [*], and others are already being worked on by Martin. There are > also comments on code that causes compile-time errors as expected > (wanted). Some assertions about evaluation of the operand are commented > out because due to the problems with [*][n] and [0][n] we have more > evaluation than I'd like. However, those are only with [0], which is > not yet well supported by GCC, so we don't need to worry much for now. > > The program below also compares with sizeof and alignof, which the > test-suite tests do not. > > Have a lovely day! > Alex > > $ cat len.c > #include <stdalign.h> > #include <stdio.h> > #include <assert.h> > > > #define memberof(T, member) \ > ( \ > (T){}.member \ > ) > > > struct s { > int x; > int y[8]; > int z[]; > }; > > > struct s2 { > int x; > int z[] __attribute__((counted_by(x))); > }; > > > extern int x[]; > > > void array(void); > void incomplete_err(int inc[]); > void unspecified_err(void); > void vla(void); > void member_array(void); > void fam_err(void); > void vla_eval(void); > void in_vla_noeval(void); > void in_vla_noeval2(void); > void array_noeval(void); > void vla_eval2(void); > void matrix_0(void); > void matrix_fixed(void); > void matrix_vla(void); > void f_fixed(void); > void f_zero(void); > void f_vla(void); > void f_star(void); > > > int > main(int argc, char *argv[argc + 1]) > { > (void) argv; > > // Wishlist: > //n = lengthof(argv); > //printf("lengthof(argv) == %zu\n", n); > > array(); > incomplete_err(&argc); > unspecified_err(); > vla(); > member_array(); > fam_err(); > vla_eval(); > in_vla_noeval(); > in_vla_noeval2(); > array_noeval(); > vla_eval2(); > matrix_0(); > matrix_fixed(); > matrix_vla(); > f_fixed(); > f_zero(); > f_vla(); > f_star(); > } > > void > array(void) > { > short a[42]; > size_t n; > > puts(""); > > n = __lengthof__(a); > printf("lengthof(a):\t\t %zu\n", n); > assert(n == 42); > > n = __lengthof__(long [0]); > printf("lengthof(long [0]):\t %zu\n", n); > assert(n == 0); > > n = __lengthof__(long [99]); > printf("lengthof(long [99]):\t %zu\n", n); > assert(n == 99); > } > > void > incomplete_err(int inc[]) > { > //size_t n; > > puts(""); > > // error: invalid application of ‘lengthof’ to incomplete type > ‘int[]’ > //n = lengthof(x); > //printf("lengthof(x):\t %zu\n", n); > > // error: > //n = lengthof(inc); > //printf("lengthof(inc):\t %zu\n", n); > } > > void > unspecified_err(void) > { > puts(""); > > // error: > //n = lengthof(int [*]); > //printf("lengthof(int [*])\t %zu\n", n); > } > > void > vla(void) > { > size_t n; > > n = 99; > puts(""); > > n = __lengthof__(short [n - 10]); > printf("lengthof(short [n - 10]):\t %zu\n", n); > assert(n == 89); > > int v[n / 2]; > n = __lengthof__(v); > printf("lengthof(v):\t %zu\n", n); > assert(n == 89 / 2); > > n = 0; > int z[n]; > n = __lengthof__(z); > printf("lengthof(z):\t %zu\n", n); > assert(n == 0); > } > > void > member_array(void) > { > size_t n; > > puts(""); > > n = __lengthof__(memberof(struct s, y)); > printf("lengthof(memberof(struct s, y)):\t %zu\n", n); > assert(n == 8); > } > > void > fam_err(void) > { > size_t n; > > puts(""); > > // error: > //n = lengthof(memberof(struct s, z)); > //printf("lengthof(memberof(struct s, z)):\t %zu\n", n); > > // error: > //n = sizeof(memberof(struct s, z)); > //printf("sizeof(memberof(struct s, z)):\t %zu\n", n); > > n = alignof(memberof(struct s, z)); > printf("alignof(memberof(struct s, z)):\t %zu\n", n); > } > > void > vla_eval(void) > { > int i; > size_t n; > > puts(""); > > i = 4; > n = __lengthof__(struct {int x;}[i++]); > printf("lengthof(struct {int x;}[i++]):\t %zu; i: %d\n", n, i); > assert(i == 5); > assert(n == 4); > > i = 4; > n = sizeof(struct {int x;}[i++]); > printf("sizeof(struct {int x;}[i++]):\t %zu; i: %d\n", n, i); > assert(i == 5); > > i = 4; > n = alignof(struct {int x;}[i++]); > printf("alignof(struct {int x;}[i++]):\t %zu; i: %d\n", n, i); > assert(i == 4); > } > > void > in_vla_noeval(void) > { > int i; > size_t n; > > puts(""); > > i = 4; > n = __lengthof__(struct {int x[i++];}[3]); > printf("lengthof(struct {int x[i++];}[3]):\t %zu; i: %d\n", n, > i); > assert(i == 4); > assert(n == 3); > > i = 4; > n = sizeof(struct {int x[i++];}[3]); > printf("sizeof(struct {int x[i++];}[3]):\t %zu; i: %d\n", n, i); > assert(i == 5); > > i = 4; > n = alignof(struct {int x[i++];}[3]); > printf("alignof(struct {int x[i++];}[3]):\t %zu; i: %d\n", n, > i); > assert(i == 4); > } > > void > in_vla_noeval2(void) > { > int i; > size_t n; > > puts(""); > > i = 4; > n = __lengthof__(struct {int x[(i++, 2)];}[3]); > printf("lengthof(struct {int x[(i++, 2)];}[3]):\t %zu; i: > %d\n", n, i); > assert(i == 4); > assert(n == 3); > > i = 4; > n = sizeof(struct {int x[(i++, 2)];}[3]); > printf("sizeof(struct {int x[(i++, 2)];}[3]):\t %zu; i: %d\n", > n, i); > assert(i == 5); > > i = 4; > n = alignof(struct {int x[(i++, 2)];}[3]); > printf("alignof(struct {int x[(i++, 2)];}[3]):\t %zu; i: > %d\n", n, i); > assert(i == 4); > } > > void > array_noeval(void) > { > short a[42]; > short (*p)[42]; > size_t n; > > puts(""); > > p = &a; > n = __lengthof__(*p++); > printf("lengthof(*p++):\t %zu; p: %p\n", n, p); > assert(p == &a); > assert(n == 42); > > p = &a; > n = sizeof(*p++); > printf("lengthof(*p++):\t %zu; p: %p\n", n, p); > assert(p == &a); > > p = &a; > n = alignof(*p++); > printf("alignof(*p++):\t %zu; p: %p\n", n, p); > assert(p == &a); > } > > void > vla_eval2(void) > { > size_t n; > > n = 33; > > int v[n / 2]; > int (*q)[__lengthof__(v)]; > > puts(""); > > q = &v; > n = __lengthof__(*q++); > printf("lengthof(*q++):\t %zu; q: %p\n", n, q); > assert(q - 1 == &v); > assert(n == 33 / 2); > > q = &v; > n = sizeof(*q++); > printf("lengthof(*q++):\t %zu; q: %p\n", n, q); > assert(q - 1 == &v); > > q = &v; > n = alignof(*q++); > printf("alignof(*q++):\t %zu; q: %p\n", n, q); > assert(q == &v); > } > > void > matrix_0(void) > { > int i; > size_t n; > > puts(""); > > n = __lengthof__(int [0][4]); > printf("lengthof(int [0][4]):\t %zu\n", n); > assert(n == 0); > > i = 5; > n = __lengthof__(int [0][i++]); > printf("lengthof(int [0][i++]):\t %zu; i: %d\n", n, i); > //assert(i == 5); > assert(n == 0); > > // error: ‘[*]’ not allowed in other than function prototype > scope > //n = lengthof(int [0][*]); > //printf("lengthof(int [0][*]):\t %zu\n", n); > //assert(n == 0); > } > > void > matrix_fixed(void) > { > int i; > size_t n; > > > n = __lengthof__(int [7][4]); > printf("lengthof(int [7][4]):\t %zu\n", n); > assert(n == 7); > > i = 5; > n = __lengthof__(int [7][i++]); > printf("lengthof(int [7][i++]):\t %zu; i: %d\n", n, i); > assert(i == 5); > assert(n == 7); > > // error: ‘[*]’ not allowed in other than function prototype > scope > //n = lengthof(int [7][*]); > //printf("lengthof(int [7][*]):\t %zu\n", n); > //assert(n == 7); > } > > void > matrix_vla(void) > { > int i; > size_t n; > > > i = 7; > n = __lengthof__(int [i++][4]); > printf("lengthof(int [i++][4]):\t %zu; i: %d\n", n, i); > assert(i == 8); > assert(n == 7); > > n = __lengthof__(int [i++][n]); > printf("lengthof(int [i++][n]):\t %zu; i: %d\n", n, i); > assert(i == 9); > assert(n == 8); > > // error: ‘[*]’ not allowed in other than function prototype > scope > //n = lengthof(int [i++][*]); > //printf("lengthof(int [i++][*]):\t %zu; i: %d\n", n, i); > //assert(i == 10); > //assert(n == 9); > } > > void l_fixed_1(int i, char (*a)[3][5], int (*x)[__lengthof__(*a)]); > void l_fixed_2(int i, char (*a)[3][i], int (*x)[__lengthof__(*a)]); > void l_fixed_3(int i, char (*a)[3][*], int (*x)[__lengthof__(*a)]); > > void s_fixed_1(int i, char (*a)[5][3], int (*x)[sizeof(**a)]); > void s_fixed_2(int i, char (*a)[i][3], int (*x)[sizeof(**a)]); > void s_fixed_3(int i, char (*a)[*][3], int (*x)[sizeof(**a)]); > > void > f_fixed(void) > { > int i3[3]; > int i5[5]; > char c35[3][5]; > char c53[5][3]; > > sizeof(l_fixed_1(5, &c35, &i3)); > //sizeof(l_fixed_1(5, &c35, &i5)); // > -Wincompatible-pointer-types > > sizeof(l_fixed_2(5, &c35, &i3)); > //sizeof(l_fixed_2(5, &c35, &i5)); // > -Wincompatible-pointer-types > > sizeof(l_fixed_3(5, &c35, &i3)); > //sizeof(l_fixed_3(5, &c35, &i5)); // > -Wincompatible-pointer-types > > sizeof(s_fixed_1(5, &c53, &i3)); > //sizeof(s_fixed_1(5, &c53, &i5)); // > -Wincompatible-pointer-types > > sizeof(s_fixed_2(5, &c53, &i3)); > //sizeof(s_fixed_2(5, &c53, &i5)); // > -Wincompatible-pointer-types > > sizeof(s_fixed_3(5, &c53, &i3)); > //sizeof(s_fixed_3(5, &c53, &i5)); // > -Wincompatible-pointer-types > } > > void l_zero_1(int i, char (*a)[0][5], int (*x)[__lengthof__(*a)]); > void l_zero_2(int i, char (*a)[0][i], int (*x)[__lengthof__(*a)]); > void l_zero_3(int i, char (*a)[0][*], int (*x)[__lengthof__(*a)]); > > void s_zero_1(int i, char (*a)[5][0], int (*x)[sizeof(**a)]); > void s_zero_2(int i, char (*a)[i][0], int (*x)[sizeof(**a)]); > void s_zero_3(int i, char (*a)[*][0], int (*x)[sizeof(**a)]); > > void > f_zero(void) > { > int i0[0]; > int i5[5]; > char c05[0][5]; > char c50[5][0]; > > sizeof(l_zero_1(5, &c05, &i0)); > //sizeof(l_zero_1(5, &c05, &i5)); // > -Wincompatible-pointer-types > > sizeof(l_zero_2(5, &c05, &i0)); > sizeof(l_zero_2(5, &c05, &i5)); // Wantfail > > sizeof(l_zero_3(5, &c05, &i0)); > sizeof(l_zero_3(5, &c05, &i5)); // Wantfail > > sizeof(s_zero_1(5, &c50, &i0)); > sizeof(s_zero_1(5, &c50, &i5)); // Wantfail > > sizeof(s_zero_2(5, &c50, &i0)); > sizeof(s_zero_2(5, &c50, &i5)); // Wantfail > > sizeof(s_zero_3(5, &c50, &i0)); > sizeof(s_zero_3(5, &c50, &i5)); // Wantfail > } > > void l_vla_1(int i, int j, char (*a)[i][5], int (*x)[__lengthof__(*a)]); > void l_vla_2(int i, int j, char (*a)[i][j], int (*x)[__lengthof__(*a)]); > void l_vla_3(int i, int j, char (*a)[i][*], int (*x)[__lengthof__(*a)]); > > void s_vla_1(int i, int j, char (*a)[5][j], int (*x)[sizeof(**a)]); > void s_vla_2(int i, int j, char (*a)[i][j], int (*x)[sizeof(**a)]); > void s_vla_3(int i, int j, char (*a)[*][j], int (*x)[sizeof(**a)]); > > void > f_vla(void) > { > int i3[3]; > int i5[5]; > char c35[3][5]; > char c53[5][3]; > > sizeof(l_vla_1(3, 5, &c35, &i3)); > sizeof(l_vla_1(3, 5, &c35, &i5)); // Wantwarn > > sizeof(l_vla_2(3, 5, &c35, &i3)); > sizeof(l_vla_2(3, 5, &c35, &i5)); // Wantwarn > > sizeof(l_vla_3(3, 5, &c35, &i3)); > sizeof(l_vla_3(3, 5, &c35, &i5)); // Wantwarn > > sizeof(s_vla_1(5, 3, &c53, &i3)); > sizeof(s_vla_1(5, 3, &c53, &i5)); // Wantwarn > > sizeof(s_vla_2(5, 3, &c53, &i3)); > sizeof(s_vla_2(5, 3, &c53, &i5)); // Wantwarn > > sizeof(s_vla_3(5, 3, &c53, &i3)); > sizeof(s_vla_3(5, 3, &c53, &i5)); // Wantwarn > } > > void l_star_1(int i, char (*a)[*][5], int (*x)[__lengthof__(*a)]); > void l_star_2(int i, char (*a)[*][i], int (*x)[__lengthof__(*a)]); > void l_star_3(int i, char (*a)[*][*], int (*x)[__lengthof__(*a)]); > > void s_star_1(int i, char (*a)[5][*], int (*x)[sizeof(**a)]); > void s_star_2(int i, char (*a)[i][*], int (*x)[sizeof(**a)]); > void s_star_3(int i, char (*a)[*][*], int (*x)[sizeof(**a)]); > > void > f_star(void) > { > int i3[3]; > int i5[5]; > char c35[3][5]; > char c53[5][3]; > > sizeof(l_star_1(5, &c35, &i3)); > sizeof(l_star_1(5, &c35, &i5)); // Wantwarn > > sizeof(l_star_2(5, &c35, &i3)); > sizeof(l_star_2(5, &c35, &i5)); // Wantwarn > > sizeof(l_star_3(5, &c35, &i3)); > sizeof(l_star_3(5, &c35, &i5)); // Wantwarn > > sizeof(s_star_1(5, &c53, &i3)); > sizeof(s_star_1(5, &c53, &i5)); // Wantwarn > > sizeof(s_star_2(5, &c53, &i3)); > sizeof(s_star_2(5, &c53, &i5)); // Wantwarn > > sizeof(s_star_3(5, &c53, &i3)); > sizeof(s_star_3(5, &c53, &i5)); // Wantwarn > } > > And here's how it runs: > > $ /opt/local/gnu/gcc/lengthof/bin/gcc len.c > $ ./a.out > > lengthof(a): 42 > lengthof(long [0]): 0 > lengthof(long [99]): 99 > > > > lengthof(short [n - 10]): 89 > lengthof(v): 44 > lengthof(z): 0 > > lengthof(memberof(struct s, y)): 8 > > alignof(memberof(struct s, z)): 4 > > lengthof(struct {int x;}[i++]): 4; i: 5 > sizeof(struct {int x;}[i++]): 16; i: 5 > alignof(struct {int x;}[i++]): 4; i: 4 > > lengthof(struct {int x[i++];}[3]): 3; i: 4 > sizeof(struct {int x[i++];}[3]): 48; i: 5 > alignof(struct {int x[i++];}[3]): 4; i: 4 > > lengthof(struct {int x[(i++, 2)];}[3]): 3; i: 4 > sizeof(struct {int x[(i++, 2)];}[3]): 24; i: 5 > alignof(struct {int x[(i++, 2)];}[3]): 4; i: 4 > > lengthof(*p++): 42; p: 0x7ffd18a52b30 > lengthof(*p++): 84; p: 0x7ffd18a52b30 > alignof(*p++): 2; p: 0x7ffd18a52b30 > > lengthof(*q++): 16; q: 0x7ffd18a52b60 > lengthof(*q++): 64; q: 0x7ffd18a52b60 > alignof(*q++): 4; q: 0x7ffd18a52b20 > > lengthof(int [0][4]): 0 > lengthof(int [0][i++]): 0; i: 6 > lengthof(int [7][4]): 7 > lengthof(int [7][i++]): 7; i: 5 > lengthof(int [i++][4]): 7; i: 8 > lengthof(int [i++][n]): 8; i: 9 > > > > Alejandro Colomar (4): > gcc/: Rename array_type_nelts() => array_type_nelts_minus_one() > Merge definitions of array_type_nelts_top() > c: Add __lengthof__() operator (n2529) > testsuite: Add tests for __lengthof__ > > 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 | 114 ++++++++++++++++++++- > 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 | 27 +++++ > 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 | 48 +++++++++ > gcc/testsuite/gcc.dg/lengthof.c | 126 ++++++++++++++++++++++++ > gcc/tree.cc | 17 +++- > gcc/tree.h | 3 +- > 27 files changed, 453 insertions(+), 79 deletions(-) > create mode 100644 gcc/testsuite/gcc.dg/lengthof-compile.c > create mode 100644 gcc/testsuite/gcc.dg/lengthof.c > > Range-diff against v3: > 1: 73010cb4af6 = 1: 73010cb4af6 gcc/: Rename array_type_nelts() => > array_type_nelts_minus_one() > 2: 2bb966a0a89 = 2: 2bb966a0a89 Merge definitions of array_type_nelts_top() > 3: d22b5e1c015 ! 3: e2dbfc43b14 c: Add __lengthof__() operator > @@ Metadata > Author: Alejandro Colomar <a...@kernel.org> > > ## Commit message ## > - c: Add __lengthof__() operator > + c: Add __lengthof__() operator (n2529) > > This operator is similar to sizeof() but can only be applied to an > array, and returns its length (number of elements). > > - TO BE DECIDED BEFORE MERGING: > - > - It would be better to not evaluate the operand if the > top-level > - array is not a VLA. > - > FUTURE DIRECTIONS: > > We could make it work with array parameters to functions, and > @@ Commit message > regardless of it being really a pointer. > > Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2529.pdf> > - Cc: Xavier Del Campo Romero <xavi....@tutanota.com> > + Link: <https://inbox.sourceware.org/gcc/m8s4oqy--...@tutanota.com/T/> > + Suggested-by: Xavier Del Campo Romero <xavi....@tutanota.com> > + Co-developed-by: Martin Uecker <uec...@tugraz.at> > Cc: Gabriel Ravier <gabrav...@gmail.com> > - Cc: Martin Uecker <uec...@tugraz.at> > Cc: Joseph Myers <josmy...@redhat.com> > Cc: Jakub Jelinek <ja...@redhat.com> > + Cc: Kees Cook <keesc...@chromium.org> > + Cc: Qing Zhao <qing.z...@oracle.com> > + Cc: Jens Gustedt <jens.gust...@inria.fr> > Signed-off-by: Alejandro Colomar <a...@kernel.org> > > ## gcc/c-family/c-common.cc ## > @@ gcc/c-family/c-common.cc: c_alignof_expr (location_t loc, tree expr) > + enum tree_code type_code; > + > + type_code = TREE_CODE (type); > ++ if (type_code != ARRAY_TYPE) > ++ { > ++ error_at (loc, "invalid application of %<lengthof%> to type %qT", > type); > ++ return error_mark_node; > ++ } > + if (!COMPLETE_TYPE_P (type)) > + { > + error_at (loc, > @@ gcc/c-family/c-common.cc: c_alignof_expr (location_t loc, tree expr) > + type); > + return error_mark_node; > + } > -+ if (type_code != ARRAY_TYPE) > -+ { > -+ error_at (loc, "invalid application of %<lengthof%> to type %qT", > type); > -+ return error_mark_node; > -+ } > + > + return array_type_nelts_top (type); > +} > @@ gcc/c/c-typeck.cc: c_expr_sizeof_type (location_t loc, struct > c_type_name *t) > return ret; > } > > ++static bool > ++is_top_array_vla (tree type) > ++{ > ++ bool zero, var; > ++ tree d; > ++ > ++ if (TREE_CODE (type) != ARRAY_TYPE) > ++ return false; > ++ if (!COMPLETE_TYPE_P (type)) > ++ return false; > ++ > ++ 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)); > ++ return var; > ++} > ++ > +/* Return the result of lengthof applied to EXPR. */ > + > +struct c_expr > @@ gcc/c/c-typeck.cc: c_expr_sizeof_type (location_t loc, struct > c_type_name *t) > + ret.original_code = LENGTHOF_EXPR; > + ret.original_type = NULL; > + ret.m_decimal = 0; > -+ if (C_TYPE_VARIABLE_SIZE (TREE_TYPE (folded_expr))) > ++ if (is_top_array_vla (TREE_TYPE (folded_expr))) > + { > + /* lengthof is evaluated when given a vla. */ > + ret.value = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (ret.value), > @@ gcc/c/c-typeck.cc: c_expr_sizeof_type (location_t loc, struct > c_type_name *t) > + C_MAYBE_CONST_EXPR_NON_CONST (ret.value) = > !expr_const_operands; > + SET_EXPR_LOCATION (ret.value, loc); > + } > -+ pop_maybe_used (C_TYPE_VARIABLE_SIZE (TREE_TYPE (folded_expr))); > ++ pop_maybe_used (is_top_array_vla (TREE_TYPE (folded_expr))); > + } > + return ret; > +} > @@ gcc/c/c-typeck.cc: c_expr_sizeof_type (location_t loc, struct > c_type_name *t) > + } > + else > + if ((type_expr || TREE_CODE (ret.value) == INTEGER_CST) > -+ && C_TYPE_VARIABLE_SIZE (type)) > ++ && is_top_array_vla (type)) > + { > + /* If the type is a [*] array, it is a VLA but is represented as > + having a size of zero. In such a case we must ensure that > @@ gcc/c/c-typeck.cc: c_expr_sizeof_type (location_t loc, struct > c_type_name *t) > + type_expr, ret.value); > + C_MAYBE_CONST_EXPR_NON_CONST (ret.value) = !type_expr_const; > + } > -+ pop_maybe_used (type != error_mark_node > -+ ? C_TYPE_VARIABLE_SIZE (type) : false); > ++ pop_maybe_used (type != error_mark_node ? is_top_array_vla (type) : > false); > + return ret; > +} > + > @@ gcc/doc/extend.texi: If the operand of the @code{__alignof__} > expression is a fu > > +@node Length > +@section Determining the Length of Arrays > ++@cindex lengthof > +@cindex length > +@cindex array length > + > +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}, > -+and the operand is evaluated following the same rules. > -+(TODO: We probably want to restrict evaluation to top-level VLAs only. > -+ This documentation describes the current implementation.) > ++Its syntax is just like @code{sizeof}. > ++The operand must be a complete array type. > ++The operand is not evaluated > ++if the top-level length designator is an integer constant expression; > ++and it is evaluated > ++if the top-level length designator is not an integer constant > expression. > ++ > ++XXX: Do we want to document the following? I think so. > ++XXX: It would prevent users from relying on __lengthof__ > ++XXX: for distinguishing arrays from pointers. > ++XXX: I don't want users to complain in the future > ++XXX: if this doesn't report errors on function parameters anymore > ++XXX: and that breaks their assumptions. > ++In the future, > ++it might also accept a function parameter with array notation, > ++an incomplete array whose length is specified by other means, > ++such as attributes, > ++or other similar cases. > + > @node Inline > @section An Inline Function is As Fast As a Macro > -: ----------- > 4: 9a691f7f208 testsuite: Add tests for __lengthof__ > -- > 2.45.2 > -- <https://www.alejandro-colomar.es/>
signature.asc
Description: PGP signature