Hi, v3:
- Add some documentation.
- Reject incomplete types.
- Rename array_type_nelts()=>array_type_nelts_minus_one(). (However, I
included that patch in this set only for completeness purposes; that
patch is also sent standalone, and I would like it to be merged in
the separate discussion for it.)
(Below is a range diff against v2.)
Below is a test program I'm using for implementing this feature:
$ cat len.c
#include <stdalign.h>
#include <stdio.h>
#define memberof(T, member) ((T){}.member)
struct s {
int x;
int y[8];
int z[];
};
extern int x[];
int
main(int argc, char *argv[argc + 1])
{
short a[42];
size_t n;
(void) argv;
// Wishlist:
//n = __lengthof__(argv);
//printf("lengthof(argv) == %zu\n", n);
n = __lengthof__(a);
printf("lengthof(a):\t %zu\n", n);
// Expected error:
//n = __lengthof__(x);
//printf("lengthof(x):\t %zu\n", n);
n = __lengthof__(long [0]);
printf("lengthof(long [0]):\t %zu\n", n);
n = __lengthof__(long [99]);
printf("lengthof(long [99]):\t %zu\n", n);
n = __lengthof__(short [n - 10]);
printf("lengthof(short [n - 10]):\t %zu\n", n);
int b[n / 2];
n = __lengthof__(b);
printf("lengthof(b):\t %zu\n", n);
puts("");
// X(memberof(struct s, y))
n = __lengthof__(memberof(struct s, y));
printf("lengthof(memberof(struct s, y)):\t %zu\n", n);
n = sizeof(memberof(struct s, y));
printf("sizeof(memberof(struct s, y)):\t %zu\n", n);
n = alignof(memberof(struct s, y));
printf("alignof(memberof(struct s, y)):\t %zu\n", n);
puts("");
// X(memberof(struct s, z))
// Expected error:
//n = __lengthof__(memberof(struct s, z));
//printf("lengthof(memberof(struct s, z)):\t %zu\n", n);
// Expected 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);
puts("");
// X(struct {int x;}[i++])
int i = 4;
n = __lengthof__(struct {int x;}[i++]);
printf("lengthof(struct {int x;}[i++]):\t %zu; i: %d\n", n, i);
i = 4;
n = sizeof(struct {int x;}[i++]);
printf("sizeof(struct {int x;}[i++]):\t %zu; i: %d\n", n, i);
i = 4;
n = alignof(struct {int x;}[i++]);
printf("alignof(struct {int x;}[i++]):\t %zu; i: %d\n", n, i);
i = 4;
typeof(struct {int x;}[i++]) z1;
printf("typeof(struct {int x;}[i++]);\t i: %d\n", i);
puts("");
// X(struct {int x[i++];}[3])
i = 4;
n = __lengthof__(struct {int x[i++];}[3]);
printf("lengthof(struct {int x[i++];}[3]):\t %zu; i: %d\n", n,
i);
i = 4;
n = sizeof(struct {int x[i++];}[3]);
printf("sizeof(struct {int x[i++];}[3]):\t %zu; i: %d\n", n, i);
i = 4;
n = alignof(struct {int x[i++];}[3]);
printf("alignof(struct {int x[i++];}[3]):\t %zu; i: %d\n", n,
i);
i = 4;
typeof(struct {int x[i++];}[3]) z2;
printf("typeof(struct {int x[i++];}[3]);\t i: %d\n", i);
puts("");
// X(struct {int x[(i++, 2)];}[3])
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);
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);
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);
i = 4;
typeof(struct {int x[(i++, 2)];}[3]) z3;
printf("typeof(struct {int x[(i++, 2)];}[3]);\t i: %d\n",
i);
puts("");
// X(*p++)
short (*p)[42];
p = &a;
n = __lengthof__(*p++);
printf("lengthof(*p++):\t %zu; p: %p\n", n, p);
p = &a;
n = sizeof(*p++);
printf("lengthof(*p++):\t %zu; p: %p\n", n, p);
p = &a;
n = alignof(*p++);
printf("alignof(*p++):\t %zu; p: %p\n", n, p);
p = &a;
typeof(*p++) z4;
printf("typeof(*p++);\t p: %p\n", p);
puts("");
// X(*q++)
short (*q)[__lengthof__(b)];
q = &a;
n = __lengthof__(*q++);
printf("lengthof(*q++):\t %zu; p: %p\n", n, q);
q = &a;
n = sizeof(*q++);
printf("lengthof(*q++):\t %zu; p: %p\n", n, q);
q = &a;
n = alignof(*q++);
printf("alignof(*q++):\t %zu; p: %p\n", n, q);
q = &a;
typeof(*q++) z5;
printf("typeof(*q++);\t p: %p\n", q);
}
$ /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(b): 44
lengthof(memberof(struct s, y)): 8
sizeof(memberof(struct s, y)): 32
alignof(memberof(struct s, y)): 4
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
typeof(struct {int x;}[i++]); i: 5
lengthof(struct {int x[i++];}[3]): 3; i: 5
sizeof(struct {int x[i++];}[3]): 48; i: 5
alignof(struct {int x[i++];}[3]): 4; i: 4
typeof(struct {int x[i++];}[3]); i: 5
lengthof(struct {int x[(i++, 2)];}[3]): 3; i: 5
sizeof(struct {int x[(i++, 2)];}[3]): 24; i: 5
alignof(struct {int x[(i++, 2)];}[3]): 4; i: 4
typeof(struct {int x[(i++, 2)];}[3]); i: 5
lengthof(*p++): 42; p: 0x7fffe52379f0
lengthof(*p++): 84; p: 0x7fffe52379f0
alignof(*p++): 2; p: 0x7fffe52379f0
typeof(*p++); p: 0x7fffe52379f0
lengthof(*q++): 44; p: 0x7fffe5237a48
lengthof(*q++): 88; p: 0x7fffe5237a48
alignof(*q++): 2; p: 0x7fffe52379f0
typeof(*q++); p: 0x7fffe5237a48
There are some things to consider:
- Error handling could be incomplete; there are a few things I still
don't understand.
- I'd like to implement it so that only top-level VLAs trigger
evaluation, but I still don't understand that well.
Other than that, it starts looking good.
Have a lovely night!
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 | 95 +++++++++++++++++++++++++++++++++--
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 | 12 +++++
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/tree.cc | 17 ++++++-
gcc/tree.h | 3 +-
25 files changed, 245 insertions(+), 79 deletions(-)
Range-diff against v2:
-: ----------- > 1: 73010cb4af6 gcc/: Rename array_type_nelts() =>
array_type_nelts_minus_one()
1: 507f5a51e17 ! 2: 2bb966a0a89 Merge definitions of array_type_nelts_top()
@@ Commit message
Merge definitions of array_type_nelts_top()
There were two identical definitions, and none of them are available
- where they are needed for implementing _Lengthof(). Merge them, and
+ where they are needed for implementing __lengthof__(). Merge them, and
provide the single definition in gcc/tree.{h,cc}, where it's available
- for _Lengthof().
+ for __lengthof__().
Signed-off-by: Alejandro Colomar <[email protected]>
@@ gcc/cp/tree.cc: cxx_print_statistics (void)
-{
- return fold_build2_loc (input_location,
- PLUS_EXPR, sizetype,
-- array_type_nelts (type),
+- array_type_nelts_minus_one (type),
- size_one_node);
-}
-
@@ gcc/rust/backend/rust-tree.cc: is_empty_class (tree type)
-array_type_nelts_top (tree type)
-{
- return fold_build2_loc (input_location, PLUS_EXPR, sizetype,
-- array_type_nelts (type), size_one_node);
+- array_type_nelts_minus_one (type), size_one_node);
-}
-
// forked from gcc/cp/tree.cc builtin_valid_in_constant_expr_p
@@ gcc/rust/backend/rust-tree.h: extern location_t rs_expr_location
(const_tree);
## gcc/tree.cc ##
-@@ gcc/tree.cc: array_type_nelts (const_tree type)
+@@ gcc/tree.cc: array_type_nelts_minus_one (const_tree type)
? max
: fold_build2 (MINUS_EXPR, TREE_TYPE (max), max, min));
}
@@ gcc/tree.cc: array_type_nelts (const_tree type)
+{
+ return fold_build2_loc (input_location,
+ PLUS_EXPR, sizetype,
-+ array_type_nelts (type),
++ array_type_nelts_minus_one (type),
+ size_one_node);
+}
@@ gcc/tree.h
@@ gcc/tree.h: extern tree build_method_type (tree, tree);
extern tree build_offset_type (tree, tree);
extern tree build_complex_type (tree, bool named = false);
- extern tree array_type_nelts (const_tree);
+ extern tree array_type_nelts_minus_one (const_tree);
+extern tree array_type_nelts_top (tree);
extern tree value_member (tree, tree);
2: 6b48d48ecdd ! 3: d22b5e1c015 c: Add __lengthof__() operator
@@ Commit message
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 <[email protected]>
Cc: Gabriel Ravier <[email protected]>
Cc: Martin Uecker <[email protected]>
Cc: Joseph Myers <[email protected]>
+ Cc: Jakub Jelinek <[email protected]>
Signed-off-by: Alejandro Colomar <[email protected]>
## 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 (!COMPLETE_TYPE_P (type))
++ {
++ error_at (loc,
++ "invalid application of %<lengthof%> to incomplete type %qT",
++ type);
++ return error_mark_node;
++ }
+ if (type_code != ARRAY_TYPE)
+ {
+ error_at (loc, "invalid application of %<lengthof%> to type %qT",
type);
@@ gcc/cp/operators.def: DEF_OPERATOR ("co_await", CO_AWAIT_EXPR, "aw",
OVL_OP_FLAG
DEF_OPERATOR ("__real__", REALPART_EXPR, "v18__real__", OVL_OP_FLAG_UNARY)
+ ## gcc/doc/extend.texi ##
+@@ gcc/doc/extend.texi: If the operand of the @code{__alignof__}
expression is a function,
+ the expression evaluates to the alignment of the function which may
+ be specified by attribute @code{aligned} (@pxref{Common Function
Attributes}).
+
++@node Length
++@section Determining the Length of Arrays
++@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.)
++
+ @node Inline
+ @section An Inline Function is As Fast As a Macro
+ @cindex inline functions
+
## gcc/target.h ##
@@ gcc/target.h: enum type_context_kind {
/* Directly measuring the alignment of T. */
--
2.45.2
signature.asc
Description: PGP signature
