* [RFC v1 0/2] c: Add _Lengthof operator
@ 2024-07-28 14:15 ` Alejandro Colomar
2024-07-28 14:15 ` [RFC v1 1/2] Merge definitions of array_type_nelts_top() Alejandro Colomar
` (22 more replies)
0 siblings, 23 replies; 248+ messages in thread
From: Alejandro Colomar @ 2024-07-28 14:15 UTC (permalink / raw)
To: gcc-patches
Cc: Alejandro Colomar, Gabriel Ravier, Martin Uecker, Joseph Myers
[-- Attachment #1: Type: text/plain, Size: 2496 bytes --]
Hi!
I've got something working:
$ cat len.c
#include <stdio.h>
int
main(int argc, char *argv[argc + 1])
{
int a[42];
size_t n;
(void) argv;
//n = _Lengthof(argv);
//printf("_Lengthof(argv) == %zu\n", n);
n = _Lengthof(a);
printf("%zu\n", n);
n = _Lengthof(long [99]);
printf("%zu\n", n);
n = _Lengthof(short [n - 10]);
printf("%zu\n", n);
int b[n / 2];
n = _Lengthof(b);
printf("%zu\n", n);
}
$ /opt/local/gnu/gcc/lengthof/bin/gcc -Wall -Wextra len.c
$ ./a.out
42
99
89
44
I'd like to be able to uncomment those two lines in the future, but we
probably want to do that in a separate commit.
Does anyone know if we have the information available for getting that
value from the 'tree' object? Or do we need some refactor first in
order to keep that information?
Also, I've reused much of sizeof's code, and maybe I should change some
of that. It's my first contribution to gcc of this size, and I don't
yet know what some of those internals mean. While my implementation
seems to be working (for the test above), I guess it's not ideal in
terms of readability, and may also not work well with C++ or some corner
cases. Can somebody with more experience have a look at the code?
I suspect this is not yet ready, and thus doesn't have a ChangeLog.
Have a lovely day!
Alex
Alejandro Colomar (2):
Merge definitions of array_type_nelts_top()
c: Add _Lengthof() operator
gcc/Makefile.in | 1 +
gcc/c-family/c-common.cc | 20 +++++++++
gcc/c-family/c-common.def | 4 ++
gcc/c-family/c-common.h | 2 +
gcc/c/c-parser.cc | 35 +++++++++++----
gcc/c/c-tree.h | 4 ++
gcc/c/c-typeck.cc | 84 +++++++++++++++++++++++++++++++++++
gcc/cp/cp-tree.h | 1 -
gcc/cp/operators.def | 1 +
gcc/cp/tree.cc | 13 ------
gcc/ginclude/stdlength.h | 35 +++++++++++++++
gcc/rust/backend/rust-tree.cc | 13 ------
gcc/rust/backend/rust-tree.h | 2 -
gcc/target.h | 3 ++
gcc/tree.cc | 13 ++++++
gcc/tree.h | 1 +
16 files changed, 195 insertions(+), 37 deletions(-)
create mode 100644 gcc/ginclude/stdlength.h
Range-diff against v0:
-: ----------- > 1: 507f5a51e17 Merge definitions of array_type_nelts_top()
-: ----------- > 2: e5835b982af c: Add _Lengthof() operator
--
2.45.2
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 248+ messages in thread
* [RFC v1 1/2] Merge definitions of array_type_nelts_top()
2024-07-28 14:15 ` [RFC v1 0/2] c: Add _Lengthof operator Alejandro Colomar
@ 2024-07-28 14:15 ` Alejandro Colomar
2024-07-29 8:27 ` Richard Biener
2024-07-28 14:16 ` [RFC v1 2/2] c: Add _Lengthof() operator Alejandro Colomar
` (21 subsequent siblings)
22 siblings, 1 reply; 248+ messages in thread
From: Alejandro Colomar @ 2024-07-28 14:15 UTC (permalink / raw)
To: gcc-patches
Cc: Alejandro Colomar, Gabriel Ravier, Martin Uecker, Joseph Myers
[-- Attachment #1: Type: text/plain, Size: 4377 bytes --]
There were two identical definitions, and none of them are available
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().
Signed-off-by: Alejandro Colomar <alx@kernel.org>
---
gcc/cp/cp-tree.h | 1 -
gcc/cp/tree.cc | 13 -------------
gcc/rust/backend/rust-tree.cc | 13 -------------
gcc/rust/backend/rust-tree.h | 2 --
gcc/tree.cc | 13 +++++++++++++
gcc/tree.h | 1 +
6 files changed, 14 insertions(+), 29 deletions(-)
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index c1a371bc721..e6c1c63f872 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -8099,7 +8099,6 @@ extern tree build_exception_variant (tree, tree);
extern void fixup_deferred_exception_variants (tree, tree);
extern tree bind_template_template_parm (tree, tree);
extern tree array_type_nelts_total (tree);
-extern tree array_type_nelts_top (tree);
extern bool array_of_unknown_bound_p (const_tree);
extern tree break_out_target_exprs (tree, bool = false);
extern tree build_ctor_subob_ref (tree, tree, tree);
diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
index dfd4a3a948b..1f3ecff1a21 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -3071,19 +3071,6 @@ cxx_print_statistics (void)
depth_reached);
}
-/* Return, as an INTEGER_CST node, the number of elements for TYPE
- (which is an ARRAY_TYPE). This counts only elements of the top
- array. */
-
-tree
-array_type_nelts_top (tree type)
-{
- return fold_build2_loc (input_location,
- PLUS_EXPR, sizetype,
- array_type_nelts (type),
- size_one_node);
-}
-
/* Return, as an INTEGER_CST node, the number of elements for TYPE
(which is an ARRAY_TYPE). This one is a recursive count of all
ARRAY_TYPEs that are clumped together. */
diff --git a/gcc/rust/backend/rust-tree.cc b/gcc/rust/backend/rust-tree.cc
index 2a5ffcbf895..dd8eda84f9b 100644
--- a/gcc/rust/backend/rust-tree.cc
+++ b/gcc/rust/backend/rust-tree.cc
@@ -859,19 +859,6 @@ is_empty_class (tree type)
return CLASSTYPE_EMPTY_P (type);
}
-// forked from gcc/cp/tree.cc array_type_nelts_top
-
-/* Return, as an INTEGER_CST node, the number of elements for TYPE
- (which is an ARRAY_TYPE). This counts only elements of the top
- array. */
-
-tree
-array_type_nelts_top (tree type)
-{
- return fold_build2_loc (input_location, PLUS_EXPR, sizetype,
- array_type_nelts (type), size_one_node);
-}
-
// forked from gcc/cp/tree.cc builtin_valid_in_constant_expr_p
/* Test whether DECL is a builtin that may appear in a
diff --git a/gcc/rust/backend/rust-tree.h b/gcc/rust/backend/rust-tree.h
index 26c8b653ac6..e597c3ab81d 100644
--- a/gcc/rust/backend/rust-tree.h
+++ b/gcc/rust/backend/rust-tree.h
@@ -2993,8 +2993,6 @@ extern location_t rs_expr_location (const_tree);
extern int
is_empty_class (tree type);
-extern tree array_type_nelts_top (tree);
-
extern bool
is_really_empty_class (tree, bool);
diff --git a/gcc/tree.cc b/gcc/tree.cc
index 2d2d5b6db6e..3b0adb4cd9f 100644
--- a/gcc/tree.cc
+++ b/gcc/tree.cc
@@ -3729,6 +3729,19 @@ array_type_nelts (const_tree type)
? max
: fold_build2 (MINUS_EXPR, TREE_TYPE (max), max, min));
}
+
+/* Return, as an INTEGER_CST node, the number of elements for TYPE
+ (which is an ARRAY_TYPE). This counts only elements of the top
+ array. */
+
+tree
+array_type_nelts_top (tree type)
+{
+ return fold_build2_loc (input_location,
+ PLUS_EXPR, sizetype,
+ array_type_nelts (type),
+ size_one_node);
+}
\f
/* If arg is static -- a reference to an object in static storage -- then
return the object. This is not the same as the C meaning of `static'.
diff --git a/gcc/tree.h b/gcc/tree.h
index 28e8e71b036..c620e55b68d 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -4922,6 +4922,7 @@ 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_top (tree);
extern tree value_member (tree, tree);
extern tree purpose_member (const_tree, tree);
--
2.45.2
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 248+ messages in thread
* [RFC v1 2/2] c: Add _Lengthof() operator
2024-07-28 14:15 ` [RFC v1 0/2] c: Add _Lengthof operator Alejandro Colomar
2024-07-28 14:15 ` [RFC v1 1/2] Merge definitions of array_type_nelts_top() Alejandro Colomar
@ 2024-07-28 14:16 ` Alejandro Colomar
2024-07-28 14:42 ` [RFC v1 0/2] c: Add _Lengthof operator Martin Uecker
` (20 subsequent siblings)
22 siblings, 0 replies; 248+ messages in thread
From: Alejandro Colomar @ 2024-07-28 14:16 UTC (permalink / raw)
To: gcc-patches
Cc: Alejandro Colomar, Gabriel Ravier, Martin Uecker, Joseph Myers
[-- Attachment #1: Type: text/plain, Size: 15573 bytes --]
This operator is similar to sizeof() but can only be applied to an
array, and returns its length (number of elements).
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.
Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2529.pdf>
Cc: Gabriel Ravier <gabravier@gmail.com>
Cc: Martin Uecker <uecker@tugraz.at>
Cc: Joseph Myers <josmyers@redhat.com>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
---
gcc/Makefile.in | 1 +
gcc/c-family/c-common.cc | 20 ++++++++++
gcc/c-family/c-common.def | 4 ++
gcc/c-family/c-common.h | 2 +
gcc/c/c-parser.cc | 35 ++++++++++++----
gcc/c/c-tree.h | 4 ++
gcc/c/c-typeck.cc | 84 +++++++++++++++++++++++++++++++++++++++
gcc/cp/operators.def | 1 +
gcc/ginclude/stdlength.h | 35 ++++++++++++++++
gcc/target.h | 3 ++
10 files changed, 181 insertions(+), 8 deletions(-)
create mode 100644 gcc/ginclude/stdlength.h
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index f4bb4a88cf3..88496edbdc8 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -477,6 +477,7 @@ USER_H = $(srcdir)/ginclude/float.h \
$(srcdir)/ginclude/stdalign.h \
$(srcdir)/ginclude/stdatomic.h \
$(srcdir)/ginclude/stdckdint.h \
+ $(srcdir)/ginclude/stdlength.h \
$(EXTRA_HEADERS)
USER_H_INC_NEXT_PRE = @user_headers_inc_next_pre@
diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
index e7e371fd26f..c9020a7faef 100644
--- a/gcc/c-family/c-common.cc
+++ b/gcc/c-family/c-common.cc
@@ -407,6 +407,7 @@ const struct c_common_resword c_common_reswords[] =
{ "_Decimal64", RID_DFLOAT64, D_CONLY },
{ "_Decimal128", RID_DFLOAT128, D_CONLY },
{ "_Fract", RID_FRACT, D_CONLY | D_EXT },
+ { "_Lengthof", RID_LENGTHOF, D_CONLY | D_EXT },
{ "_Accum", RID_ACCUM, D_CONLY | D_EXT },
{ "_Sat", RID_SAT, D_CONLY | D_EXT },
{ "_Static_assert", RID_STATIC_ASSERT, D_CONLY },
@@ -523,6 +524,7 @@ const struct c_common_resword c_common_reswords[] =
{ "if", RID_IF, 0 },
{ "inline", RID_INLINE, D_EXT89 },
{ "int", RID_INT, 0 },
+ { "lengthof", RID_LENGTHOF, D_EXT },
{ "long", RID_LONG, 0 },
{ "mutable", RID_MUTABLE, D_CXXONLY | D_CXXWARN },
{ "namespace", RID_NAMESPACE, D_CXXONLY | D_CXXWARN },
@@ -4070,6 +4072,24 @@ c_alignof_expr (location_t loc, tree expr)
return fold_convert_loc (loc, size_type_node, t);
}
+
+/* Implement the _Lengthof keyword: Return the length of an array,
+ that is, the number of elements in the array. */
+
+tree
+c_lengthof_type (location_t loc, tree type)
+{
+ 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;
+ }
+
+ return array_type_nelts_top (type);
+}
\f
/* Handle C and C++ default attributes. */
diff --git a/gcc/c-family/c-common.def b/gcc/c-family/c-common.def
index 5de96e5d4a8..46e128072b5 100644
--- a/gcc/c-family/c-common.def
+++ b/gcc/c-family/c-common.def
@@ -50,6 +50,10 @@ DEFTREECODE (EXCESS_PRECISION_EXPR, "excess_precision_expr", tcc_expression, 1)
number. */
DEFTREECODE (USERDEF_LITERAL, "userdef_literal", tcc_exceptional, 3)
+/* Represents a 'sizeof' expression during C++ template expansion,
+ or for the purpose of -Wsizeof-pointer-memaccess warning. */
+DEFTREECODE (LENGTHOF_EXPR, "lengthof_expr", tcc_expression, 1)
+
/* Represents a 'sizeof' expression during C++ template expansion,
or for the purpose of -Wsizeof-pointer-memaccess warning. */
DEFTREECODE (SIZEOF_EXPR, "sizeof_expr", tcc_expression, 1)
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index ccaea27c2b9..f815a4cf3bc 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -105,6 +105,7 @@ enum rid
/* C extensions */
RID_ASM, RID_TYPEOF, RID_TYPEOF_UNQUAL, RID_ALIGNOF, RID_ATTRIBUTE,
+ RID_LENGTHOF,
RID_VA_ARG,
RID_EXTENSION, RID_IMAGPART, RID_REALPART, RID_LABEL, RID_CHOOSE_EXPR,
RID_TYPES_COMPATIBLE_P, RID_BUILTIN_COMPLEX, RID_BUILTIN_SHUFFLE,
@@ -885,6 +886,7 @@ extern tree c_common_truthvalue_conversion (location_t, tree);
extern void c_apply_type_quals_to_decl (int, tree);
extern tree c_sizeof_or_alignof_type (location_t, tree, bool, bool, int);
extern tree c_alignof_expr (location_t, tree);
+extern tree c_lengthof_type (location_t, tree);
/* Print an error message for invalid operands to arith operation CODE.
NOP_EXPR is used as a special case (see truthvalue_conversion). */
extern void binary_op_error (rich_location *, enum tree_code, tree, tree);
diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
index 12c5ed5d92c..eb1d8b932fd 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -74,7 +74,17 @@ along with GCC; see the file COPYING3. If not see
#include "bitmap.h"
#include "analyzer/analyzer-language.h"
#include "toplev.h"
+\f
+#define c_parser_sizeof_expression(parser) \
+( \
+ c_parser_sizeof_or_lengthof_expression (parser, RID_SIZEOF) \
+)
+#define c_parser_lengthof_expression(parser) \
+( \
+ c_parser_sizeof_or_lengthof_expression (parser, RID_LENGTHOF) \
+)
+\f
/* We need to walk over decls with incomplete struct/union/enum types
after parsing the whole translation unit.
In finish_decl(), if the decl is static, has incomplete
@@ -1687,7 +1697,7 @@ static struct c_expr c_parser_binary_expression (c_parser *, struct c_expr *,
tree);
static struct c_expr c_parser_cast_expression (c_parser *, struct c_expr *);
static struct c_expr c_parser_unary_expression (c_parser *);
-static struct c_expr c_parser_sizeof_expression (c_parser *);
+static struct c_expr c_parser_sizeof_or_lengthof_expression (c_parser *, enum rid);
static struct c_expr c_parser_alignof_expression (c_parser *);
static struct c_expr c_parser_postfix_expression (c_parser *);
static struct c_expr c_parser_postfix_expression_after_paren_type (c_parser *,
@@ -9864,6 +9874,8 @@ c_parser_unary_expression (c_parser *parser)
case CPP_KEYWORD:
switch (c_parser_peek_token (parser)->keyword)
{
+ case RID_LENGTHOF:
+ return c_parser_lengthof_expression (parser);
case RID_SIZEOF:
return c_parser_sizeof_expression (parser);
case RID_ALIGNOF:
@@ -9903,12 +9915,13 @@ c_parser_unary_expression (c_parser *parser)
/* Parse a sizeof expression. */
static struct c_expr
-c_parser_sizeof_expression (c_parser *parser)
+c_parser_sizeof_or_lengthof_expression (c_parser *parser, enum rid rid)
{
+ const char *op_name = (rid == RID_SIZEOF) ? "sizeof" : "_Lengthof";
struct c_expr expr;
struct c_expr result;
location_t expr_loc;
- gcc_assert (c_parser_next_token_is_keyword (parser, RID_SIZEOF));
+ gcc_assert (c_parser_next_token_is_keyword (parser, rid));
location_t start;
location_t finish = UNKNOWN_LOCATION;
@@ -9952,13 +9965,16 @@ c_parser_sizeof_expression (c_parser *parser)
}
/* sizeof ( type-name ). */
if (scspecs)
- error_at (expr_loc, "storage class specifier in %<sizeof%>");
+ error_at (expr_loc, "storage class specifier in %qs", op_name);
if (type_name->specs->alignas_p)
error_at (type_name->specs->locations[cdw_alignas],
- "alignment specified for type name in %<sizeof%>");
+ "alignment specified for type name in %qs", op_name);
c_inhibit_evaluation_warnings--;
in_sizeof--;
- result = c_expr_sizeof_type (expr_loc, type_name);
+ if (rid == RID_LENGTHOF)
+ result = c_expr_lengthof_type (expr_loc, type_name);
+ else
+ result = c_expr_sizeof_type (expr_loc, type_name);
}
else
{
@@ -9971,8 +9987,11 @@ c_parser_sizeof_expression (c_parser *parser)
mark_exp_read (expr.value);
if (TREE_CODE (expr.value) == COMPONENT_REF
&& DECL_C_BIT_FIELD (TREE_OPERAND (expr.value, 1)))
- error_at (expr_loc, "%<sizeof%> applied to a bit-field");
- result = c_expr_sizeof_expr (expr_loc, expr);
+ error_at (expr_loc, "%qs applied to a bit-field", op_name);
+ if (rid == RID_LENGTHOF)
+ result = c_expr_lengthof_expr (expr_loc, expr);
+ else
+ result = c_expr_sizeof_expr (expr_loc, expr);
}
if (finish == UNKNOWN_LOCATION)
finish = start;
diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h
index 15da875a029..102fcfefea6 100644
--- a/gcc/c/c-tree.h
+++ b/gcc/c/c-tree.h
@@ -736,6 +736,7 @@ extern int c_type_dwarf_attribute (const_tree, int);
/* in c-typeck.cc */
extern int in_alignof;
extern int in_sizeof;
+extern int in_lengthof;
extern int in_typeof;
extern bool c_in_omp_for;
extern bool c_omp_array_section_p;
@@ -786,6 +787,9 @@ extern tree build_external_ref (location_t, tree, bool, tree *);
extern void pop_maybe_used (bool);
extern struct c_expr c_expr_sizeof_expr (location_t, struct c_expr);
extern struct c_expr c_expr_sizeof_type (location_t, struct c_type_name *);
+extern struct c_expr c_expr_lengthof_expr (location_t, struct c_expr);
+extern struct c_expr c_expr_lengthof_type (location_t loc,
+ struct c_type_name *);
extern struct c_expr parser_build_unary_op (location_t, enum tree_code,
struct c_expr);
extern struct c_expr parser_build_binary_op (location_t,
diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index 7e0f01ed22b..543254406f5 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -3453,6 +3453,90 @@ c_expr_sizeof_type (location_t loc, struct c_type_name *t)
return ret;
}
+/* Return the result of _Lengthof applied to EXPR. */
+
+struct c_expr
+c_expr_lengthof_expr (location_t loc, struct c_expr expr)
+{
+ struct c_expr ret;
+ if (expr.value == error_mark_node)
+ {
+ ret.value = error_mark_node;
+ ret.original_code = ERROR_MARK;
+ ret.original_type = NULL;
+ ret.m_decimal = 0;
+ pop_maybe_used (false);
+ }
+ else
+ {
+ bool expr_const_operands = true;
+
+ tree folded_expr = c_fully_fold (expr.value, require_constant_value,
+ &expr_const_operands);
+ ret.value = c_lengthof_type (loc, TREE_TYPE (folded_expr));
+ c_last_sizeof_arg = expr.value;
+ c_last_sizeof_loc = loc;
+ ret.original_code = LENGTHOF_EXPR;
+ ret.original_type = NULL;
+ ret.m_decimal = 0;
+ if (C_TYPE_VARIABLE_SIZE (TREE_TYPE (folded_expr)))
+ {
+ /* _Lengthof is evaluated when given a vla. */
+ ret.value = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (ret.value),
+ folded_expr, ret.value);
+ 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)));
+ }
+ return ret;
+}
+
+/* Return the result of _Lengthof applied to T, a structure for the type
+ name passed to _lengthof (rather than the type itself). LOC is the
+ location of the original expression. */
+
+struct c_expr
+c_expr_lengthof_type (location_t loc, struct c_type_name *t)
+{
+ tree type;
+ struct c_expr ret;
+ tree type_expr = NULL_TREE;
+ bool type_expr_const = true;
+ type = groktypename (t, &type_expr, &type_expr_const);
+ ret.value = c_lengthof_type (loc, type);
+ c_last_sizeof_arg = type;
+ c_last_sizeof_loc = loc;
+ ret.original_code = LENGTHOF_EXPR;
+ ret.original_type = NULL;
+ ret.m_decimal = 0;
+ if (type == error_mark_node)
+ {
+ ret.value = error_mark_node;
+ ret.original_code = ERROR_MARK;
+ }
+ else
+ if ((type_expr || TREE_CODE (ret.value) == INTEGER_CST)
+ && C_TYPE_VARIABLE_SIZE (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
+ the result of _Lengthof does not get folded to a constant by
+ c_fully_fold, because if the length is evaluated the result is
+ not constant and so constraints on zero or negative size
+ arrays must not be applied when this _Lengthof call is inside
+ another array declarator. */
+ if (!type_expr)
+ type_expr = integer_zero_node;
+ ret.value = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (ret.value),
+ 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);
+ return ret;
+}
+
/* Build a function call to function FUNCTION with parameters PARAMS.
The function call is at LOC.
PARAMS is a list--a chain of TREE_LIST nodes--in which the
diff --git a/gcc/cp/operators.def b/gcc/cp/operators.def
index d8878923602..ab1447a3386 100644
--- a/gcc/cp/operators.def
+++ b/gcc/cp/operators.def
@@ -91,6 +91,7 @@ DEF_OPERATOR ("co_await", CO_AWAIT_EXPR, "aw", OVL_OP_FLAG_UNARY)
/* These are extensions. */
DEF_OPERATOR ("alignof", ALIGNOF_EXPR, "az", OVL_OP_FLAG_UNARY)
+DEF_OPERATOR ("lengthof", LENGTHOF_EXPR, "lz", OVL_OP_FLAG_UNARY)
DEF_OPERATOR ("__imag__", IMAGPART_EXPR, "v18__imag__", OVL_OP_FLAG_UNARY)
DEF_OPERATOR ("__real__", REALPART_EXPR, "v18__real__", OVL_OP_FLAG_UNARY)
diff --git a/gcc/ginclude/stdlength.h b/gcc/ginclude/stdlength.h
new file mode 100644
index 00000000000..551de92ecb1
--- /dev/null
+++ b/gcc/ginclude/stdlength.h
@@ -0,0 +1,35 @@
+/* Copyright (C) 2024 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+Under Section 7 of GPL version 3, you are granted additional
+permissions described in the GCC Runtime Library Exception, version
+3.1, as published by the Free Software Foundation.
+
+You should have received a copy of the GNU General Public License and
+a copy of the GCC Runtime Library Exception along with this program;
+see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+<http://www.gnu.org/licenses/>. */
+
+#ifndef _STDLENGTH_H
+#define _STDLENGTH_H
+
+#if (!defined __cplusplus)
+
+#define lengthof _Lengthof
+
+#define __lengthof_is_defined 1
+
+#endif
+
+#endif /* stdlength.h */
diff --git a/gcc/target.h b/gcc/target.h
index c1f99b97b86..79890ae9944 100644
--- a/gcc/target.h
+++ b/gcc/target.h
@@ -245,6 +245,9 @@ enum type_context_kind {
/* Directly measuring the alignment of T. */
TCTX_ALIGNOF,
+ /* Directly measuring the length of array T. */
+ TCTX_LENGTHOF,
+
/* Creating objects of type T with static storage duration. */
TCTX_STATIC_STORAGE,
--
2.45.2
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [RFC v1 0/2] c: Add _Lengthof operator
2024-07-28 14:15 ` [RFC v1 0/2] c: Add _Lengthof operator Alejandro Colomar
2024-07-28 14:15 ` [RFC v1 1/2] Merge definitions of array_type_nelts_top() Alejandro Colomar
2024-07-28 14:16 ` [RFC v1 2/2] c: Add _Lengthof() operator Alejandro Colomar
@ 2024-07-28 14:42 ` Martin Uecker
2024-07-28 15:19 ` Alejandro Colomar
2024-07-28 16:48 ` [RFC v2 0/2] c: Add __lengthof__ operator Alejandro Colomar
` (19 subsequent siblings)
22 siblings, 1 reply; 248+ messages in thread
From: Martin Uecker @ 2024-07-28 14:42 UTC (permalink / raw)
To: Alejandro Colomar, gcc-patches; +Cc: Gabriel Ravier, Joseph Myers
Am Sonntag, dem 28.07.2024 um 16:15 +0200 schrieb Alejandro Colomar:
...
>
> Does anyone know if we have the information available for getting that
> value from the 'tree' object? Or do we need some refactor first in
> order to keep that information?
What I wanted to try is to not immediately adjust the type to a
pointer and keep it represented as an array, so that the size is
preserved. We currently already have a flag that tells us that
the type came from a parameter declared as an array, so we would
do it the other way round and have a flag that tells us that it
is really a pointer.
In most cases the array would then decay and nothing needs to be
changed, but in some cases we would special case it to get the
correct result (addressof / sizeof / typeof and maybe others).
Those are also cases which should have a warning anyway. So this
*should* be simple, but I haven't tried.
I will look at you code later, but I would recommend to avoid
refactoring that touches different parts of the compiler at this
point.
I also wonder whether it would make sense to propose a GNU
extension first instead of implementing a full prototype for
the standard feature? I do not think we could merge the
former without having an accepted proposal.
Martin
>
> Also, I've reused much of sizeof's code, and maybe I should change some
> of that. It's my first contribution to gcc of this size, and I don't
> yet know what some of those internals mean. While my implementation
> seems to be working (for the test above), I guess it's not ideal in
> terms of readability, and may also not work well with C++ or some corner
> cases. Can somebody with more experience have a look at the code?
>
> I suspect this is not yet ready, and thus doesn't have a ChangeLog.
>
> Have a lovely day!
> Alex
>
>
> Alejandro Colomar (2):
> Merge definitions of array_type_nelts_top()
> c: Add _Lengthof() operator
>
> gcc/Makefile.in | 1 +
> gcc/c-family/c-common.cc | 20 +++++++++
> gcc/c-family/c-common.def | 4 ++
> gcc/c-family/c-common.h | 2 +
> gcc/c/c-parser.cc | 35 +++++++++++----
> gcc/c/c-tree.h | 4 ++
> gcc/c/c-typeck.cc | 84 +++++++++++++++++++++++++++++++++++
> gcc/cp/cp-tree.h | 1 -
> gcc/cp/operators.def | 1 +
> gcc/cp/tree.cc | 13 ------
> gcc/ginclude/stdlength.h | 35 +++++++++++++++
> gcc/rust/backend/rust-tree.cc | 13 ------
> gcc/rust/backend/rust-tree.h | 2 -
> gcc/target.h | 3 ++
> gcc/tree.cc | 13 ++++++
> gcc/tree.h | 1 +
> 16 files changed, 195 insertions(+), 37 deletions(-)
> create mode 100644 gcc/ginclude/stdlength.h
>
> Range-diff against v0:
> -: ----------- > 1: 507f5a51e17 Merge definitions of array_type_nelts_top()
> -: ----------- > 2: e5835b982af c: Add _Lengthof() operator
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [RFC v1 0/2] c: Add _Lengthof operator
2024-07-28 14:42 ` [RFC v1 0/2] c: Add _Lengthof operator Martin Uecker
@ 2024-07-28 15:19 ` Alejandro Colomar
0 siblings, 0 replies; 248+ messages in thread
From: Alejandro Colomar @ 2024-07-28 15:19 UTC (permalink / raw)
To: Martin Uecker; +Cc: gcc-patches, Gabriel Ravier, Joseph Myers
[-- Attachment #1: Type: text/plain, Size: 3076 bytes --]
Hi Martin,
On Sun, Jul 28, 2024 at 04:42:26PM GMT, Martin Uecker wrote:
> Am Sonntag, dem 28.07.2024 um 16:15 +0200 schrieb Alejandro Colomar:
>
> ...
> >
> > Does anyone know if we have the information available for getting that
> > value from the 'tree' object? Or do we need some refactor first in
> > order to keep that information?
>
> What I wanted to try is to not immediately adjust the type to a
> pointer and keep it represented as an array, so that the size is
> preserved. We currently already have a flag that tells us that
> the type came from a parameter declared as an array, so we would
> do it the other way round and have a flag that tells us that it
> is really a pointer.
Thanks! Thanks makes sense. I suspected you had something in mind. :)
Do you remember that flag's name? I can have a look at inverting that.
> In most cases the array would then decay and nothing needs to be
> changed, but in some cases we would special case it to get the
> correct result (addressof / sizeof / typeof and maybe others).
> Those are also cases which should have a warning anyway. So this
> *should* be simple, but I haven't tried.
>
> I will look at you code later, but I would recommend to avoid
> refactoring that touches different parts of the compiler at this
> point.
I had to do patch 1/2 for having the function that gives me the nelts
value; other than that, I've tried to keep it minimal.
> I also wonder whether it would make sense to propose a GNU
> extension first instead of implementing a full prototype for
> the standard feature? I do not think we could merge the
> former without having an accepted proposal.
Do you mean a __lengthof__ operator first, without using the _L name
or <stdlength.h>?
If so, I agree.
> Martin
Cheers,
Alex
> > Alejandro Colomar (2):
> > Merge definitions of array_type_nelts_top()
> > c: Add _Lengthof() operator
> >
> > gcc/Makefile.in | 1 +
> > gcc/c-family/c-common.cc | 20 +++++++++
> > gcc/c-family/c-common.def | 4 ++
> > gcc/c-family/c-common.h | 2 +
> > gcc/c/c-parser.cc | 35 +++++++++++----
> > gcc/c/c-tree.h | 4 ++
> > gcc/c/c-typeck.cc | 84 +++++++++++++++++++++++++++++++++++
> > gcc/cp/cp-tree.h | 1 -
> > gcc/cp/operators.def | 1 +
> > gcc/cp/tree.cc | 13 ------
> > gcc/ginclude/stdlength.h | 35 +++++++++++++++
> > gcc/rust/backend/rust-tree.cc | 13 ------
> > gcc/rust/backend/rust-tree.h | 2 -
> > gcc/target.h | 3 ++
> > gcc/tree.cc | 13 ++++++
> > gcc/tree.h | 1 +
> > 16 files changed, 195 insertions(+), 37 deletions(-)
> > create mode 100644 gcc/ginclude/stdlength.h
> >
> > Range-diff against v0:
> > -: ----------- > 1: 507f5a51e17 Merge definitions of array_type_nelts_top()
> > -: ----------- > 2: e5835b982af c: Add _Lengthof() operator
>
--
<https://www.alejandro-colomar.es/>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 248+ messages in thread
* [RFC v2 0/2] c: Add __lengthof__ operator
2024-07-28 14:15 ` [RFC v1 0/2] c: Add _Lengthof operator Alejandro Colomar
` (2 preceding siblings ...)
2024-07-28 14:42 ` [RFC v1 0/2] c: Add _Lengthof operator Martin Uecker
@ 2024-07-28 16:48 ` Alejandro Colomar
2024-07-28 16:48 ` [RFC v2 1/2] Merge definitions of array_type_nelts_top() Alejandro Colomar
2024-07-28 16:48 ` [RFC v2 2/2] c: Add __lengthof__() operator Alejandro Colomar
2024-07-29 11:13 ` [RFC v1 0/2] c: Add _Lengthof operator Joseph Myers
` (18 subsequent siblings)
22 siblings, 2 replies; 248+ messages in thread
From: Alejandro Colomar @ 2024-07-28 16:48 UTC (permalink / raw)
To: gcc-patches
Cc: Alejandro Colomar, Gabriel Ravier, Martin Uecker, Joseph Myers
[-- Attachment #1: Type: text/plain, Size: 16896 bytes --]
v2:
- Add a GNU extension first; not using ISO C-reserved names. That is,
add __lengthof__ instead of _Lengthof/lengthof.
- Use 'in_lengthof' instead of 'in_sizeof'.
Alejandro Colomar (2):
Merge definitions of array_type_nelts_top()
c: Add __lengthof__() operator
gcc/c-family/c-common.cc | 19 +++++++
gcc/c-family/c-common.def | 3 ++
gcc/c-family/c-common.h | 2 +
gcc/c/c-decl.cc | 20 +++++---
gcc/c/c-parser.cc | 61 ++++++++++++++++------
gcc/c/c-tree.h | 4 ++
gcc/c/c-typeck.cc | 95 +++++++++++++++++++++++++++++++++--
gcc/cp/cp-tree.h | 1 -
gcc/cp/operators.def | 1 +
gcc/cp/tree.cc | 13 -----
gcc/rust/backend/rust-tree.cc | 13 -----
gcc/rust/backend/rust-tree.h | 2 -
gcc/target.h | 3 ++
gcc/tree.cc | 13 +++++
gcc/tree.h | 1 +
15 files changed, 198 insertions(+), 53 deletions(-)
Range-diff against v1:
1: 507f5a51e17 = 1: 507f5a51e17 Merge definitions of array_type_nelts_top()
2: e5835b982af ! 2: 6b48d48ecdd c: Add _Lengthof() operator
@@ Metadata
Author: Alejandro Colomar <alx@kernel.org>
## Commit message ##
- c: Add _Lengthof() operator
+ c: Add __lengthof__() operator
This operator is similar to sizeof() but can only be applied to an
array, and returns its length (number of elements).
@@ Commit message
Cc: Joseph Myers <josmyers@redhat.com>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
- ## gcc/Makefile.in ##
-@@ gcc/Makefile.in: USER_H = $(srcdir)/ginclude/float.h \
- $(srcdir)/ginclude/stdalign.h \
- $(srcdir)/ginclude/stdatomic.h \
- $(srcdir)/ginclude/stdckdint.h \
-+ $(srcdir)/ginclude/stdlength.h \
- $(EXTRA_HEADERS)
-
- USER_H_INC_NEXT_PRE = @user_headers_inc_next_pre@
-
## gcc/c-family/c-common.cc ##
@@ gcc/c-family/c-common.cc: const struct c_common_resword c_common_reswords[] =
- { "_Decimal64", RID_DFLOAT64, D_CONLY },
- { "_Decimal128", RID_DFLOAT128, D_CONLY },
- { "_Fract", RID_FRACT, D_CONLY | D_EXT },
-+ { "_Lengthof", RID_LENGTHOF, D_CONLY | D_EXT },
- { "_Accum", RID_ACCUM, D_CONLY | D_EXT },
- { "_Sat", RID_SAT, D_CONLY | D_EXT },
- { "_Static_assert", RID_STATIC_ASSERT, D_CONLY },
-@@ gcc/c-family/c-common.cc: const struct c_common_resword c_common_reswords[] =
- { "if", RID_IF, 0 },
- { "inline", RID_INLINE, D_EXT89 },
- { "int", RID_INT, 0 },
-+ { "lengthof", RID_LENGTHOF, D_EXT },
- { "long", RID_LONG, 0 },
- { "mutable", RID_MUTABLE, D_CXXONLY | D_CXXWARN },
- { "namespace", RID_NAMESPACE, D_CXXONLY | D_CXXWARN },
+ { "__inline", RID_INLINE, 0 },
+ { "__inline__", RID_INLINE, 0 },
+ { "__label__", RID_LABEL, 0 },
++ { "__lengthof__", RID_LENGTHOF, 0 },
+ { "__null", RID_NULL, 0 },
+ { "__real", RID_REALPART, 0 },
+ { "__real__", RID_REALPART, 0 },
@@ gcc/c-family/c-common.cc: c_alignof_expr (location_t loc, tree expr)
return fold_convert_loc (loc, size_type_node, t);
}
+
-+/* Implement the _Lengthof keyword: Return the length of an array,
++/* Implement the lengthof keyword: Return the length of an array,
+ that is, the number of elements in the array. */
+
+tree
@@ gcc/c-family/c-common.cc: c_alignof_expr (location_t loc, tree expr)
+ type_code = TREE_CODE (type);
+ if (type_code != ARRAY_TYPE)
+ {
-+ error_at (loc, "invalid application of %<_Lengthof%> to type %qT", type);
++ error_at (loc, "invalid application of %<lengthof%> to type %qT", type);
+ return error_mark_node;
+ }
+
@@ gcc/c-family/c-common.def: DEFTREECODE (EXCESS_PRECISION_EXPR, "excess_precision
number. */
DEFTREECODE (USERDEF_LITERAL, "userdef_literal", tcc_exceptional, 3)
-+/* Represents a 'sizeof' expression during C++ template expansion,
-+ or for the purpose of -Wsizeof-pointer-memaccess warning. */
++/* Represents a 'lengthof' expression. */
+DEFTREECODE (LENGTHOF_EXPR, "lengthof_expr", tcc_expression, 1)
+
/* Represents a 'sizeof' expression during C++ template expansion,
@@ gcc/c-family/c-common.h: extern tree c_common_truthvalue_conversion (location_t,
NOP_EXPR is used as a special case (see truthvalue_conversion). */
extern void binary_op_error (rich_location *, enum tree_code, tree, tree);
+ ## gcc/c/c-decl.cc ##
+@@ gcc/c/c-decl.cc: start_struct (location_t loc, enum tree_code code, tree name,
+ within a statement expr used within sizeof, et. al. This is not
+ terribly serious as C++ doesn't permit statement exprs within
+ sizeof anyhow. */
+- if (warn_cxx_compat && (in_sizeof || in_typeof || in_alignof))
++ if (warn_cxx_compat && (in_sizeof || in_typeof || in_alignof || in_lengthof))
+ warning_at (loc, OPT_Wc___compat,
+ "defining type in %qs expression is invalid in C++",
+ (in_sizeof
+ ? "sizeof"
+- : (in_typeof ? "typeof" : "alignof")));
++ : (in_typeof
++ ? "typeof"
++ : (in_alignof
++ ? "alignof"
++ : "lengthof"))));
+
+ if (in_underspecified_init)
+ error_at (loc, "%qT defined in underspecified object initializer", ref);
+@@ gcc/c/c-decl.cc: finish_struct (location_t loc, tree t, tree fieldlist, tree attributes,
+ struct_types. */
+ if (warn_cxx_compat
+ && struct_parse_info != NULL
+- && !in_sizeof && !in_typeof && !in_alignof)
++ && !in_sizeof && !in_typeof && !in_alignof && !in_lengthof)
+ struct_parse_info->struct_types.safe_push (t);
+ }
+
+@@ gcc/c/c-decl.cc: start_enum (location_t loc, struct c_enum_contents *the_enum, tree name,
+ /* FIXME: This will issue a warning for a use of a type defined
+ within sizeof in a statement expr. This is not terribly serious
+ as C++ doesn't permit statement exprs within sizeof anyhow. */
+- if (warn_cxx_compat && (in_sizeof || in_typeof || in_alignof))
++ if (warn_cxx_compat && (in_sizeof || in_typeof || in_alignof || in_lengthof))
+ warning_at (loc, OPT_Wc___compat,
+ "defining type in %qs expression is invalid in C++",
+ (in_sizeof
+ ? "sizeof"
+- : (in_typeof ? "typeof" : "alignof")));
++ : (in_typeof
++ ? "typeof"
++ : (in_alignof
++ ? "alignof"
++ : "lengthof"))));
+
+ if (in_underspecified_init)
+ error_at (loc, "%qT defined in underspecified object initializer",
+@@ gcc/c/c-decl.cc: finish_enum (tree enumtype, tree values, tree attributes)
+ struct_types. */
+ if (warn_cxx_compat
+ && struct_parse_info != NULL
+- && !in_sizeof && !in_typeof && !in_alignof)
++ && !in_sizeof && !in_typeof && !in_alignof && !in_lengthof)
+ struct_parse_info->struct_types.safe_push (enumtype);
+
+ /* Check for consistency with previous definition */
+
## gcc/c/c-parser.cc ##
@@ gcc/c/c-parser.cc: along with GCC; see the file COPYING3. If not see
#include "bitmap.h"
@@ gcc/c/c-parser.cc: c_parser_unary_expression (c_parser *parser)
-c_parser_sizeof_expression (c_parser *parser)
+c_parser_sizeof_or_lengthof_expression (c_parser *parser, enum rid rid)
{
-+ const char *op_name = (rid == RID_SIZEOF) ? "sizeof" : "_Lengthof";
++ const char *op_name = (rid == RID_LENGTHOF) ? "lengthof" : "sizeof";
struct c_expr expr;
struct c_expr result;
location_t expr_loc;
@@ gcc/c/c-parser.cc: c_parser_unary_expression (c_parser *parser)
location_t start;
location_t finish = UNKNOWN_LOCATION;
@@ gcc/c/c-parser.cc: c_parser_sizeof_expression (c_parser *parser)
+
+ c_parser_consume_token (parser);
+ c_inhibit_evaluation_warnings++;
+- in_sizeof++;
++ if (rid == RID_LENGTHOF)
++ in_lengthof++;
++ else
++ in_sizeof++;
+ if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)
+ && c_token_starts_compound_literal (c_parser_peek_2nd_token (parser)))
+ {
+@@ gcc/c/c-parser.cc: c_parser_sizeof_expression (c_parser *parser)
+ {
+ struct c_expr ret;
+ c_inhibit_evaluation_warnings--;
+- in_sizeof--;
++ if (rid == RID_LENGTHOF)
++ in_lengthof--;
++ else
++ in_sizeof--;
+ ret.set_error ();
+ ret.original_code = ERROR_MARK;
+ ret.original_type = NULL;
+@@ gcc/c/c-parser.cc: c_parser_sizeof_expression (c_parser *parser)
+ type_name,
+ expr_loc);
+ finish = expr.get_finish ();
+- goto sizeof_expr;
++ goto Xof_expr;
}
/* sizeof ( type-name ). */
if (scspecs)
@@ gcc/c/c-parser.cc: c_parser_sizeof_expression (c_parser *parser)
- "alignment specified for type name in %<sizeof%>");
+ "alignment specified for type name in %qs", op_name);
c_inhibit_evaluation_warnings--;
- in_sizeof--;
+- in_sizeof--;
- result = c_expr_sizeof_type (expr_loc, type_name);
+ if (rid == RID_LENGTHOF)
-+ result = c_expr_lengthof_type (expr_loc, type_name);
++ {
++ in_lengthof--;
++ result = c_expr_lengthof_type (expr_loc, type_name);
++ }
+ else
-+ result = c_expr_sizeof_type (expr_loc, type_name);
++ {
++ in_sizeof--;
++ result = c_expr_sizeof_type (expr_loc, type_name);
++ }
}
else
{
-@@ gcc/c/c-parser.cc: c_parser_sizeof_expression (c_parser *parser)
+ expr_loc = c_parser_peek_token (parser)->location;
+ expr = c_parser_unary_expression (parser);
+ finish = expr.get_finish ();
+- sizeof_expr:
++ Xof_expr:
+ c_inhibit_evaluation_warnings--;
+- in_sizeof--;
++ if (rid == RID_LENGTHOF)
++ in_lengthof--;
++ else
++ in_sizeof--;
mark_exp_read (expr.value);
if (TREE_CODE (expr.value) == COMPONENT_REF
&& DECL_C_BIT_FIELD (TREE_OPERAND (expr.value, 1)))
@@ gcc/c/c-tree.h: extern tree build_external_ref (location_t, tree, bool, tree *);
extern struct c_expr parser_build_binary_op (location_t,
## gcc/c/c-typeck.cc ##
+@@ gcc/c/c-typeck.cc: int in_alignof;
+ /* The level of nesting inside "sizeof". */
+ int in_sizeof;
+
++/* The level of nesting inside "sizeof". */
++int in_lengthof;
++
+ /* The level of nesting inside "typeof". */
+ int in_typeof;
+
+@@ gcc/c/c-typeck.cc: build_external_ref (location_t loc, tree id, bool fun, tree *type)
+
+ if (TREE_CODE (ref) == FUNCTION_DECL && !in_alignof)
+ {
+- if (!in_sizeof && !in_typeof)
++ if (!in_sizeof && !in_typeof && !in_lengthof)
+ C_DECL_USED (ref) = 1;
+ else if (DECL_INITIAL (ref) == NULL_TREE
+ && DECL_EXTERNAL (ref)
+@@ gcc/c/c-typeck.cc: struct maybe_used_decl
+ {
+ /* The decl. */
+ tree decl;
+- /* The level seen at (in_sizeof + in_typeof). */
++ /* The level seen at (in_sizeof + in_typeof + in_lengthof). */
+ int level;
+ /* The next one at this level or above, or NULL. */
+ struct maybe_used_decl *next;
+@@ gcc/c/c-typeck.cc: record_maybe_used_decl (tree decl)
+ {
+ struct maybe_used_decl *t = XOBNEW (&parser_obstack, struct maybe_used_decl);
+ t->decl = decl;
+- t->level = in_sizeof + in_typeof;
++ t->level = in_sizeof + in_typeof + in_lengthof;
+ t->next = maybe_used_decls;
+ maybe_used_decls = t;
+ }
+@@ gcc/c/c-typeck.cc: void
+ pop_maybe_used (bool used)
+ {
+ struct maybe_used_decl *p = maybe_used_decls;
+- int cur_level = in_sizeof + in_typeof;
++ int cur_level = in_sizeof + in_typeof + in_lengthof;
+ while (p && p->level > cur_level)
+ {
+ if (used)
@@ gcc/c/c-typeck.cc: c_expr_sizeof_type (location_t loc, struct c_type_name *t)
return ret;
}
-+/* Return the result of _Lengthof applied to EXPR. */
++/* Return the result of lengthof applied to EXPR. */
+
+struct c_expr
+c_expr_lengthof_expr (location_t loc, struct c_expr expr)
@@ gcc/c/c-typeck.cc: c_expr_sizeof_type (location_t loc, struct c_type_name *t)
+ ret.m_decimal = 0;
+ if (C_TYPE_VARIABLE_SIZE (TREE_TYPE (folded_expr)))
+ {
-+ /* _Lengthof is evaluated when given a vla. */
++ /* lengthof is evaluated when given a vla. */
+ ret.value = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (ret.value),
+ folded_expr, ret.value);
+ C_MAYBE_CONST_EXPR_NON_CONST (ret.value) = !expr_const_operands;
@@ gcc/c/c-typeck.cc: c_expr_sizeof_type (location_t loc, struct c_type_name *t)
+ return ret;
+}
+
-+/* Return the result of _Lengthof applied to T, a structure for the type
++/* Return the result of lengthof applied to T, a structure for the type
+ name passed to _lengthof (rather than the type itself). LOC is the
+ location of the original expression. */
+
@@ gcc/c/c-typeck.cc: c_expr_sizeof_type (location_t loc, struct c_type_name *t)
+ {
+ /* 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
-+ the result of _Lengthof does not get folded to a constant by
++ the result of lengthof does not get folded to a constant by
+ c_fully_fold, because if the length is evaluated the result is
+ not constant and so constraints on zero or negative size
-+ arrays must not be applied when this _Lengthof call is inside
++ arrays must not be applied when this lengthof call is inside
+ another array declarator. */
+ if (!type_expr)
+ type_expr = integer_zero_node;
@@ gcc/cp/operators.def: DEF_OPERATOR ("co_await", CO_AWAIT_EXPR, "aw", OVL_OP_FLAG
/* These are extensions. */
DEF_OPERATOR ("alignof", ALIGNOF_EXPR, "az", OVL_OP_FLAG_UNARY)
-+DEF_OPERATOR ("lengthof", LENGTHOF_EXPR, "lz", OVL_OP_FLAG_UNARY)
++DEF_OPERATOR ("__lengthof__", LENGTHOF_EXPR, "lz", OVL_OP_FLAG_UNARY)
DEF_OPERATOR ("__imag__", IMAGPART_EXPR, "v18__imag__", OVL_OP_FLAG_UNARY)
DEF_OPERATOR ("__real__", REALPART_EXPR, "v18__real__", OVL_OP_FLAG_UNARY)
- ## gcc/ginclude/stdlength.h (new) ##
-@@
-+/* Copyright (C) 2024 Free Software Foundation, Inc.
-+
-+This file is part of GCC.
-+
-+GCC is free software; you can redistribute it and/or modify
-+it under the terms of the GNU General Public License as published by
-+the Free Software Foundation; either version 3, or (at your option)
-+any later version.
-+
-+GCC is distributed in the hope that it will be useful,
-+but WITHOUT ANY WARRANTY; without even the implied warranty of
-+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+GNU General Public License for more details.
-+
-+Under Section 7 of GPL version 3, you are granted additional
-+permissions described in the GCC Runtime Library Exception, version
-+3.1, as published by the Free Software Foundation.
-+
-+You should have received a copy of the GNU General Public License and
-+a copy of the GCC Runtime Library Exception along with this program;
-+see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
-+<http://www.gnu.org/licenses/>. */
-+
-+#ifndef _STDLENGTH_H
-+#define _STDLENGTH_H
-+
-+#if (!defined __cplusplus)
-+
-+#define lengthof _Lengthof
-+
-+#define __lengthof_is_defined 1
-+
-+#endif
-+
-+#endif /* stdlength.h */
-
## gcc/target.h ##
@@ gcc/target.h: enum type_context_kind {
/* Directly measuring the alignment of T. */
--
2.45.2
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 248+ messages in thread
* [RFC v2 1/2] Merge definitions of array_type_nelts_top()
2024-07-28 16:48 ` [RFC v2 0/2] c: Add __lengthof__ operator Alejandro Colomar
@ 2024-07-28 16:48 ` Alejandro Colomar
2024-07-28 16:48 ` [RFC v2 2/2] c: Add __lengthof__() operator Alejandro Colomar
1 sibling, 0 replies; 248+ messages in thread
From: Alejandro Colomar @ 2024-07-28 16:48 UTC (permalink / raw)
To: gcc-patches
Cc: Alejandro Colomar, Gabriel Ravier, Martin Uecker, Joseph Myers
[-- Attachment #1: Type: text/plain, Size: 4377 bytes --]
There were two identical definitions, and none of them are available
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().
Signed-off-by: Alejandro Colomar <alx@kernel.org>
---
gcc/cp/cp-tree.h | 1 -
gcc/cp/tree.cc | 13 -------------
gcc/rust/backend/rust-tree.cc | 13 -------------
gcc/rust/backend/rust-tree.h | 2 --
gcc/tree.cc | 13 +++++++++++++
gcc/tree.h | 1 +
6 files changed, 14 insertions(+), 29 deletions(-)
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index c1a371bc721..e6c1c63f872 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -8099,7 +8099,6 @@ extern tree build_exception_variant (tree, tree);
extern void fixup_deferred_exception_variants (tree, tree);
extern tree bind_template_template_parm (tree, tree);
extern tree array_type_nelts_total (tree);
-extern tree array_type_nelts_top (tree);
extern bool array_of_unknown_bound_p (const_tree);
extern tree break_out_target_exprs (tree, bool = false);
extern tree build_ctor_subob_ref (tree, tree, tree);
diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
index dfd4a3a948b..1f3ecff1a21 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -3071,19 +3071,6 @@ cxx_print_statistics (void)
depth_reached);
}
-/* Return, as an INTEGER_CST node, the number of elements for TYPE
- (which is an ARRAY_TYPE). This counts only elements of the top
- array. */
-
-tree
-array_type_nelts_top (tree type)
-{
- return fold_build2_loc (input_location,
- PLUS_EXPR, sizetype,
- array_type_nelts (type),
- size_one_node);
-}
-
/* Return, as an INTEGER_CST node, the number of elements for TYPE
(which is an ARRAY_TYPE). This one is a recursive count of all
ARRAY_TYPEs that are clumped together. */
diff --git a/gcc/rust/backend/rust-tree.cc b/gcc/rust/backend/rust-tree.cc
index 2a5ffcbf895..dd8eda84f9b 100644
--- a/gcc/rust/backend/rust-tree.cc
+++ b/gcc/rust/backend/rust-tree.cc
@@ -859,19 +859,6 @@ is_empty_class (tree type)
return CLASSTYPE_EMPTY_P (type);
}
-// forked from gcc/cp/tree.cc array_type_nelts_top
-
-/* Return, as an INTEGER_CST node, the number of elements for TYPE
- (which is an ARRAY_TYPE). This counts only elements of the top
- array. */
-
-tree
-array_type_nelts_top (tree type)
-{
- return fold_build2_loc (input_location, PLUS_EXPR, sizetype,
- array_type_nelts (type), size_one_node);
-}
-
// forked from gcc/cp/tree.cc builtin_valid_in_constant_expr_p
/* Test whether DECL is a builtin that may appear in a
diff --git a/gcc/rust/backend/rust-tree.h b/gcc/rust/backend/rust-tree.h
index 26c8b653ac6..e597c3ab81d 100644
--- a/gcc/rust/backend/rust-tree.h
+++ b/gcc/rust/backend/rust-tree.h
@@ -2993,8 +2993,6 @@ extern location_t rs_expr_location (const_tree);
extern int
is_empty_class (tree type);
-extern tree array_type_nelts_top (tree);
-
extern bool
is_really_empty_class (tree, bool);
diff --git a/gcc/tree.cc b/gcc/tree.cc
index 2d2d5b6db6e..3b0adb4cd9f 100644
--- a/gcc/tree.cc
+++ b/gcc/tree.cc
@@ -3729,6 +3729,19 @@ array_type_nelts (const_tree type)
? max
: fold_build2 (MINUS_EXPR, TREE_TYPE (max), max, min));
}
+
+/* Return, as an INTEGER_CST node, the number of elements for TYPE
+ (which is an ARRAY_TYPE). This counts only elements of the top
+ array. */
+
+tree
+array_type_nelts_top (tree type)
+{
+ return fold_build2_loc (input_location,
+ PLUS_EXPR, sizetype,
+ array_type_nelts (type),
+ size_one_node);
+}
\f
/* If arg is static -- a reference to an object in static storage -- then
return the object. This is not the same as the C meaning of `static'.
diff --git a/gcc/tree.h b/gcc/tree.h
index 28e8e71b036..c620e55b68d 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -4922,6 +4922,7 @@ 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_top (tree);
extern tree value_member (tree, tree);
extern tree purpose_member (const_tree, tree);
--
2.45.2
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 248+ messages in thread
* [RFC v2 2/2] c: Add __lengthof__() operator
2024-07-28 16:48 ` [RFC v2 0/2] c: Add __lengthof__ operator Alejandro Colomar
2024-07-28 16:48 ` [RFC v2 1/2] Merge definitions of array_type_nelts_top() Alejandro Colomar
@ 2024-07-28 16:48 ` Alejandro Colomar
1 sibling, 0 replies; 248+ messages in thread
From: Alejandro Colomar @ 2024-07-28 16:48 UTC (permalink / raw)
To: gcc-patches
Cc: Alejandro Colomar, Gabriel Ravier, Martin Uecker, Joseph Myers
[-- Attachment #1: Type: text/plain, Size: 18323 bytes --]
This operator is similar to sizeof() but can only be applied to an
array, and returns its length (number of elements).
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.
Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2529.pdf>
Cc: Gabriel Ravier <gabravier@gmail.com>
Cc: Martin Uecker <uecker@tugraz.at>
Cc: Joseph Myers <josmyers@redhat.com>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
---
gcc/c-family/c-common.cc | 19 ++++++++
gcc/c-family/c-common.def | 3 ++
gcc/c-family/c-common.h | 2 +
gcc/c/c-decl.cc | 20 ++++++---
gcc/c/c-parser.cc | 61 +++++++++++++++++++------
gcc/c/c-tree.h | 4 ++
gcc/c/c-typeck.cc | 95 +++++++++++++++++++++++++++++++++++++--
gcc/cp/operators.def | 1 +
gcc/target.h | 3 ++
9 files changed, 184 insertions(+), 24 deletions(-)
diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
index e7e371fd26f..c0d6239c1f8 100644
--- a/gcc/c-family/c-common.cc
+++ b/gcc/c-family/c-common.cc
@@ -465,6 +465,7 @@ const struct c_common_resword c_common_reswords[] =
{ "__inline", RID_INLINE, 0 },
{ "__inline__", RID_INLINE, 0 },
{ "__label__", RID_LABEL, 0 },
+ { "__lengthof__", RID_LENGTHOF, 0 },
{ "__null", RID_NULL, 0 },
{ "__real", RID_REALPART, 0 },
{ "__real__", RID_REALPART, 0 },
@@ -4070,6 +4071,24 @@ c_alignof_expr (location_t loc, tree expr)
return fold_convert_loc (loc, size_type_node, t);
}
+
+/* Implement the lengthof keyword: Return the length of an array,
+ that is, the number of elements in the array. */
+
+tree
+c_lengthof_type (location_t loc, tree type)
+{
+ 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;
+ }
+
+ return array_type_nelts_top (type);
+}
\f
/* Handle C and C++ default attributes. */
diff --git a/gcc/c-family/c-common.def b/gcc/c-family/c-common.def
index 5de96e5d4a8..6d162f67104 100644
--- a/gcc/c-family/c-common.def
+++ b/gcc/c-family/c-common.def
@@ -50,6 +50,9 @@ DEFTREECODE (EXCESS_PRECISION_EXPR, "excess_precision_expr", tcc_expression, 1)
number. */
DEFTREECODE (USERDEF_LITERAL, "userdef_literal", tcc_exceptional, 3)
+/* Represents a 'lengthof' expression. */
+DEFTREECODE (LENGTHOF_EXPR, "lengthof_expr", tcc_expression, 1)
+
/* Represents a 'sizeof' expression during C++ template expansion,
or for the purpose of -Wsizeof-pointer-memaccess warning. */
DEFTREECODE (SIZEOF_EXPR, "sizeof_expr", tcc_expression, 1)
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index ccaea27c2b9..f815a4cf3bc 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -105,6 +105,7 @@ enum rid
/* C extensions */
RID_ASM, RID_TYPEOF, RID_TYPEOF_UNQUAL, RID_ALIGNOF, RID_ATTRIBUTE,
+ RID_LENGTHOF,
RID_VA_ARG,
RID_EXTENSION, RID_IMAGPART, RID_REALPART, RID_LABEL, RID_CHOOSE_EXPR,
RID_TYPES_COMPATIBLE_P, RID_BUILTIN_COMPLEX, RID_BUILTIN_SHUFFLE,
@@ -885,6 +886,7 @@ extern tree c_common_truthvalue_conversion (location_t, tree);
extern void c_apply_type_quals_to_decl (int, tree);
extern tree c_sizeof_or_alignof_type (location_t, tree, bool, bool, int);
extern tree c_alignof_expr (location_t, tree);
+extern tree c_lengthof_type (location_t, tree);
/* Print an error message for invalid operands to arith operation CODE.
NOP_EXPR is used as a special case (see truthvalue_conversion). */
extern void binary_op_error (rich_location *, enum tree_code, tree, tree);
diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 97f1d346835..1836151fc41 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -8937,12 +8937,16 @@ start_struct (location_t loc, enum tree_code code, tree name,
within a statement expr used within sizeof, et. al. This is not
terribly serious as C++ doesn't permit statement exprs within
sizeof anyhow. */
- if (warn_cxx_compat && (in_sizeof || in_typeof || in_alignof))
+ if (warn_cxx_compat && (in_sizeof || in_typeof || in_alignof || in_lengthof))
warning_at (loc, OPT_Wc___compat,
"defining type in %qs expression is invalid in C++",
(in_sizeof
? "sizeof"
- : (in_typeof ? "typeof" : "alignof")));
+ : (in_typeof
+ ? "typeof"
+ : (in_alignof
+ ? "alignof"
+ : "lengthof"))));
if (in_underspecified_init)
error_at (loc, "%qT defined in underspecified object initializer", ref);
@@ -9897,7 +9901,7 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes,
struct_types. */
if (warn_cxx_compat
&& struct_parse_info != NULL
- && !in_sizeof && !in_typeof && !in_alignof)
+ && !in_sizeof && !in_typeof && !in_alignof && !in_lengthof)
struct_parse_info->struct_types.safe_push (t);
}
@@ -10071,12 +10075,16 @@ start_enum (location_t loc, struct c_enum_contents *the_enum, tree name,
/* FIXME: This will issue a warning for a use of a type defined
within sizeof in a statement expr. This is not terribly serious
as C++ doesn't permit statement exprs within sizeof anyhow. */
- if (warn_cxx_compat && (in_sizeof || in_typeof || in_alignof))
+ if (warn_cxx_compat && (in_sizeof || in_typeof || in_alignof || in_lengthof))
warning_at (loc, OPT_Wc___compat,
"defining type in %qs expression is invalid in C++",
(in_sizeof
? "sizeof"
- : (in_typeof ? "typeof" : "alignof")));
+ : (in_typeof
+ ? "typeof"
+ : (in_alignof
+ ? "alignof"
+ : "lengthof"))));
if (in_underspecified_init)
error_at (loc, "%qT defined in underspecified object initializer",
@@ -10270,7 +10278,7 @@ finish_enum (tree enumtype, tree values, tree attributes)
struct_types. */
if (warn_cxx_compat
&& struct_parse_info != NULL
- && !in_sizeof && !in_typeof && !in_alignof)
+ && !in_sizeof && !in_typeof && !in_alignof && !in_lengthof)
struct_parse_info->struct_types.safe_push (enumtype);
/* Check for consistency with previous definition */
diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
index 12c5ed5d92c..09bb19f9299 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -74,7 +74,17 @@ along with GCC; see the file COPYING3. If not see
#include "bitmap.h"
#include "analyzer/analyzer-language.h"
#include "toplev.h"
+\f
+#define c_parser_sizeof_expression(parser) \
+( \
+ c_parser_sizeof_or_lengthof_expression (parser, RID_SIZEOF) \
+)
+#define c_parser_lengthof_expression(parser) \
+( \
+ c_parser_sizeof_or_lengthof_expression (parser, RID_LENGTHOF) \
+)
+\f
/* We need to walk over decls with incomplete struct/union/enum types
after parsing the whole translation unit.
In finish_decl(), if the decl is static, has incomplete
@@ -1687,7 +1697,7 @@ static struct c_expr c_parser_binary_expression (c_parser *, struct c_expr *,
tree);
static struct c_expr c_parser_cast_expression (c_parser *, struct c_expr *);
static struct c_expr c_parser_unary_expression (c_parser *);
-static struct c_expr c_parser_sizeof_expression (c_parser *);
+static struct c_expr c_parser_sizeof_or_lengthof_expression (c_parser *, enum rid);
static struct c_expr c_parser_alignof_expression (c_parser *);
static struct c_expr c_parser_postfix_expression (c_parser *);
static struct c_expr c_parser_postfix_expression_after_paren_type (c_parser *,
@@ -9864,6 +9874,8 @@ c_parser_unary_expression (c_parser *parser)
case CPP_KEYWORD:
switch (c_parser_peek_token (parser)->keyword)
{
+ case RID_LENGTHOF:
+ return c_parser_lengthof_expression (parser);
case RID_SIZEOF:
return c_parser_sizeof_expression (parser);
case RID_ALIGNOF:
@@ -9903,12 +9915,13 @@ c_parser_unary_expression (c_parser *parser)
/* Parse a sizeof expression. */
static struct c_expr
-c_parser_sizeof_expression (c_parser *parser)
+c_parser_sizeof_or_lengthof_expression (c_parser *parser, enum rid rid)
{
+ const char *op_name = (rid == RID_LENGTHOF) ? "lengthof" : "sizeof";
struct c_expr expr;
struct c_expr result;
location_t expr_loc;
- gcc_assert (c_parser_next_token_is_keyword (parser, RID_SIZEOF));
+ gcc_assert (c_parser_next_token_is_keyword (parser, rid));
location_t start;
location_t finish = UNKNOWN_LOCATION;
@@ -9917,7 +9930,10 @@ c_parser_sizeof_expression (c_parser *parser)
c_parser_consume_token (parser);
c_inhibit_evaluation_warnings++;
- in_sizeof++;
+ if (rid == RID_LENGTHOF)
+ in_lengthof++;
+ else
+ in_sizeof++;
if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)
&& c_token_starts_compound_literal (c_parser_peek_2nd_token (parser)))
{
@@ -9936,7 +9952,10 @@ c_parser_sizeof_expression (c_parser *parser)
{
struct c_expr ret;
c_inhibit_evaluation_warnings--;
- in_sizeof--;
+ if (rid == RID_LENGTHOF)
+ in_lengthof--;
+ else
+ in_sizeof--;
ret.set_error ();
ret.original_code = ERROR_MARK;
ret.original_type = NULL;
@@ -9948,31 +9967,45 @@ c_parser_sizeof_expression (c_parser *parser)
type_name,
expr_loc);
finish = expr.get_finish ();
- goto sizeof_expr;
+ goto Xof_expr;
}
/* sizeof ( type-name ). */
if (scspecs)
- error_at (expr_loc, "storage class specifier in %<sizeof%>");
+ error_at (expr_loc, "storage class specifier in %qs", op_name);
if (type_name->specs->alignas_p)
error_at (type_name->specs->locations[cdw_alignas],
- "alignment specified for type name in %<sizeof%>");
+ "alignment specified for type name in %qs", op_name);
c_inhibit_evaluation_warnings--;
- in_sizeof--;
- result = c_expr_sizeof_type (expr_loc, type_name);
+ if (rid == RID_LENGTHOF)
+ {
+ in_lengthof--;
+ result = c_expr_lengthof_type (expr_loc, type_name);
+ }
+ else
+ {
+ in_sizeof--;
+ result = c_expr_sizeof_type (expr_loc, type_name);
+ }
}
else
{
expr_loc = c_parser_peek_token (parser)->location;
expr = c_parser_unary_expression (parser);
finish = expr.get_finish ();
- sizeof_expr:
+ Xof_expr:
c_inhibit_evaluation_warnings--;
- in_sizeof--;
+ if (rid == RID_LENGTHOF)
+ in_lengthof--;
+ else
+ in_sizeof--;
mark_exp_read (expr.value);
if (TREE_CODE (expr.value) == COMPONENT_REF
&& DECL_C_BIT_FIELD (TREE_OPERAND (expr.value, 1)))
- error_at (expr_loc, "%<sizeof%> applied to a bit-field");
- result = c_expr_sizeof_expr (expr_loc, expr);
+ error_at (expr_loc, "%qs applied to a bit-field", op_name);
+ if (rid == RID_LENGTHOF)
+ result = c_expr_lengthof_expr (expr_loc, expr);
+ else
+ result = c_expr_sizeof_expr (expr_loc, expr);
}
if (finish == UNKNOWN_LOCATION)
finish = start;
diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h
index 15da875a029..102fcfefea6 100644
--- a/gcc/c/c-tree.h
+++ b/gcc/c/c-tree.h
@@ -736,6 +736,7 @@ extern int c_type_dwarf_attribute (const_tree, int);
/* in c-typeck.cc */
extern int in_alignof;
extern int in_sizeof;
+extern int in_lengthof;
extern int in_typeof;
extern bool c_in_omp_for;
extern bool c_omp_array_section_p;
@@ -786,6 +787,9 @@ extern tree build_external_ref (location_t, tree, bool, tree *);
extern void pop_maybe_used (bool);
extern struct c_expr c_expr_sizeof_expr (location_t, struct c_expr);
extern struct c_expr c_expr_sizeof_type (location_t, struct c_type_name *);
+extern struct c_expr c_expr_lengthof_expr (location_t, struct c_expr);
+extern struct c_expr c_expr_lengthof_type (location_t loc,
+ struct c_type_name *);
extern struct c_expr parser_build_unary_op (location_t, enum tree_code,
struct c_expr);
extern struct c_expr parser_build_binary_op (location_t,
diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index 7e0f01ed22b..121e74de25d 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -71,6 +71,9 @@ int in_alignof;
/* The level of nesting inside "sizeof". */
int in_sizeof;
+/* The level of nesting inside "sizeof". */
+int in_lengthof;
+
/* The level of nesting inside "typeof". */
int in_typeof;
@@ -3255,7 +3258,7 @@ build_external_ref (location_t loc, tree id, bool fun, tree *type)
if (TREE_CODE (ref) == FUNCTION_DECL && !in_alignof)
{
- if (!in_sizeof && !in_typeof)
+ if (!in_sizeof && !in_typeof && !in_lengthof)
C_DECL_USED (ref) = 1;
else if (DECL_INITIAL (ref) == NULL_TREE
&& DECL_EXTERNAL (ref)
@@ -3311,7 +3314,7 @@ struct maybe_used_decl
{
/* The decl. */
tree decl;
- /* The level seen at (in_sizeof + in_typeof). */
+ /* The level seen at (in_sizeof + in_typeof + in_lengthof). */
int level;
/* The next one at this level or above, or NULL. */
struct maybe_used_decl *next;
@@ -3329,7 +3332,7 @@ record_maybe_used_decl (tree decl)
{
struct maybe_used_decl *t = XOBNEW (&parser_obstack, struct maybe_used_decl);
t->decl = decl;
- t->level = in_sizeof + in_typeof;
+ t->level = in_sizeof + in_typeof + in_lengthof;
t->next = maybe_used_decls;
maybe_used_decls = t;
}
@@ -3343,7 +3346,7 @@ void
pop_maybe_used (bool used)
{
struct maybe_used_decl *p = maybe_used_decls;
- int cur_level = in_sizeof + in_typeof;
+ int cur_level = in_sizeof + in_typeof + in_lengthof;
while (p && p->level > cur_level)
{
if (used)
@@ -3453,6 +3456,90 @@ c_expr_sizeof_type (location_t loc, struct c_type_name *t)
return ret;
}
+/* Return the result of lengthof applied to EXPR. */
+
+struct c_expr
+c_expr_lengthof_expr (location_t loc, struct c_expr expr)
+{
+ struct c_expr ret;
+ if (expr.value == error_mark_node)
+ {
+ ret.value = error_mark_node;
+ ret.original_code = ERROR_MARK;
+ ret.original_type = NULL;
+ ret.m_decimal = 0;
+ pop_maybe_used (false);
+ }
+ else
+ {
+ bool expr_const_operands = true;
+
+ tree folded_expr = c_fully_fold (expr.value, require_constant_value,
+ &expr_const_operands);
+ ret.value = c_lengthof_type (loc, TREE_TYPE (folded_expr));
+ c_last_sizeof_arg = expr.value;
+ c_last_sizeof_loc = loc;
+ ret.original_code = LENGTHOF_EXPR;
+ ret.original_type = NULL;
+ ret.m_decimal = 0;
+ if (C_TYPE_VARIABLE_SIZE (TREE_TYPE (folded_expr)))
+ {
+ /* lengthof is evaluated when given a vla. */
+ ret.value = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (ret.value),
+ folded_expr, ret.value);
+ 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)));
+ }
+ return ret;
+}
+
+/* Return the result of lengthof applied to T, a structure for the type
+ name passed to _lengthof (rather than the type itself). LOC is the
+ location of the original expression. */
+
+struct c_expr
+c_expr_lengthof_type (location_t loc, struct c_type_name *t)
+{
+ tree type;
+ struct c_expr ret;
+ tree type_expr = NULL_TREE;
+ bool type_expr_const = true;
+ type = groktypename (t, &type_expr, &type_expr_const);
+ ret.value = c_lengthof_type (loc, type);
+ c_last_sizeof_arg = type;
+ c_last_sizeof_loc = loc;
+ ret.original_code = LENGTHOF_EXPR;
+ ret.original_type = NULL;
+ ret.m_decimal = 0;
+ if (type == error_mark_node)
+ {
+ ret.value = error_mark_node;
+ ret.original_code = ERROR_MARK;
+ }
+ else
+ if ((type_expr || TREE_CODE (ret.value) == INTEGER_CST)
+ && C_TYPE_VARIABLE_SIZE (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
+ the result of lengthof does not get folded to a constant by
+ c_fully_fold, because if the length is evaluated the result is
+ not constant and so constraints on zero or negative size
+ arrays must not be applied when this lengthof call is inside
+ another array declarator. */
+ if (!type_expr)
+ type_expr = integer_zero_node;
+ ret.value = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (ret.value),
+ 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);
+ return ret;
+}
+
/* Build a function call to function FUNCTION with parameters PARAMS.
The function call is at LOC.
PARAMS is a list--a chain of TREE_LIST nodes--in which the
diff --git a/gcc/cp/operators.def b/gcc/cp/operators.def
index d8878923602..d640ed8bd91 100644
--- a/gcc/cp/operators.def
+++ b/gcc/cp/operators.def
@@ -91,6 +91,7 @@ DEF_OPERATOR ("co_await", CO_AWAIT_EXPR, "aw", OVL_OP_FLAG_UNARY)
/* These are extensions. */
DEF_OPERATOR ("alignof", ALIGNOF_EXPR, "az", OVL_OP_FLAG_UNARY)
+DEF_OPERATOR ("__lengthof__", LENGTHOF_EXPR, "lz", OVL_OP_FLAG_UNARY)
DEF_OPERATOR ("__imag__", IMAGPART_EXPR, "v18__imag__", OVL_OP_FLAG_UNARY)
DEF_OPERATOR ("__real__", REALPART_EXPR, "v18__real__", OVL_OP_FLAG_UNARY)
diff --git a/gcc/target.h b/gcc/target.h
index c1f99b97b86..79890ae9944 100644
--- a/gcc/target.h
+++ b/gcc/target.h
@@ -245,6 +245,9 @@ enum type_context_kind {
/* Directly measuring the alignment of T. */
TCTX_ALIGNOF,
+ /* Directly measuring the length of array T. */
+ TCTX_LENGTHOF,
+
/* Creating objects of type T with static storage duration. */
TCTX_STATIC_STORAGE,
--
2.45.2
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [RFC v1 1/2] Merge definitions of array_type_nelts_top()
2024-07-28 14:15 ` [RFC v1 1/2] Merge definitions of array_type_nelts_top() Alejandro Colomar
@ 2024-07-29 8:27 ` Richard Biener
2024-07-29 8:55 ` Alejandro Colomar
0 siblings, 1 reply; 248+ messages in thread
From: Richard Biener @ 2024-07-29 8:27 UTC (permalink / raw)
To: Alejandro Colomar
Cc: gcc-patches, Gabriel Ravier, Martin Uecker, Joseph Myers
On Sun, Jul 28, 2024 at 4:16 PM Alejandro Colomar <alx@kernel.org> wrote:
>
> There were two identical definitions, and none of them are available
> 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().
>
> Signed-off-by: Alejandro Colomar <alx@kernel.org>
> ---
> gcc/cp/cp-tree.h | 1 -
> gcc/cp/tree.cc | 13 -------------
> gcc/rust/backend/rust-tree.cc | 13 -------------
> gcc/rust/backend/rust-tree.h | 2 --
> gcc/tree.cc | 13 +++++++++++++
> gcc/tree.h | 1 +
> 6 files changed, 14 insertions(+), 29 deletions(-)
>
> diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
> index c1a371bc721..e6c1c63f872 100644
> --- a/gcc/cp/cp-tree.h
> +++ b/gcc/cp/cp-tree.h
> @@ -8099,7 +8099,6 @@ extern tree build_exception_variant (tree, tree);
> extern void fixup_deferred_exception_variants (tree, tree);
> extern tree bind_template_template_parm (tree, tree);
> extern tree array_type_nelts_total (tree);
> -extern tree array_type_nelts_top (tree);
> extern bool array_of_unknown_bound_p (const_tree);
> extern tree break_out_target_exprs (tree, bool = false);
> extern tree build_ctor_subob_ref (tree, tree, tree);
> diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
> index dfd4a3a948b..1f3ecff1a21 100644
> --- a/gcc/cp/tree.cc
> +++ b/gcc/cp/tree.cc
> @@ -3071,19 +3071,6 @@ cxx_print_statistics (void)
> depth_reached);
> }
>
> -/* Return, as an INTEGER_CST node, the number of elements for TYPE
> - (which is an ARRAY_TYPE). This counts only elements of the top
> - array. */
> -
> -tree
> -array_type_nelts_top (tree type)
> -{
> - return fold_build2_loc (input_location,
> - PLUS_EXPR, sizetype,
> - array_type_nelts (type),
> - size_one_node);
> -}
> -
> /* Return, as an INTEGER_CST node, the number of elements for TYPE
> (which is an ARRAY_TYPE). This one is a recursive count of all
> ARRAY_TYPEs that are clumped together. */
> diff --git a/gcc/rust/backend/rust-tree.cc b/gcc/rust/backend/rust-tree.cc
> index 2a5ffcbf895..dd8eda84f9b 100644
> --- a/gcc/rust/backend/rust-tree.cc
> +++ b/gcc/rust/backend/rust-tree.cc
> @@ -859,19 +859,6 @@ is_empty_class (tree type)
> return CLASSTYPE_EMPTY_P (type);
> }
>
> -// forked from gcc/cp/tree.cc array_type_nelts_top
> -
> -/* Return, as an INTEGER_CST node, the number of elements for TYPE
> - (which is an ARRAY_TYPE). This counts only elements of the top
> - array. */
> -
> -tree
> -array_type_nelts_top (tree type)
> -{
> - return fold_build2_loc (input_location, PLUS_EXPR, sizetype,
> - array_type_nelts (type), size_one_node);
> -}
> -
> // forked from gcc/cp/tree.cc builtin_valid_in_constant_expr_p
>
> /* Test whether DECL is a builtin that may appear in a
> diff --git a/gcc/rust/backend/rust-tree.h b/gcc/rust/backend/rust-tree.h
> index 26c8b653ac6..e597c3ab81d 100644
> --- a/gcc/rust/backend/rust-tree.h
> +++ b/gcc/rust/backend/rust-tree.h
> @@ -2993,8 +2993,6 @@ extern location_t rs_expr_location (const_tree);
> extern int
> is_empty_class (tree type);
>
> -extern tree array_type_nelts_top (tree);
> -
> extern bool
> is_really_empty_class (tree, bool);
>
> diff --git a/gcc/tree.cc b/gcc/tree.cc
> index 2d2d5b6db6e..3b0adb4cd9f 100644
> --- a/gcc/tree.cc
> +++ b/gcc/tree.cc
> @@ -3729,6 +3729,19 @@ array_type_nelts (const_tree type)
> ? max
> : fold_build2 (MINUS_EXPR, TREE_TYPE (max), max, min));
> }
> +
> +/* Return, as an INTEGER_CST node, the number of elements for TYPE
> + (which is an ARRAY_TYPE). This counts only elements of the top
> + array. */
> +
> +tree
> +array_type_nelts_top (tree type)
> +{
> + return fold_build2_loc (input_location,
> + PLUS_EXPR, sizetype,
> + array_type_nelts (type),
> + size_one_node);
> +}
But this is now extremely confusing API with array_type_nelts above this
saying
/* Return, as a tree node, the number of elements for TYPE (which is an
ARRAY_TYPE) minus one. This counts only elements of the top array. */
so both are "_top". And there's build_array_type_nelts that's taking
the number of elements.
Can you please rename the existing array_type_nelts to
array_type_nelts_minus_one? Then _top could be dropped as well from
the alternate API you add.
I'll also note since array_type_nelts_top calls the other function and that has
/* If they did it with unspecified bounds, then we should have already
given an error about it before we got here. */
if (! TYPE_DOMAIN (type))
return error_mark_node;
the function should handle error_mark_node (and pass that down).
Note array_type_nelts returns nelts - 1 because that avoids building
a new tree node for arrays with lower bound zero.
Thanks,
Richard.
> /* If arg is static -- a reference to an object in static storage -- then
> return the object. This is not the same as the C meaning of `static'.
> diff --git a/gcc/tree.h b/gcc/tree.h
> index 28e8e71b036..c620e55b68d 100644
> --- a/gcc/tree.h
> +++ b/gcc/tree.h
> @@ -4922,6 +4922,7 @@ 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_top (tree);
>
> extern tree value_member (tree, tree);
> extern tree purpose_member (const_tree, tree);
> --
> 2.45.2
>
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [RFC v1 1/2] Merge definitions of array_type_nelts_top()
2024-07-29 8:27 ` Richard Biener
@ 2024-07-29 8:55 ` Alejandro Colomar
2024-07-29 9:08 ` Richard Biener
0 siblings, 1 reply; 248+ messages in thread
From: Alejandro Colomar @ 2024-07-29 8:55 UTC (permalink / raw)
To: Richard Biener; +Cc: gcc-patches, Gabriel Ravier, Martin Uecker, Joseph Myers
[-- Attachment #1: Type: text/plain, Size: 5737 bytes --]
Hi Richard,
On Mon, Jul 29, 2024 at 10:27:35AM GMT, Richard Biener wrote:
> On Sun, Jul 28, 2024 at 4:16 PM Alejandro Colomar <alx@kernel.org> wrote:
> >
> > There were two identical definitions, and none of them are available
> > 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().
> >
> > Signed-off-by: Alejandro Colomar <alx@kernel.org>
> > ---
> > gcc/cp/cp-tree.h | 1 -
> > gcc/cp/tree.cc | 13 -------------
> > gcc/rust/backend/rust-tree.cc | 13 -------------
> > gcc/rust/backend/rust-tree.h | 2 --
> > gcc/tree.cc | 13 +++++++++++++
> > gcc/tree.h | 1 +
> > 6 files changed, 14 insertions(+), 29 deletions(-)
> >
[...]
> > diff --git a/gcc/tree.cc b/gcc/tree.cc
> > index 2d2d5b6db6e..3b0adb4cd9f 100644
> > --- a/gcc/tree.cc
> > +++ b/gcc/tree.cc
> > @@ -3729,6 +3729,19 @@ array_type_nelts (const_tree type)
> > ? max
> > : fold_build2 (MINUS_EXPR, TREE_TYPE (max), max, min));
> > }
> > +
> > +/* Return, as an INTEGER_CST node, the number of elements for TYPE
> > + (which is an ARRAY_TYPE). This counts only elements of the top
> > + array. */
> > +
> > +tree
> > +array_type_nelts_top (tree type)
> > +{
> > + return fold_build2_loc (input_location,
> > + PLUS_EXPR, sizetype,
> > + array_type_nelts (type),
> > + size_one_node);
> > +}
>
> But this is now extremely confusing API with array_type_nelts above this
> saying
>
> /* Return, as a tree node, the number of elements for TYPE (which is an
> ARRAY_TYPE) minus one. This counts only elements of the top array. */
>
> so both are "_top". And there's build_array_type_nelts that's taking
> the number of elements.
>
> Can you please rename the existing array_type_nelts to
> array_type_nelts_minus_one? Then _top could be dropped as well from
> the alternate API you add.
I wanted to do that, but then I found other functions that are named
similarly, such as build_array_type_nelts(), and thought that I wasn't
sure if all of them should be renamed to _minus_one, or just some. So
I decided to start without renaming.
But yeah, I think I should rename. I'll prepare a patch for renaming it
independently of this patch set, and send it to be merged before this
patch set.
> I'll also note since array_type_nelts_top calls the other function and that has
>
> /* If they did it with unspecified bounds, then we should have already
> given an error about it before we got here. */
> if (! TYPE_DOMAIN (type))
> return error_mark_node;
>
> the function should handle error_mark_node (and pass that down).
Hmmmm, now I understand that (! TYPE_DOMAIN (type))
$ grep -rn return.array_type_nelts gcc
gcc/cp/call.cc:12111: return array_type_nelts_top (c->type);
gcc/c-family/c-common.cc:4090: return array_type_nelts_top (type);
$ sed -n 12102,12119p gcc/cp/call.cc
/* Return a tree representing the number of elements initialized by the
list-initialization C. The caller must check that C converts to an
array type. */
static tree
nelts_initialized_by_list_init (conversion *c)
{
/* If the array we're converting to has a dimension, we'll use that. */
if (TYPE_DOMAIN (c->type))
return array_type_nelts_top (c->type);
else
{
/* Otherwise, we look at how many elements the constructor we're
initializing from has. */
tree ctor = conv_get_original_expr (c);
return size_int (CONSTRUCTOR_NELTS (ctor));
}
}
It seems that would fail when measuring for example
#define memberof(T, member) ((T){}.member)
struct s {
int x;
int a[];
};
__lengthof__(memberof(struct s, a));
I guess?
$ cat len.c
#include <stdio.h>
#define memberof(T, member) ((T){}.member)
struct s {
int x;
int y[];
};
int
main(int argc, char *argv[argc + 1])
{
int a[42];
size_t n;
(void) argv;
//n = __lengthof__(argv);
//printf("__lengthof__(argv) == %zu\n", n);
n = __lengthof__(a);
printf("lengthof(a):\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);
n = __lengthof__(memberof(struct s, y));
printf("lengthof(memberof(struct s, y)):\t %zu\n", n);
}
alx@debian:~/tmp/gcc$ /opt/local/gnu/gcc/lengthof/bin/gcc len.c
alx@debian:~/tmp/gcc$ ./a.out
lengthof(a): 42
lengthof(long [99]): 99
lengthof(short [n - 10]): 89
lengthof(b): 44
lengthof(memberof(struct s, y)): 44
Indeed, it's misbehaving. I'll have a look at that. I'll probably have
to add an error similar to sizeof's one:
len.c: In function ‘main’:
len.c:37:19: error: invalid application of ‘sizeof’ to incomplete type ‘int[]’
37 | n = sizeof(memberof(struct s, y));
| ^
Thanks!
>
> Note array_type_nelts returns nelts - 1 because that avoids building
> a new tree node for arrays with lower bound zero.
What does it mean that the lower bound is zero? I didn't understand
that part.
>
> Thanks,
> Richard.
>
> > /* If arg is static -- a reference to an object in static storage -- then
> > return the object. This is not the same as the C meaning of `static'.
Have a lovely day!
Alex
--
<https://www.alejandro-colomar.es/>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [RFC v1 1/2] Merge definitions of array_type_nelts_top()
2024-07-29 8:55 ` Alejandro Colomar
@ 2024-07-29 9:08 ` Richard Biener
0 siblings, 0 replies; 248+ messages in thread
From: Richard Biener @ 2024-07-29 9:08 UTC (permalink / raw)
To: Alejandro Colomar
Cc: gcc-patches, Gabriel Ravier, Martin Uecker, Joseph Myers
On Mon, Jul 29, 2024 at 10:55 AM Alejandro Colomar <alx@kernel.org> wrote:
>
> Hi Richard,
>
> On Mon, Jul 29, 2024 at 10:27:35AM GMT, Richard Biener wrote:
> > On Sun, Jul 28, 2024 at 4:16 PM Alejandro Colomar <alx@kernel.org> wrote:
> > >
> > > There were two identical definitions, and none of them are available
> > > 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().
> > >
> > > Signed-off-by: Alejandro Colomar <alx@kernel.org>
> > > ---
> > > gcc/cp/cp-tree.h | 1 -
> > > gcc/cp/tree.cc | 13 -------------
> > > gcc/rust/backend/rust-tree.cc | 13 -------------
> > > gcc/rust/backend/rust-tree.h | 2 --
> > > gcc/tree.cc | 13 +++++++++++++
> > > gcc/tree.h | 1 +
> > > 6 files changed, 14 insertions(+), 29 deletions(-)
> > >
>
> [...]
>
> > > diff --git a/gcc/tree.cc b/gcc/tree.cc
> > > index 2d2d5b6db6e..3b0adb4cd9f 100644
> > > --- a/gcc/tree.cc
> > > +++ b/gcc/tree.cc
> > > @@ -3729,6 +3729,19 @@ array_type_nelts (const_tree type)
> > > ? max
> > > : fold_build2 (MINUS_EXPR, TREE_TYPE (max), max, min));
> > > }
> > > +
> > > +/* Return, as an INTEGER_CST node, the number of elements for TYPE
> > > + (which is an ARRAY_TYPE). This counts only elements of the top
> > > + array. */
> > > +
> > > +tree
> > > +array_type_nelts_top (tree type)
> > > +{
> > > + return fold_build2_loc (input_location,
> > > + PLUS_EXPR, sizetype,
> > > + array_type_nelts (type),
> > > + size_one_node);
> > > +}
> >
> > But this is now extremely confusing API with array_type_nelts above this
> > saying
> >
> > /* Return, as a tree node, the number of elements for TYPE (which is an
> > ARRAY_TYPE) minus one. This counts only elements of the top array. */
> >
> > so both are "_top". And there's build_array_type_nelts that's taking
> > the number of elements.
> >
> > Can you please rename the existing array_type_nelts to
> > array_type_nelts_minus_one? Then _top could be dropped as well from
> > the alternate API you add.
>
> I wanted to do that, but then I found other functions that are named
> similarly, such as build_array_type_nelts(), and thought that I wasn't
> sure if all of them should be renamed to _minus_one, or just some. So
> I decided to start without renaming.
Just array_type_nelts needs renaming, build_array_type_nelts is fine.
> But yeah, I think I should rename. I'll prepare a patch for renaming it
> independently of this patch set, and send it to be merged before this
> patch set.
Thanks.
> > I'll also note since array_type_nelts_top calls the other function and that has
> >
> > /* If they did it with unspecified bounds, then we should have already
> > given an error about it before we got here. */
> > if (! TYPE_DOMAIN (type))
> > return error_mark_node;
> >
> > the function should handle error_mark_node (and pass that down).
>
> Hmmmm, now I understand that (! TYPE_DOMAIN (type))
>
> $ grep -rn return.array_type_nelts gcc
> gcc/cp/call.cc:12111: return array_type_nelts_top (c->type);
> gcc/c-family/c-common.cc:4090: return array_type_nelts_top (type);
>
> $ sed -n 12102,12119p gcc/cp/call.cc
> /* Return a tree representing the number of elements initialized by the
> list-initialization C. The caller must check that C converts to an
> array type. */
>
> static tree
> nelts_initialized_by_list_init (conversion *c)
> {
> /* If the array we're converting to has a dimension, we'll use that. */
> if (TYPE_DOMAIN (c->type))
> return array_type_nelts_top (c->type);
> else
> {
> /* Otherwise, we look at how many elements the constructor we're
> initializing from has. */
> tree ctor = conv_get_original_expr (c);
> return size_int (CONSTRUCTOR_NELTS (ctor));
> }
> }
The point is that if you make this a general API it should be safe to be used,
not depending on constraints that are apparently checked right now.
> It seems that would fail when measuring for example
>
> #define memberof(T, member) ((T){}.member)
>
> struct s {
> int x;
> int a[];
> };
>
> __lengthof__(memberof(struct s, a));
>
> I guess?
>
> $ cat len.c
> #include <stdio.h>
>
> #define memberof(T, member) ((T){}.member)
>
> struct s {
> int x;
> int y[];
> };
>
> int
> main(int argc, char *argv[argc + 1])
> {
> int a[42];
> size_t n;
>
> (void) argv;
>
> //n = __lengthof__(argv);
> //printf("__lengthof__(argv) == %zu\n", n);
>
> n = __lengthof__(a);
> printf("lengthof(a):\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);
>
> n = __lengthof__(memberof(struct s, y));
> printf("lengthof(memberof(struct s, y)):\t %zu\n", n);
> }
> alx@debian:~/tmp/gcc$ /opt/local/gnu/gcc/lengthof/bin/gcc len.c
> alx@debian:~/tmp/gcc$ ./a.out
> lengthof(a): 42
> lengthof(long [99]): 99
> lengthof(short [n - 10]): 89
> lengthof(b): 44
> lengthof(memberof(struct s, y)): 44
>
> Indeed, it's misbehaving. I'll have a look at that. I'll probably have
> to add an error similar to sizeof's one:
>
> len.c: In function ‘main’:
> len.c:37:19: error: invalid application of ‘sizeof’ to incomplete type ‘int[]’
> 37 | n = sizeof(memberof(struct s, y));
> | ^
>
> Thanks!
>
> >
> > Note array_type_nelts returns nelts - 1 because that avoids building
> > a new tree node for arrays with lower bound zero.
>
> What does it mean that the lower bound is zero? I didn't understand
> that part.
It means the function can return TYPE_MAX_VALUE of the TYPE_DOMAIN
unchanged.
Richard.
> >
> > Thanks,
> > Richard.
> >
> > > /* If arg is static -- a reference to an object in static storage -- then
> > > return the object. This is not the same as the C meaning of `static'.
>
> Have a lovely day!
> Alex
>
> --
> <https://www.alejandro-colomar.es/>
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [RFC v1 0/2] c: Add _Lengthof operator
2024-07-28 14:15 ` [RFC v1 0/2] c: Add _Lengthof operator Alejandro Colomar
` (3 preceding siblings ...)
2024-07-28 16:48 ` [RFC v2 0/2] c: Add __lengthof__ operator Alejandro Colomar
@ 2024-07-29 11:13 ` Joseph Myers
2024-08-03 22:59 ` Alejandro Colomar
2024-08-03 23:17 ` [RFC v3 0/3] c: Add __lengthof__ operator Alejandro Colomar
` (17 subsequent siblings)
22 siblings, 1 reply; 248+ messages in thread
From: Joseph Myers @ 2024-07-29 11:13 UTC (permalink / raw)
To: Alejandro Colomar; +Cc: gcc-patches, Gabriel Ravier, Martin Uecker
On Sun, 28 Jul 2024, Alejandro Colomar wrote:
> gcc/Makefile.in | 1 +
> gcc/c-family/c-common.cc | 20 +++++++++
> gcc/c-family/c-common.def | 4 ++
> gcc/c-family/c-common.h | 2 +
> gcc/c/c-parser.cc | 35 +++++++++++----
> gcc/c/c-tree.h | 4 ++
> gcc/c/c-typeck.cc | 84 +++++++++++++++++++++++++++++++++++
> gcc/cp/cp-tree.h | 1 -
> gcc/cp/operators.def | 1 +
> gcc/cp/tree.cc | 13 ------
> gcc/ginclude/stdlength.h | 35 +++++++++++++++
> gcc/rust/backend/rust-tree.cc | 13 ------
> gcc/rust/backend/rust-tree.h | 2 -
> gcc/target.h | 3 ++
> gcc/tree.cc | 13 ++++++
> gcc/tree.h | 1 +
Please start with documentation and testcases, neither of which are
included here - making sure that both documentation and testcases cover
all the error cases and questions of e.g. evaluation of VLA operands.
Documentation and testcases are the most important pieces for reviewing a
proposed addition of a new language feature, before the actual
implementation.
A relevant semantic question to answer here: sizeof evaluates all VLA
operands, should this operator do likewise, or should it only evaluate
when the toplevel array is of variable length (but not for a
constant-length array of variable-size elements)?
--
Joseph S. Myers
josmyers@redhat.com
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [RFC v1 0/2] c: Add _Lengthof operator
2024-07-29 11:13 ` [RFC v1 0/2] c: Add _Lengthof operator Joseph Myers
@ 2024-08-03 22:59 ` Alejandro Colomar
0 siblings, 0 replies; 248+ messages in thread
From: Alejandro Colomar @ 2024-08-03 22:59 UTC (permalink / raw)
To: Joseph Myers; +Cc: gcc-patches, Gabriel Ravier, Martin Uecker
[-- Attachment #1: Type: text/plain, Size: 2617 bytes --]
Hi Joseph,
On Mon, Jul 29, 2024 at 11:13:08AM GMT, Joseph Myers wrote:
> On Sun, 28 Jul 2024, Alejandro Colomar wrote:
>
> > gcc/Makefile.in | 1 +
> > gcc/c-family/c-common.cc | 20 +++++++++
> > gcc/c-family/c-common.def | 4 ++
> > gcc/c-family/c-common.h | 2 +
> > gcc/c/c-parser.cc | 35 +++++++++++----
> > gcc/c/c-tree.h | 4 ++
> > gcc/c/c-typeck.cc | 84 +++++++++++++++++++++++++++++++++++
> > gcc/cp/cp-tree.h | 1 -
> > gcc/cp/operators.def | 1 +
> > gcc/cp/tree.cc | 13 ------
> > gcc/ginclude/stdlength.h | 35 +++++++++++++++
> > gcc/rust/backend/rust-tree.cc | 13 ------
> > gcc/rust/backend/rust-tree.h | 2 -
> > gcc/target.h | 3 ++
> > gcc/tree.cc | 13 ++++++
> > gcc/tree.h | 1 +
>
> Please start with documentation and testcases, neither of which are
> included here
While I haven't started yet with test cases within the test suite, I
have tests. There's a test program in the cover letter of the patch set
is the draft of a test suite for the feature.
Running the test suite is much more uncomfortable (to me) than compiling
a program manually, for iterating on the feature. I need to get used to
this test suite. :)
> - making sure that both documentation and testcases cover
> all the error cases and questions of e.g. evaluation of VLA operands.
> Documentation and testcases are the most important pieces for reviewing a
> proposed addition of a new language feature, before the actual
> implementation.
I was just having a look at what can be done. Now that it's working for
the cases I wanted it to work, I've started documenting it. I'll also
have a look at adding the tests to the test suite, although that will
take a few more iterations probably.
> A relevant semantic question to answer here: sizeof evaluates all VLA
> operands, should this operator do likewise, or should it only evaluate
> when the toplevel array is of variable length (but not for a
> constant-length array of variable-size elements)?
I see benefits of both approaches. The former is trivial to implement.
I'm not sure how much work would be needed for the latter, but probably
a bit more than that. As a programmer, I think I would ask for the
latter; I guess that's what we'd want, ideally. Thanks for the
feedback! :)
Have a lovely night!
Alex
> --
> Joseph S. Myers
> josmyers@redhat.com
>
--
<https://www.alejandro-colomar.es/>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 248+ messages in thread
* [RFC v3 0/3] c: Add __lengthof__ operator
2024-07-28 14:15 ` [RFC v1 0/2] c: Add _Lengthof operator Alejandro Colomar
` (4 preceding siblings ...)
2024-07-29 11:13 ` [RFC v1 0/2] c: Add _Lengthof operator Joseph Myers
@ 2024-08-03 23:17 ` Alejandro Colomar
2024-08-03 23:17 ` [RFC v3 1/3] gcc/: Rename array_type_nelts() => array_type_nelts_minus_one() Alejandro Colomar
` (2 more replies)
2024-08-06 12:22 ` [RFC v4 0/4] c: Add __lengthof__ operator Alejandro Colomar
` (16 subsequent siblings)
22 siblings, 3 replies; 248+ messages in thread
From: Alejandro Colomar @ 2024-08-03 23:17 UTC (permalink / raw)
To: gcc-patches
Cc: Alejandro Colomar, Xavier Del Campo Romero, Gabriel Ravier,
Martin Uecker, Joseph Myers, Jakub Jelinek
[-- Attachment #1: Type: text/plain, Size: 12605 bytes --]
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 <alx@kernel.org>
@@ 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);
+}
\f
@@ 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 <xavi.dcr@tutanota.com>
Cc: Gabriel Ravier <gabravier@gmail.com>
Cc: Martin Uecker <uecker@tugraz.at>
Cc: Joseph Myers <josmyers@redhat.com>
+ Cc: Jakub Jelinek <jakub@redhat.com>
Signed-off-by: Alejandro Colomar <alx@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 (!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
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 248+ messages in thread
* [RFC v3 1/3] gcc/: Rename array_type_nelts() => array_type_nelts_minus_one()
2024-08-03 23:17 ` [RFC v3 0/3] c: Add __lengthof__ operator Alejandro Colomar
@ 2024-08-03 23:17 ` Alejandro Colomar
2024-08-03 23:17 ` [RFC v3 2/3] Merge definitions of array_type_nelts_top() Alejandro Colomar
2024-08-03 23:17 ` [RFC v3 3/3] c: Add __lengthof__() operator Alejandro Colomar
2 siblings, 0 replies; 248+ messages in thread
From: Alejandro Colomar @ 2024-08-03 23:17 UTC (permalink / raw)
To: gcc-patches
Cc: Alejandro Colomar, Xavier Del Campo Romero, Gabriel Ravier,
Martin Uecker, Joseph Myers, Jakub Jelinek, Richard Biener
[-- Attachment #1: Type: text/plain, Size: 12983 bytes --]
The old name was misleading.
While at it, also rename some temporary variables that are used with
this function, for consistency.
Link: https://inbox.sourceware.org/gcc-patches/9fffd80-dca-2c7e-14b-6c9b509a7215@redhat.com/T/#m2f661c67c8f7b2c405c8c7fc3152dd85dc729120
Cc: Gabriel Ravier <gabravier@gmail.com>
Cc: Martin Uecker <uecker@tugraz.at>
Cc: Joseph Myers <josmyers@redhat.com>
Cc: Xavier Del Campo Romero <xavi.dcr@tutanota.com>
Cc: Jakub Jelinek <jakub@redhat.com>
gcc/ChangeLog:
* tree.cc (array_type_nelts): Rename function ...
(array_type_nelts_minus_one): ... to this name. The old name
was misleading.
* tree.h (array_type_nelts): Rename function ...
(array_type_nelts_minus_one): ... to this name. The old name
was misleading.
* expr.cc (count_type_elements):
Rename array_type_nelts() => array_type_nelts_minus_one()
* config/aarch64/aarch64.cc
(pure_scalable_type_info::analyze_array): Likewise.
* config/i386/i386.cc (ix86_canonical_va_list_type): Likewise.
gcc/c/ChangeLog:
* c-decl.cc (one_element_array_type_p, get_parm_array_spec):
Rename array_type_nelts() => array_type_nelts_minus_one()
* c-fold.cc (c_fold_array_ref): Likewise.
gcc/cp/ChangeLog:
* decl.cc (reshape_init_array):
Rename array_type_nelts() => array_type_nelts_minus_one()
* init.cc (build_zero_init_1): Likewise.
(build_value_init_noctor): Likewise.
(build_vec_init): Likewise.
(build_delete): Likewise.
* lambda.cc (add_capture): Likewise.
* tree.cc (array_type_nelts_top): Likewise.
gcc/fortran/ChangeLog:
* trans-array.cc (structure_alloc_comps):
Rename array_type_nelts() => array_type_nelts_minus_one()
* trans-openmp.cc (gfc_walk_alloc_comps): Likewise.
(gfc_omp_clause_linear_ctor): Likewise.
gcc/rust/ChangeLog:
* backend/rust-tree.cc (array_type_nelts_top):
Rename array_type_nelts() => array_type_nelts_minus_one()
Suggested-by: Richard Biener <richard.guenther@gmail.com>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
---
gcc/c/c-decl.cc | 10 +++++-----
gcc/c/c-fold.cc | 7 ++++---
gcc/config/aarch64/aarch64.cc | 2 +-
gcc/config/i386/i386.cc | 2 +-
gcc/cp/decl.cc | 2 +-
gcc/cp/init.cc | 8 ++++----
gcc/cp/lambda.cc | 3 ++-
gcc/cp/tree.cc | 2 +-
gcc/expr.cc | 8 ++++----
gcc/fortran/trans-array.cc | 2 +-
gcc/fortran/trans-openmp.cc | 4 ++--
gcc/rust/backend/rust-tree.cc | 2 +-
gcc/tree.cc | 4 ++--
gcc/tree.h | 2 +-
14 files changed, 30 insertions(+), 28 deletions(-)
diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 97f1d346835..4dced430d1f 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -5309,7 +5309,7 @@ one_element_array_type_p (const_tree type)
{
if (TREE_CODE (type) != ARRAY_TYPE)
return false;
- return integer_zerop (array_type_nelts (type));
+ return integer_zerop (array_type_nelts_minus_one (type));
}
/* Determine whether TYPE is a zero-length array type "[0]". */
@@ -6257,15 +6257,15 @@ get_parm_array_spec (const struct c_parm *parm, tree attrs)
for (tree type = parm->specs->type; TREE_CODE (type) == ARRAY_TYPE;
type = TREE_TYPE (type))
{
- tree nelts = array_type_nelts (type);
- if (error_operand_p (nelts))
+ tree nelts_minus_one = array_type_nelts_minus_one (type);
+ if (error_operand_p (nelts_minus_one))
return attrs;
- if (TREE_CODE (nelts) != INTEGER_CST)
+ if (TREE_CODE (nelts_minus_one) != INTEGER_CST)
{
/* Each variable VLA bound is represented by the dollar
sign. */
spec += "$";
- tpbnds = tree_cons (NULL_TREE, nelts, tpbnds);
+ tpbnds = tree_cons (NULL_TREE, nelts_minus_one, tpbnds);
}
}
tpbnds = nreverse (tpbnds);
diff --git a/gcc/c/c-fold.cc b/gcc/c/c-fold.cc
index 57b67c74bd8..9ea174f79c4 100644
--- a/gcc/c/c-fold.cc
+++ b/gcc/c/c-fold.cc
@@ -73,11 +73,12 @@ c_fold_array_ref (tree type, tree ary, tree index)
unsigned elem_nchars = (TYPE_PRECISION (elem_type)
/ TYPE_PRECISION (char_type_node));
unsigned len = (unsigned) TREE_STRING_LENGTH (ary) / elem_nchars;
- tree nelts = array_type_nelts (TREE_TYPE (ary));
+ tree nelts_minus_one = array_type_nelts_minus_one (TREE_TYPE (ary));
bool dummy1 = true, dummy2 = true;
- nelts = c_fully_fold_internal (nelts, true, &dummy1, &dummy2, false, false);
+ nelts_minus_one = c_fully_fold_internal (nelts_minus_one, true, &dummy1,
+ &dummy2, false, false);
unsigned HOST_WIDE_INT i = tree_to_uhwi (index);
- if (!tree_int_cst_le (index, nelts)
+ if (!tree_int_cst_le (index, nelts_minus_one)
|| i >= len
|| i + elem_nchars > len)
return NULL_TREE;
diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
index 0d41a193ec1..eaef2a0e985 100644
--- a/gcc/config/aarch64/aarch64.cc
+++ b/gcc/config/aarch64/aarch64.cc
@@ -1082,7 +1082,7 @@ pure_scalable_type_info::analyze_array (const_tree type)
/* An array of unknown, flexible or variable length will be passed and
returned by reference whatever we do. */
- tree nelts_minus_one = array_type_nelts (type);
+ tree nelts_minus_one = array_type_nelts_minus_one (type);
if (!tree_fits_uhwi_p (nelts_minus_one))
return DOESNT_MATTER;
diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc
index 9c2ebe74fc9..298d8c9131a 100644
--- a/gcc/config/i386/i386.cc
+++ b/gcc/config/i386/i386.cc
@@ -24519,7 +24519,7 @@ ix86_canonical_va_list_type (tree type)
return ms_va_list_type_node;
if ((TREE_CODE (type) == ARRAY_TYPE
- && integer_zerop (array_type_nelts (type)))
+ && integer_zerop (array_type_nelts_minus_one (type)))
|| POINTER_TYPE_P (type))
{
tree elem_type = TREE_TYPE (type);
diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index e7bb4fa3089..fc3e28c4dec 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -6936,7 +6936,7 @@ reshape_init_array (tree type, reshape_iter *d, tree first_initializer_p,
gcc_assert (TREE_CODE (type) == ARRAY_TYPE);
if (TYPE_DOMAIN (type))
- max_index = array_type_nelts (type);
+ max_index = array_type_nelts_minus_one (type);
return reshape_init_array_1 (TREE_TYPE (type), max_index, d,
first_initializer_p, complain);
diff --git a/gcc/cp/init.cc b/gcc/cp/init.cc
index e9561c146d7..4558151b4c2 100644
--- a/gcc/cp/init.cc
+++ b/gcc/cp/init.cc
@@ -260,7 +260,7 @@ build_zero_init_1 (tree type, tree nelts, bool static_storage_p,
else if (TYPE_DOMAIN (type) == NULL_TREE)
return NULL_TREE;
else
- max_index = array_type_nelts (type);
+ max_index = array_type_nelts_minus_one (type);
/* If we have an error_mark here, we should just return error mark
as we don't know the size of the array yet. */
@@ -471,7 +471,7 @@ build_value_init_noctor (tree type, tsubst_flags_t complain)
vec<constructor_elt, va_gc> *v = NULL;
/* Iterate over the array elements, building initializations. */
- tree max_index = array_type_nelts (type);
+ tree max_index = array_type_nelts_minus_one (type);
/* If we have an error_mark here, we should just return error mark
as we don't know the size of the array yet. */
@@ -4516,7 +4516,7 @@ build_vec_init (tree base, tree maxindex, tree init,
: location_of (base));
if (TREE_CODE (atype) == ARRAY_TYPE && TYPE_DOMAIN (atype))
- maxindex = array_type_nelts (atype);
+ maxindex = array_type_nelts_minus_one (atype);
if (maxindex == NULL_TREE || maxindex == error_mark_node)
return error_mark_node;
@@ -5172,7 +5172,7 @@ build_delete (location_t loc, tree otype, tree addr,
error_at (loc, "unknown array size in delete");
return error_mark_node;
}
- return build_vec_delete (loc, addr, array_type_nelts (type),
+ return build_vec_delete (loc, addr, array_type_nelts_minus_one (type),
auto_delete, use_global_delete, complain);
}
diff --git a/gcc/cp/lambda.cc b/gcc/cp/lambda.cc
index 0770417810e..065113bc122 100644
--- a/gcc/cp/lambda.cc
+++ b/gcc/cp/lambda.cc
@@ -556,7 +556,8 @@ add_capture (tree lambda, tree id, tree orig_init, bool by_reference_p,
integer_zero_node, tf_warning_or_error);
initializer = build_constructor_va (init_list_type_node, 2,
NULL_TREE, build_address (elt),
- NULL_TREE, array_type_nelts (type));
+ NULL_TREE,
+ array_type_nelts_minus_one (type));
type = vla_capture_type (type);
}
else if (!dependent_type_p (type)
diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
index dfd4a3a948b..3baeb8fa252 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -3080,7 +3080,7 @@ array_type_nelts_top (tree type)
{
return fold_build2_loc (input_location,
PLUS_EXPR, sizetype,
- array_type_nelts (type),
+ array_type_nelts_minus_one (type),
size_one_node);
}
diff --git a/gcc/expr.cc b/gcc/expr.cc
index ffbac513692..cba8b365856 100644
--- a/gcc/expr.cc
+++ b/gcc/expr.cc
@@ -6970,14 +6970,14 @@ count_type_elements (const_tree type, bool for_ctor_p)
{
case ARRAY_TYPE:
{
- tree nelts;
+ tree nelts_minus_one;
- nelts = array_type_nelts (type);
- if (nelts && tree_fits_uhwi_p (nelts))
+ nelts_minus_one = array_type_nelts_minus_one (type);
+ if (nelts_minus_one && tree_fits_uhwi_p (nelts_minus_one))
{
unsigned HOST_WIDE_INT n;
- n = tree_to_uhwi (nelts) + 1;
+ n = tree_to_uhwi (nelts_minus_one) + 1;
if (n == 0 || for_ctor_p)
return n;
else
diff --git a/gcc/fortran/trans-array.cc b/gcc/fortran/trans-array.cc
index 140d933e45d..b7927bcdf01 100644
--- a/gcc/fortran/trans-array.cc
+++ b/gcc/fortran/trans-array.cc
@@ -9572,7 +9572,7 @@ structure_alloc_comps (gfc_symbol * der_type, tree decl, tree dest,
else
{
/* Otherwise use the TYPE_DOMAIN information. */
- tmp = array_type_nelts (decl_type);
+ tmp = array_type_nelts_minus_one (decl_type);
tmp = fold_convert (gfc_array_index_type, tmp);
}
diff --git a/gcc/fortran/trans-openmp.cc b/gcc/fortran/trans-openmp.cc
index df1bf144e23..14cd2f9fad7 100644
--- a/gcc/fortran/trans-openmp.cc
+++ b/gcc/fortran/trans-openmp.cc
@@ -582,7 +582,7 @@ gfc_walk_alloc_comps (tree decl, tree dest, tree var,
tem = size_binop (MINUS_EXPR, tem, size_one_node);
}
else
- tem = array_type_nelts (type);
+ tem = array_type_nelts_minus_one (type);
tem = fold_convert (gfc_array_index_type, tem);
}
@@ -1309,7 +1309,7 @@ gfc_omp_clause_linear_ctor (tree clause, tree dest, tree src, tree add)
nelems = size_binop (MINUS_EXPR, nelems, size_one_node);
}
else
- nelems = array_type_nelts (type);
+ nelems = array_type_nelts_minus_one (type);
nelems = fold_convert (gfc_array_index_type, nelems);
gfc_omp_linear_clause_add_loop (&block, dest, src, add, nelems);
diff --git a/gcc/rust/backend/rust-tree.cc b/gcc/rust/backend/rust-tree.cc
index 2a5ffcbf895..a2c12204667 100644
--- a/gcc/rust/backend/rust-tree.cc
+++ b/gcc/rust/backend/rust-tree.cc
@@ -869,7 +869,7 @@ tree
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
diff --git a/gcc/tree.cc b/gcc/tree.cc
index 2d2d5b6db6e..dcaccc4c362 100644
--- a/gcc/tree.cc
+++ b/gcc/tree.cc
@@ -3698,7 +3698,7 @@ int_byte_position (const_tree field)
ARRAY_TYPE) minus one. This counts only elements of the top array. */
tree
-array_type_nelts (const_tree type)
+array_type_nelts_minus_one (const_tree type)
{
tree index_type, min, max;
@@ -14797,7 +14797,7 @@ is_empty_type (const_tree type)
return true;
}
else if (TREE_CODE (type) == ARRAY_TYPE)
- return (integer_minus_onep (array_type_nelts (type))
+ return (integer_minus_onep (array_type_nelts_minus_one (type))
|| TYPE_DOMAIN (type) == NULL_TREE
|| is_empty_type (TREE_TYPE (type)));
return false;
diff --git a/gcc/tree.h b/gcc/tree.h
index 28e8e71b036..fdddbcf408e 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -4921,7 +4921,7 @@ extern tree build_method_type_directly (tree, tree, tree);
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 value_member (tree, tree);
extern tree purpose_member (const_tree, tree);
--
2.45.2
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 248+ messages in thread
* [RFC v3 2/3] Merge definitions of array_type_nelts_top()
2024-08-03 23:17 ` [RFC v3 0/3] c: Add __lengthof__ operator Alejandro Colomar
2024-08-03 23:17 ` [RFC v3 1/3] gcc/: Rename array_type_nelts() => array_type_nelts_minus_one() Alejandro Colomar
@ 2024-08-03 23:17 ` Alejandro Colomar
2024-08-03 23:17 ` [RFC v3 3/3] c: Add __lengthof__() operator Alejandro Colomar
2 siblings, 0 replies; 248+ messages in thread
From: Alejandro Colomar @ 2024-08-03 23:17 UTC (permalink / raw)
To: gcc-patches
Cc: Alejandro Colomar, Xavier Del Campo Romero, Gabriel Ravier,
Martin Uecker, Joseph Myers, Jakub Jelinek
[-- Attachment #1: Type: text/plain, Size: 4433 bytes --]
There were two identical definitions, and none of them are available
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__().
Signed-off-by: Alejandro Colomar <alx@kernel.org>
---
gcc/cp/cp-tree.h | 1 -
gcc/cp/tree.cc | 13 -------------
gcc/rust/backend/rust-tree.cc | 13 -------------
gcc/rust/backend/rust-tree.h | 2 --
gcc/tree.cc | 13 +++++++++++++
gcc/tree.h | 1 +
6 files changed, 14 insertions(+), 29 deletions(-)
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index c1a371bc721..e6c1c63f872 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -8099,7 +8099,6 @@ extern tree build_exception_variant (tree, tree);
extern void fixup_deferred_exception_variants (tree, tree);
extern tree bind_template_template_parm (tree, tree);
extern tree array_type_nelts_total (tree);
-extern tree array_type_nelts_top (tree);
extern bool array_of_unknown_bound_p (const_tree);
extern tree break_out_target_exprs (tree, bool = false);
extern tree build_ctor_subob_ref (tree, tree, tree);
diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
index 3baeb8fa252..1f3ecff1a21 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -3071,19 +3071,6 @@ cxx_print_statistics (void)
depth_reached);
}
-/* Return, as an INTEGER_CST node, the number of elements for TYPE
- (which is an ARRAY_TYPE). This counts only elements of the top
- array. */
-
-tree
-array_type_nelts_top (tree type)
-{
- return fold_build2_loc (input_location,
- PLUS_EXPR, sizetype,
- array_type_nelts_minus_one (type),
- size_one_node);
-}
-
/* Return, as an INTEGER_CST node, the number of elements for TYPE
(which is an ARRAY_TYPE). This one is a recursive count of all
ARRAY_TYPEs that are clumped together. */
diff --git a/gcc/rust/backend/rust-tree.cc b/gcc/rust/backend/rust-tree.cc
index a2c12204667..dd8eda84f9b 100644
--- a/gcc/rust/backend/rust-tree.cc
+++ b/gcc/rust/backend/rust-tree.cc
@@ -859,19 +859,6 @@ is_empty_class (tree type)
return CLASSTYPE_EMPTY_P (type);
}
-// forked from gcc/cp/tree.cc array_type_nelts_top
-
-/* Return, as an INTEGER_CST node, the number of elements for TYPE
- (which is an ARRAY_TYPE). This counts only elements of the top
- array. */
-
-tree
-array_type_nelts_top (tree type)
-{
- return fold_build2_loc (input_location, PLUS_EXPR, sizetype,
- array_type_nelts_minus_one (type), size_one_node);
-}
-
// forked from gcc/cp/tree.cc builtin_valid_in_constant_expr_p
/* Test whether DECL is a builtin that may appear in a
diff --git a/gcc/rust/backend/rust-tree.h b/gcc/rust/backend/rust-tree.h
index 26c8b653ac6..e597c3ab81d 100644
--- a/gcc/rust/backend/rust-tree.h
+++ b/gcc/rust/backend/rust-tree.h
@@ -2993,8 +2993,6 @@ extern location_t rs_expr_location (const_tree);
extern int
is_empty_class (tree type);
-extern tree array_type_nelts_top (tree);
-
extern bool
is_really_empty_class (tree, bool);
diff --git a/gcc/tree.cc b/gcc/tree.cc
index dcaccc4c362..cbbc7627ad6 100644
--- a/gcc/tree.cc
+++ b/gcc/tree.cc
@@ -3729,6 +3729,19 @@ array_type_nelts_minus_one (const_tree type)
? max
: fold_build2 (MINUS_EXPR, TREE_TYPE (max), max, min));
}
+
+/* Return, as an INTEGER_CST node, the number of elements for TYPE
+ (which is an ARRAY_TYPE). This counts only elements of the top
+ array. */
+
+tree
+array_type_nelts_top (tree type)
+{
+ return fold_build2_loc (input_location,
+ PLUS_EXPR, sizetype,
+ array_type_nelts_minus_one (type),
+ size_one_node);
+}
\f
/* If arg is static -- a reference to an object in static storage -- then
return the object. This is not the same as the C meaning of `static'.
diff --git a/gcc/tree.h b/gcc/tree.h
index fdddbcf408e..a6c46440b1a 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -4922,6 +4922,7 @@ 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_minus_one (const_tree);
+extern tree array_type_nelts_top (tree);
extern tree value_member (tree, tree);
extern tree purpose_member (const_tree, tree);
--
2.45.2
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 248+ messages in thread
* [RFC v3 3/3] c: Add __lengthof__() operator
2024-08-03 23:17 ` [RFC v3 0/3] c: Add __lengthof__ operator Alejandro Colomar
2024-08-03 23:17 ` [RFC v3 1/3] gcc/: Rename array_type_nelts() => array_type_nelts_minus_one() Alejandro Colomar
2024-08-03 23:17 ` [RFC v3 2/3] Merge definitions of array_type_nelts_top() Alejandro Colomar
@ 2024-08-03 23:17 ` Alejandro Colomar
2024-08-04 5:38 ` Martin Uecker
2 siblings, 1 reply; 248+ messages in thread
From: Alejandro Colomar @ 2024-08-03 23:17 UTC (permalink / raw)
To: gcc-patches
Cc: Alejandro Colomar, Xavier Del Campo Romero, Gabriel Ravier,
Martin Uecker, Joseph Myers, Jakub Jelinek
[-- Attachment #1: Type: text/plain, Size: 19719 bytes --]
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
somehow magically return the length designator of the array,
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.dcr@tutanota.com>
Cc: Gabriel Ravier <gabravier@gmail.com>
Cc: Martin Uecker <uecker@tugraz.at>
Cc: Joseph Myers <josmyers@redhat.com>
Cc: Jakub Jelinek <jakub@redhat.com>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
---
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 | 20 ++++++---
gcc/c/c-parser.cc | 61 +++++++++++++++++++------
gcc/c/c-tree.h | 4 ++
gcc/c/c-typeck.cc | 95 +++++++++++++++++++++++++++++++++++++--
gcc/cp/operators.def | 1 +
gcc/doc/extend.texi | 12 +++++
gcc/target.h | 3 ++
10 files changed, 203 insertions(+), 24 deletions(-)
diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
index e7e371fd26f..91793dfbffc 100644
--- a/gcc/c-family/c-common.cc
+++ b/gcc/c-family/c-common.cc
@@ -465,6 +465,7 @@ const struct c_common_resword c_common_reswords[] =
{ "__inline", RID_INLINE, 0 },
{ "__inline__", RID_INLINE, 0 },
{ "__label__", RID_LABEL, 0 },
+ { "__lengthof__", RID_LENGTHOF, 0 },
{ "__null", RID_NULL, 0 },
{ "__real", RID_REALPART, 0 },
{ "__real__", RID_REALPART, 0 },
@@ -4070,6 +4071,31 @@ c_alignof_expr (location_t loc, tree expr)
return fold_convert_loc (loc, size_type_node, t);
}
+
+/* Implement the lengthof keyword: Return the length of an array,
+ that is, the number of elements in the array. */
+
+tree
+c_lengthof_type (location_t loc, tree type)
+{
+ 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);
+ return error_mark_node;
+ }
+
+ return array_type_nelts_top (type);
+}
\f
/* Handle C and C++ default attributes. */
diff --git a/gcc/c-family/c-common.def b/gcc/c-family/c-common.def
index 5de96e5d4a8..6d162f67104 100644
--- a/gcc/c-family/c-common.def
+++ b/gcc/c-family/c-common.def
@@ -50,6 +50,9 @@ DEFTREECODE (EXCESS_PRECISION_EXPR, "excess_precision_expr", tcc_expression, 1)
number. */
DEFTREECODE (USERDEF_LITERAL, "userdef_literal", tcc_exceptional, 3)
+/* Represents a 'lengthof' expression. */
+DEFTREECODE (LENGTHOF_EXPR, "lengthof_expr", tcc_expression, 1)
+
/* Represents a 'sizeof' expression during C++ template expansion,
or for the purpose of -Wsizeof-pointer-memaccess warning. */
DEFTREECODE (SIZEOF_EXPR, "sizeof_expr", tcc_expression, 1)
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index ccaea27c2b9..f815a4cf3bc 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -105,6 +105,7 @@ enum rid
/* C extensions */
RID_ASM, RID_TYPEOF, RID_TYPEOF_UNQUAL, RID_ALIGNOF, RID_ATTRIBUTE,
+ RID_LENGTHOF,
RID_VA_ARG,
RID_EXTENSION, RID_IMAGPART, RID_REALPART, RID_LABEL, RID_CHOOSE_EXPR,
RID_TYPES_COMPATIBLE_P, RID_BUILTIN_COMPLEX, RID_BUILTIN_SHUFFLE,
@@ -885,6 +886,7 @@ extern tree c_common_truthvalue_conversion (location_t, tree);
extern void c_apply_type_quals_to_decl (int, tree);
extern tree c_sizeof_or_alignof_type (location_t, tree, bool, bool, int);
extern tree c_alignof_expr (location_t, tree);
+extern tree c_lengthof_type (location_t, tree);
/* Print an error message for invalid operands to arith operation CODE.
NOP_EXPR is used as a special case (see truthvalue_conversion). */
extern void binary_op_error (rich_location *, enum tree_code, tree, tree);
diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 4dced430d1f..790c58b2558 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -8937,12 +8937,16 @@ start_struct (location_t loc, enum tree_code code, tree name,
within a statement expr used within sizeof, et. al. This is not
terribly serious as C++ doesn't permit statement exprs within
sizeof anyhow. */
- if (warn_cxx_compat && (in_sizeof || in_typeof || in_alignof))
+ if (warn_cxx_compat && (in_sizeof || in_typeof || in_alignof || in_lengthof))
warning_at (loc, OPT_Wc___compat,
"defining type in %qs expression is invalid in C++",
(in_sizeof
? "sizeof"
- : (in_typeof ? "typeof" : "alignof")));
+ : (in_typeof
+ ? "typeof"
+ : (in_alignof
+ ? "alignof"
+ : "lengthof"))));
if (in_underspecified_init)
error_at (loc, "%qT defined in underspecified object initializer", ref);
@@ -9897,7 +9901,7 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes,
struct_types. */
if (warn_cxx_compat
&& struct_parse_info != NULL
- && !in_sizeof && !in_typeof && !in_alignof)
+ && !in_sizeof && !in_typeof && !in_alignof && !in_lengthof)
struct_parse_info->struct_types.safe_push (t);
}
@@ -10071,12 +10075,16 @@ start_enum (location_t loc, struct c_enum_contents *the_enum, tree name,
/* FIXME: This will issue a warning for a use of a type defined
within sizeof in a statement expr. This is not terribly serious
as C++ doesn't permit statement exprs within sizeof anyhow. */
- if (warn_cxx_compat && (in_sizeof || in_typeof || in_alignof))
+ if (warn_cxx_compat && (in_sizeof || in_typeof || in_alignof || in_lengthof))
warning_at (loc, OPT_Wc___compat,
"defining type in %qs expression is invalid in C++",
(in_sizeof
? "sizeof"
- : (in_typeof ? "typeof" : "alignof")));
+ : (in_typeof
+ ? "typeof"
+ : (in_alignof
+ ? "alignof"
+ : "lengthof"))));
if (in_underspecified_init)
error_at (loc, "%qT defined in underspecified object initializer",
@@ -10270,7 +10278,7 @@ finish_enum (tree enumtype, tree values, tree attributes)
struct_types. */
if (warn_cxx_compat
&& struct_parse_info != NULL
- && !in_sizeof && !in_typeof && !in_alignof)
+ && !in_sizeof && !in_typeof && !in_alignof && !in_lengthof)
struct_parse_info->struct_types.safe_push (enumtype);
/* Check for consistency with previous definition */
diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
index 12c5ed5d92c..09bb19f9299 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -74,7 +74,17 @@ along with GCC; see the file COPYING3. If not see
#include "bitmap.h"
#include "analyzer/analyzer-language.h"
#include "toplev.h"
+\f
+#define c_parser_sizeof_expression(parser) \
+( \
+ c_parser_sizeof_or_lengthof_expression (parser, RID_SIZEOF) \
+)
+#define c_parser_lengthof_expression(parser) \
+( \
+ c_parser_sizeof_or_lengthof_expression (parser, RID_LENGTHOF) \
+)
+\f
/* We need to walk over decls with incomplete struct/union/enum types
after parsing the whole translation unit.
In finish_decl(), if the decl is static, has incomplete
@@ -1687,7 +1697,7 @@ static struct c_expr c_parser_binary_expression (c_parser *, struct c_expr *,
tree);
static struct c_expr c_parser_cast_expression (c_parser *, struct c_expr *);
static struct c_expr c_parser_unary_expression (c_parser *);
-static struct c_expr c_parser_sizeof_expression (c_parser *);
+static struct c_expr c_parser_sizeof_or_lengthof_expression (c_parser *, enum rid);
static struct c_expr c_parser_alignof_expression (c_parser *);
static struct c_expr c_parser_postfix_expression (c_parser *);
static struct c_expr c_parser_postfix_expression_after_paren_type (c_parser *,
@@ -9864,6 +9874,8 @@ c_parser_unary_expression (c_parser *parser)
case CPP_KEYWORD:
switch (c_parser_peek_token (parser)->keyword)
{
+ case RID_LENGTHOF:
+ return c_parser_lengthof_expression (parser);
case RID_SIZEOF:
return c_parser_sizeof_expression (parser);
case RID_ALIGNOF:
@@ -9903,12 +9915,13 @@ c_parser_unary_expression (c_parser *parser)
/* Parse a sizeof expression. */
static struct c_expr
-c_parser_sizeof_expression (c_parser *parser)
+c_parser_sizeof_or_lengthof_expression (c_parser *parser, enum rid rid)
{
+ const char *op_name = (rid == RID_LENGTHOF) ? "lengthof" : "sizeof";
struct c_expr expr;
struct c_expr result;
location_t expr_loc;
- gcc_assert (c_parser_next_token_is_keyword (parser, RID_SIZEOF));
+ gcc_assert (c_parser_next_token_is_keyword (parser, rid));
location_t start;
location_t finish = UNKNOWN_LOCATION;
@@ -9917,7 +9930,10 @@ c_parser_sizeof_expression (c_parser *parser)
c_parser_consume_token (parser);
c_inhibit_evaluation_warnings++;
- in_sizeof++;
+ if (rid == RID_LENGTHOF)
+ in_lengthof++;
+ else
+ in_sizeof++;
if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)
&& c_token_starts_compound_literal (c_parser_peek_2nd_token (parser)))
{
@@ -9936,7 +9952,10 @@ c_parser_sizeof_expression (c_parser *parser)
{
struct c_expr ret;
c_inhibit_evaluation_warnings--;
- in_sizeof--;
+ if (rid == RID_LENGTHOF)
+ in_lengthof--;
+ else
+ in_sizeof--;
ret.set_error ();
ret.original_code = ERROR_MARK;
ret.original_type = NULL;
@@ -9948,31 +9967,45 @@ c_parser_sizeof_expression (c_parser *parser)
type_name,
expr_loc);
finish = expr.get_finish ();
- goto sizeof_expr;
+ goto Xof_expr;
}
/* sizeof ( type-name ). */
if (scspecs)
- error_at (expr_loc, "storage class specifier in %<sizeof%>");
+ error_at (expr_loc, "storage class specifier in %qs", op_name);
if (type_name->specs->alignas_p)
error_at (type_name->specs->locations[cdw_alignas],
- "alignment specified for type name in %<sizeof%>");
+ "alignment specified for type name in %qs", op_name);
c_inhibit_evaluation_warnings--;
- in_sizeof--;
- result = c_expr_sizeof_type (expr_loc, type_name);
+ if (rid == RID_LENGTHOF)
+ {
+ in_lengthof--;
+ result = c_expr_lengthof_type (expr_loc, type_name);
+ }
+ else
+ {
+ in_sizeof--;
+ result = c_expr_sizeof_type (expr_loc, type_name);
+ }
}
else
{
expr_loc = c_parser_peek_token (parser)->location;
expr = c_parser_unary_expression (parser);
finish = expr.get_finish ();
- sizeof_expr:
+ Xof_expr:
c_inhibit_evaluation_warnings--;
- in_sizeof--;
+ if (rid == RID_LENGTHOF)
+ in_lengthof--;
+ else
+ in_sizeof--;
mark_exp_read (expr.value);
if (TREE_CODE (expr.value) == COMPONENT_REF
&& DECL_C_BIT_FIELD (TREE_OPERAND (expr.value, 1)))
- error_at (expr_loc, "%<sizeof%> applied to a bit-field");
- result = c_expr_sizeof_expr (expr_loc, expr);
+ error_at (expr_loc, "%qs applied to a bit-field", op_name);
+ if (rid == RID_LENGTHOF)
+ result = c_expr_lengthof_expr (expr_loc, expr);
+ else
+ result = c_expr_sizeof_expr (expr_loc, expr);
}
if (finish == UNKNOWN_LOCATION)
finish = start;
diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h
index 15da875a029..102fcfefea6 100644
--- a/gcc/c/c-tree.h
+++ b/gcc/c/c-tree.h
@@ -736,6 +736,7 @@ extern int c_type_dwarf_attribute (const_tree, int);
/* in c-typeck.cc */
extern int in_alignof;
extern int in_sizeof;
+extern int in_lengthof;
extern int in_typeof;
extern bool c_in_omp_for;
extern bool c_omp_array_section_p;
@@ -786,6 +787,9 @@ extern tree build_external_ref (location_t, tree, bool, tree *);
extern void pop_maybe_used (bool);
extern struct c_expr c_expr_sizeof_expr (location_t, struct c_expr);
extern struct c_expr c_expr_sizeof_type (location_t, struct c_type_name *);
+extern struct c_expr c_expr_lengthof_expr (location_t, struct c_expr);
+extern struct c_expr c_expr_lengthof_type (location_t loc,
+ struct c_type_name *);
extern struct c_expr parser_build_unary_op (location_t, enum tree_code,
struct c_expr);
extern struct c_expr parser_build_binary_op (location_t,
diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index 7e0f01ed22b..121e74de25d 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -71,6 +71,9 @@ int in_alignof;
/* The level of nesting inside "sizeof". */
int in_sizeof;
+/* The level of nesting inside "sizeof". */
+int in_lengthof;
+
/* The level of nesting inside "typeof". */
int in_typeof;
@@ -3255,7 +3258,7 @@ build_external_ref (location_t loc, tree id, bool fun, tree *type)
if (TREE_CODE (ref) == FUNCTION_DECL && !in_alignof)
{
- if (!in_sizeof && !in_typeof)
+ if (!in_sizeof && !in_typeof && !in_lengthof)
C_DECL_USED (ref) = 1;
else if (DECL_INITIAL (ref) == NULL_TREE
&& DECL_EXTERNAL (ref)
@@ -3311,7 +3314,7 @@ struct maybe_used_decl
{
/* The decl. */
tree decl;
- /* The level seen at (in_sizeof + in_typeof). */
+ /* The level seen at (in_sizeof + in_typeof + in_lengthof). */
int level;
/* The next one at this level or above, or NULL. */
struct maybe_used_decl *next;
@@ -3329,7 +3332,7 @@ record_maybe_used_decl (tree decl)
{
struct maybe_used_decl *t = XOBNEW (&parser_obstack, struct maybe_used_decl);
t->decl = decl;
- t->level = in_sizeof + in_typeof;
+ t->level = in_sizeof + in_typeof + in_lengthof;
t->next = maybe_used_decls;
maybe_used_decls = t;
}
@@ -3343,7 +3346,7 @@ void
pop_maybe_used (bool used)
{
struct maybe_used_decl *p = maybe_used_decls;
- int cur_level = in_sizeof + in_typeof;
+ int cur_level = in_sizeof + in_typeof + in_lengthof;
while (p && p->level > cur_level)
{
if (used)
@@ -3453,6 +3456,90 @@ c_expr_sizeof_type (location_t loc, struct c_type_name *t)
return ret;
}
+/* Return the result of lengthof applied to EXPR. */
+
+struct c_expr
+c_expr_lengthof_expr (location_t loc, struct c_expr expr)
+{
+ struct c_expr ret;
+ if (expr.value == error_mark_node)
+ {
+ ret.value = error_mark_node;
+ ret.original_code = ERROR_MARK;
+ ret.original_type = NULL;
+ ret.m_decimal = 0;
+ pop_maybe_used (false);
+ }
+ else
+ {
+ bool expr_const_operands = true;
+
+ tree folded_expr = c_fully_fold (expr.value, require_constant_value,
+ &expr_const_operands);
+ ret.value = c_lengthof_type (loc, TREE_TYPE (folded_expr));
+ c_last_sizeof_arg = expr.value;
+ c_last_sizeof_loc = loc;
+ ret.original_code = LENGTHOF_EXPR;
+ ret.original_type = NULL;
+ ret.m_decimal = 0;
+ if (C_TYPE_VARIABLE_SIZE (TREE_TYPE (folded_expr)))
+ {
+ /* lengthof is evaluated when given a vla. */
+ ret.value = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (ret.value),
+ folded_expr, ret.value);
+ 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)));
+ }
+ return ret;
+}
+
+/* Return the result of lengthof applied to T, a structure for the type
+ name passed to _lengthof (rather than the type itself). LOC is the
+ location of the original expression. */
+
+struct c_expr
+c_expr_lengthof_type (location_t loc, struct c_type_name *t)
+{
+ tree type;
+ struct c_expr ret;
+ tree type_expr = NULL_TREE;
+ bool type_expr_const = true;
+ type = groktypename (t, &type_expr, &type_expr_const);
+ ret.value = c_lengthof_type (loc, type);
+ c_last_sizeof_arg = type;
+ c_last_sizeof_loc = loc;
+ ret.original_code = LENGTHOF_EXPR;
+ ret.original_type = NULL;
+ ret.m_decimal = 0;
+ if (type == error_mark_node)
+ {
+ ret.value = error_mark_node;
+ ret.original_code = ERROR_MARK;
+ }
+ else
+ if ((type_expr || TREE_CODE (ret.value) == INTEGER_CST)
+ && C_TYPE_VARIABLE_SIZE (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
+ the result of lengthof does not get folded to a constant by
+ c_fully_fold, because if the length is evaluated the result is
+ not constant and so constraints on zero or negative size
+ arrays must not be applied when this lengthof call is inside
+ another array declarator. */
+ if (!type_expr)
+ type_expr = integer_zero_node;
+ ret.value = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (ret.value),
+ 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);
+ return ret;
+}
+
/* Build a function call to function FUNCTION with parameters PARAMS.
The function call is at LOC.
PARAMS is a list--a chain of TREE_LIST nodes--in which the
diff --git a/gcc/cp/operators.def b/gcc/cp/operators.def
index d8878923602..d640ed8bd91 100644
--- a/gcc/cp/operators.def
+++ b/gcc/cp/operators.def
@@ -91,6 +91,7 @@ DEF_OPERATOR ("co_await", CO_AWAIT_EXPR, "aw", OVL_OP_FLAG_UNARY)
/* These are extensions. */
DEF_OPERATOR ("alignof", ALIGNOF_EXPR, "az", OVL_OP_FLAG_UNARY)
+DEF_OPERATOR ("__lengthof__", LENGTHOF_EXPR, "lz", OVL_OP_FLAG_UNARY)
DEF_OPERATOR ("__imag__", IMAGPART_EXPR, "v18__imag__", OVL_OP_FLAG_UNARY)
DEF_OPERATOR ("__real__", REALPART_EXPR, "v18__real__", OVL_OP_FLAG_UNARY)
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 0b572afca72..4d6066f8acd 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -10391,6 +10391,18 @@ 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
diff --git a/gcc/target.h b/gcc/target.h
index c1f99b97b86..79890ae9944 100644
--- a/gcc/target.h
+++ b/gcc/target.h
@@ -245,6 +245,9 @@ enum type_context_kind {
/* Directly measuring the alignment of T. */
TCTX_ALIGNOF,
+ /* Directly measuring the length of array T. */
+ TCTX_LENGTHOF,
+
/* Creating objects of type T with static storage duration. */
TCTX_STATIC_STORAGE,
--
2.45.2
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [RFC v3 3/3] c: Add __lengthof__() operator
2024-08-03 23:17 ` [RFC v3 3/3] c: Add __lengthof__() operator Alejandro Colomar
@ 2024-08-04 5:38 ` Martin Uecker
2024-08-04 8:25 ` Alejandro Colomar
0 siblings, 1 reply; 248+ messages in thread
From: Martin Uecker @ 2024-08-04 5:38 UTC (permalink / raw)
To: Alejandro Colomar, gcc-patches
Cc: Xavier Del Campo Romero, Gabriel Ravier, Joseph Myers, Jakub Jelinek
Am Sonntag, dem 04.08.2024 um 01:17 +0200 schrieb Alejandro Colomar:
>
> 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.
And maybe flexible array members with "counted_by" attribute.
> +
> +/* Implement the lengthof keyword: Return the length of an array,
> + that is, the number of elements in the array. */
> +
> +tree
> +c_lengthof_type (location_t loc, tree type)
> +{
> + 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);
> + return error_mark_node;
> + }
I would swap these two errors, because the first is more specific and
less helpful if you pass an incomplete struct, where it would be better
to get the second error.
Martin
> +
> + return array_type_nelts_top (type);
> +}
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [RFC v3 3/3] c: Add __lengthof__() operator
2024-08-04 5:38 ` Martin Uecker
@ 2024-08-04 8:25 ` Alejandro Colomar
2024-08-04 9:39 ` Martin Uecker
0 siblings, 1 reply; 248+ messages in thread
From: Alejandro Colomar @ 2024-08-04 8:25 UTC (permalink / raw)
To: Martin Uecker
Cc: gcc-patches, Xavier Del Campo Romero, Gabriel Ravier,
Joseph Myers, Jakub Jelinek
[-- Attachment #1: Type: text/plain, Size: 1762 bytes --]
Hi Martin,
On Sun, Aug 04, 2024 at 07:38:49AM GMT, Martin Uecker wrote:
> Am Sonntag, dem 04.08.2024 um 01:17 +0200 schrieb Alejandro Colomar:
> >
> > 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.
>
> And maybe flexible array members with "counted_by" attribute.
Hmmm; I didn't know that one. Indeed. I'll have a look at implementing
that in this patch set.
> > +
> > +/* Implement the lengthof keyword: Return the length of an array,
> > + that is, the number of elements in the array. */
> > +
> > +tree
> > +c_lengthof_type (location_t loc, tree type)
> > +{
> > + 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);
> > + return error_mark_node;
> > + }
>
> I would swap these two errors, because the first is more specific and
> less helpful if you pass an incomplete struct, where it would be better
> to get the second error.
Agree.
BTW, I still don't understand what `if (! TYPE_DOMAIN (type))` means,
within array_type_nelts_minus_one(). What code triggers that condition?
Am I missing error handling for that? Thanks!
Have a lovely day!
Alex
>
> Martin
>
> > +
> > + return array_type_nelts_top (type);
> > +}
>
--
<https://www.alejandro-colomar.es/>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [RFC v3 3/3] c: Add __lengthof__() operator
2024-08-04 8:25 ` Alejandro Colomar
@ 2024-08-04 9:39 ` Martin Uecker
2024-08-04 16:40 ` Alejandro Colomar
2024-08-05 11:55 ` Alejandro Colomar
0 siblings, 2 replies; 248+ messages in thread
From: Martin Uecker @ 2024-08-04 9:39 UTC (permalink / raw)
To: Alejandro Colomar
Cc: gcc-patches, Xavier Del Campo Romero, Gabriel Ravier,
Joseph Myers, Jakub Jelinek
Am Sonntag, dem 04.08.2024 um 10:25 +0200 schrieb Alejandro Colomar:
> Hi Martin,
>
> On Sun, Aug 04, 2024 at 07:38:49AM GMT, Martin Uecker wrote:
> > Am Sonntag, dem 04.08.2024 um 01:17 +0200 schrieb Alejandro Colomar:
> > >
> > > 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.
> >
> > And maybe flexible array members with "counted_by" attribute.
>
> Hmmm; I didn't know that one. Indeed. I'll have a look at implementing
> that in this patch set.
But maybe wait for this:
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=116016
>
> > > +
> > > +/* Implement the lengthof keyword: Return the length of an array,
> > > + that is, the number of elements in the array. */
> > > +
> > > +tree
> > > +c_lengthof_type (location_t loc, tree type)
> > > +{
> > > + 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);
> > > + return error_mark_node;
> > > + }
> >
> > I would swap these two errors, because the first is more specific and
> > less helpful if you pass an incomplete struct, where it would be better
> > to get the second error.
>
> Agree.
>
> BTW, I still don't understand what `if (! TYPE_DOMAIN (type))` means,
> within array_type_nelts_minus_one(). What code triggers that condition?
> Am I missing error handling for that? Thanks!
For incomplete arrays, basically we have the following different
variants for arrays:
T[ ] incomplete: !TYPE_DOMAIN
T[1] constant size: TYPE_MAX_VALUE == INTEGER_CST
T[n] variable size: TYPE_MAX_VALUE != INTEGER_CST
T[0] flexible array member: !TYPE_MAX_VALUE && !C_TYPE_VARIABLE_SIZE
(ISO version T[0] has TYPE_SIZE == NULL_TREE)
T[*] unspecified variable size: !TYPE_MAX_VALUE && C_TYPE_VARIABLE_SIZE
The first should give an error. The next two should work giving an
integer constant expression or run-time size, respectively.
The ISO FAM case should also give an error, while the GNU fam case
could return zero to be consistent with sizeof (not sure). The last
case should return a non-constant.
If you reuse the sizeof code, it should be mostly correct, but
maybe the last case needs to be revisted. In the following
examples
void foo(char (*a)[3][*], int (*x)[__lengthof__(*a)]);
void bar(char (*a)[*][3], int (*x)[__lengthof__(*a)]);
the array '*x' should be a regular fixed size array in foo
but a VLA in 'bar'.
Martin
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [RFC v3 3/3] c: Add __lengthof__() operator
2024-08-04 9:39 ` Martin Uecker
@ 2024-08-04 16:40 ` Alejandro Colomar
2024-08-04 16:43 ` Alejandro Colomar
2024-08-04 17:28 ` Martin Uecker
2024-08-05 11:55 ` Alejandro Colomar
1 sibling, 2 replies; 248+ messages in thread
From: Alejandro Colomar @ 2024-08-04 16:40 UTC (permalink / raw)
To: Martin Uecker
Cc: gcc-patches, Xavier Del Campo Romero, Gabriel Ravier,
Joseph Myers, Jakub Jelinek
[-- Attachment #1: Type: text/plain, Size: 7479 bytes --]
Hi Martin,
On Sun, Aug 04, 2024 at 11:39:26AM GMT, Martin Uecker wrote:
> Am Sonntag, dem 04.08.2024 um 10:25 +0200 schrieb Alejandro Colomar:
> > Hi Martin,
> >
> > On Sun, Aug 04, 2024 at 07:38:49AM GMT, Martin Uecker wrote:
> > > Am Sonntag, dem 04.08.2024 um 01:17 +0200 schrieb Alejandro Colomar:
> > > >
> > > > 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.
> > >
> > > And maybe flexible array members with "counted_by" attribute.
> >
> > Hmmm; I didn't know that one. Indeed. I'll have a look at implementing
> > that in this patch set.
>
> But maybe wait for this:
> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=116016
Maybe; if I don't find a way to implement it now, their patches may give
me some tool to do it. I'll still try to do it now, just to try.
I've drafted something by making build_counted_by_ref() an extern
function, and then I wrote
diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
index 9f5feb83345..875d471a1f4 100644
--- a/gcc/c-family/c-common.cc
+++ b/gcc/c-family/c-common.cc
@@ -4078,6 +4078,7 @@ c_alignof_expr (location_t loc, tree expr)
tree
c_lengthof_type (location_t loc, tree type)
{
+ tree counted_by;
enum tree_code type_code;
type_code = TREE_CODE (type);
@@ -4086,6 +4087,12 @@ c_lengthof_type (location_t loc, tree type)
error_at (loc, "invalid application of %<lengthof%> to type %qT", type);
return error_mark_node;
}
+
+ counted_by = lookup_attribute ("counted_by", DECL_ATTRIBUTES (type));
+ if (counted_by)
+ // XXX: How to build the counted_by ref without the parent struct type?
+ return build_counted_by_ref (NULL, type, counted_by);
+
if (!COMPLETE_TYPE_P (type))
{
error_at (loc,
But since I don't have the struct to which the FAM belongs, I don't know
how to get that working. Do you have any idea? Or maybe it's better to
just wait for those patches to be merged, and reuse their
infrastructure?
> > > > +
> > > > +/* Implement the lengthof keyword: Return the length of an array,
> > > > + that is, the number of elements in the array. */
> > > > +
> > > > +tree
> > > > +c_lengthof_type (location_t loc, tree type)
> > > > +{
> > > > + 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);
> > > > + return error_mark_node;
> > > > + }
> > >
> > > I would swap these two errors, because the first is more specific and
> > > less helpful if you pass an incomplete struct, where it would be better
> > > to get the second error.
> >
> > Agree.
> >
> > BTW, I still don't understand what `if (! TYPE_DOMAIN (type))` means,
> > within array_type_nelts_minus_one(). What code triggers that condition?
> > Am I missing error handling for that? Thanks!
>
> For incomplete arrays, basically we have the following different
> variants for arrays:
Thanks! This list is very useful.
> T[ ] incomplete: !TYPE_DOMAIN
> T[1] constant size: TYPE_MAX_VALUE == INTEGER_CST
I guess that old flexible-array members using [1] are understood as
normal arrays [42], right?
> T[n] variable size: TYPE_MAX_VALUE != INTEGER_CST
> T[0] flexible array member: !TYPE_MAX_VALUE && !C_TYPE_VARIABLE_SIZE
> (ISO version T[0] has TYPE_SIZE == NULL_TREE)
ISO version is T[], right? Did ISO add support for zero-sized arrays?
> T[*] unspecified variable size: !TYPE_MAX_VALUE && C_TYPE_VARIABLE_SIZE
This is not allowed aoutside of function-prototype scope. And there it
decays to pointer way before reaching __lengthof__. So we can't handle
that at the moment. However, we'll have to keep it in mind for when you
do the change to keep the array types of function prototypes. When that
happens, I guess we'll have to reject these arrays.
>
> The first should give an error.
Agree (and already implemented []).
> The next two should work giving an
> integer constant expression or run-time size, respectively.
Agree (and already implemented [42] and [n]).
> The ISO FAM case should also give an error,
Agree (and already implemented []). (Although I didn't really
distinguish it from an incomplete type.)
Although, if attributed with counted_by, we'd like it to work. But this
is not yet implemented.
> while the GNU fam case
> could return zero to be consistent with sizeof (not sure).
Agree. I've made it consistent with sizeof, and it returns 0.
BTW, I'd like to add full support for zero-sized arrays in the language.
I was discussing it with Jens Gustedt last week, and will start some
discussion about it in a separate thread.
> The last
> case should return a non-constant.
The last case [*] is only allowed in prototypes. How should we get the
non-constant value? It's just another way to say [], isn't it?
> If you reuse the sizeof code, it should be mostly correct, but
> maybe the last case needs to be revisted. In the following
> examples
>
> void foo(char (*a)[3][*], int (*x)[__lengthof__(*a)]);
> void bar(char (*a)[*][3], int (*x)[__lengthof__(*a)]);
>
> the array '*x' should be a regular fixed size array in foo
> but a VLA in 'bar'.
In the function prototype, it seems to be completely ignoring
__lengthof__, just as it ignores any expression, so I don't know if it's
working (I could try to print some debugging values to stderr from the
compiler, if we care about it).
$ cat muecker.h
void foo(char (*a)[3][*], int (*x)[__lengthof__(*a)]);
void bar(char (*a)[*][3], int (*x)[__lengthof__(*a)]);
void f(char (*a)[3][*], int (*x)[sizeof(*a)]);
void b(char (*a)[*][3], int (*x)[sizeof(*a)]);
$ /opt/local/gnu/gcc/lengthof/bin/gcc muecker.h -S
$
I assume the code above is not reaching my code.
In the function definition, it doesn't accept [*] at all, so I can't
handle it:
$ cat muecker.c
void foo(char (*a)[3][*], int (*x)[__lengthof__(*a)]) {}
void bar(char (*a)[*][3], int (*x)[__lengthof__(*a)]) {}
void f(char (*a)[3][*], int (*x)[sizeof(*a)]) {}
void b(char (*a)[*][3], int (*x)[sizeof(*a)]) {}
$ /opt/local/gnu/gcc/lengthof/bin/gcc muecker.c -S
muecker.c:1:1: error: ‘[*]’ not allowed in other than function prototype scope
1 | void foo(char (*a)[3][*], int (*x)[__lengthof__(*a)]) {}
| ^~~~
muecker.c:2:1: error: ‘[*]’ not allowed in other than function prototype scope
2 | void bar(char (*a)[*][3], int (*x)[__lengthof__(*a)]) {}
| ^~~~
muecker.c:3:1: error: ‘[*]’ not allowed in other than function prototype scope
3 | void f(char (*a)[3][*], int (*x)[sizeof(*a)]) {}
| ^~~~
muecker.c:4:1: error: ‘[*]’ not allowed in other than function prototype scope
4 | void b(char (*a)[*][3], int (*x)[sizeof(*a)]) {}
| ^~~~
Have a lovely day!
Alex
> Martin
--
<https://www.alejandro-colomar.es/>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [RFC v3 3/3] c: Add __lengthof__() operator
2024-08-04 16:40 ` Alejandro Colomar
@ 2024-08-04 16:43 ` Alejandro Colomar
2024-08-04 17:49 ` Alejandro Colomar
2024-08-04 17:28 ` Martin Uecker
1 sibling, 1 reply; 248+ messages in thread
From: Alejandro Colomar @ 2024-08-04 16:43 UTC (permalink / raw)
To: Martin Uecker
Cc: gcc-patches, Xavier Del Campo Romero, Gabriel Ravier,
Joseph Myers, Jakub Jelinek
[-- Attachment #1: Type: text/plain, Size: 1432 bytes --]
On Sun, Aug 04, 2024 at 06:40:14PM GMT, Alejandro Colomar wrote:
> > The last
> > case should return a non-constant.
>
> The last case [*] is only allowed in prototypes. How should we get the
> non-constant value? It's just another way to say [], isn't it?
>
> > If you reuse the sizeof code, it should be mostly correct, but
> > maybe the last case needs to be revisted. In the following
> > examples
> >
> > void foo(char (*a)[3][*], int (*x)[__lengthof__(*a)]);
> > void bar(char (*a)[*][3], int (*x)[__lengthof__(*a)]);
> >
> > the array '*x' should be a regular fixed size array in foo
> > but a VLA in 'bar'.
>
> In the function prototype, it seems to be completely ignoring
> __lengthof__, just as it ignores any expression, so I don't know if it's
> working (I could try to print some debugging values to stderr from the
> compiler, if we care about it).
Huh, no, my bad. It must be using the lengthof value. It needs to
match pointers to arrays of a given size. I'll test this.
>
> $ cat muecker.h
> void foo(char (*a)[3][*], int (*x)[__lengthof__(*a)]);
> void bar(char (*a)[*][3], int (*x)[__lengthof__(*a)]);
> void f(char (*a)[3][*], int (*x)[sizeof(*a)]);
> void b(char (*a)[*][3], int (*x)[sizeof(*a)]);
> $ /opt/local/gnu/gcc/lengthof/bin/gcc muecker.h -S
> $
>
> I assume the code above is not reaching my code.
--
<https://www.alejandro-colomar.es/>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [RFC v3 3/3] c: Add __lengthof__() operator
2024-08-04 16:40 ` Alejandro Colomar
2024-08-04 16:43 ` Alejandro Colomar
@ 2024-08-04 17:28 ` Martin Uecker
1 sibling, 0 replies; 248+ messages in thread
From: Martin Uecker @ 2024-08-04 17:28 UTC (permalink / raw)
To: Alejandro Colomar
Cc: gcc-patches, Xavier Del Campo Romero, Gabriel Ravier,
Joseph Myers, Jakub Jelinek
Hi Alex,
Am Sonntag, dem 04.08.2024 um 18:40 +0200 schrieb Alejandro Colomar:
> Hi Martin,
>
> On Sun, Aug 04, 2024 at 11:39:26AM GMT, Martin Uecker wrote:
> > Am Sonntag, dem 04.08.2024 um 10:25 +0200 schrieb Alejandro Colomar:
> > > Hi Martin,
> > >
> > > On Sun, Aug 04, 2024 at 07:38:49AM GMT, Martin Uecker wrote:
> > > > Am Sonntag, dem 04.08.2024 um 01:17 +0200 schrieb Alejandro Colomar:
> > > > >
> > > > > 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.
> > > >
> > > > And maybe flexible array members with "counted_by" attribute.
> > >
> > > Hmmm; I didn't know that one. Indeed. I'll have a look at implementing
> > > that in this patch set.
> >
> > But maybe wait for this:
> > https://gcc.gnu.org/bugzilla/show_bug.cgi?id=116016
>
> Maybe; if I don't find a way to implement it now, their patches may give
> me some tool to do it. I'll still try to do it now, just to try.
>
> I've drafted something by making build_counted_by_ref() an extern
> function, and then I wrote
>
> diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
> index 9f5feb83345..875d471a1f4 100644
> --- a/gcc/c-family/c-common.cc
> +++ b/gcc/c-family/c-common.cc
> @@ -4078,6 +4078,7 @@ c_alignof_expr (location_t loc, tree expr)
> tree
> c_lengthof_type (location_t loc, tree type)
> {
> + tree counted_by;
> enum tree_code type_code;
>
> type_code = TREE_CODE (type);
> @@ -4086,6 +4087,12 @@ c_lengthof_type (location_t loc, tree type)
> error_at (loc, "invalid application of %<lengthof%> to type %qT", type);
> return error_mark_node;
> }
> +
> + counted_by = lookup_attribute ("counted_by", DECL_ATTRIBUTES (type));
> + if (counted_by)
> + // XXX: How to build the counted_by ref without the parent struct type?
> + return build_counted_by_ref (NULL, type, counted_by);
> +
> if (!COMPLETE_TYPE_P (type))
> {
> error_at (loc,
>
> But since I don't have the struct to which the FAM belongs, I don't know
> how to get that working. Do you have any idea? Or maybe it's better to
> just wait for those patches to be merged, and reuse their
> infrastructure?
I would wait, also not to duplicate work.
>
> > > > > +
> > > > > +/* Implement the lengthof keyword: Return the length of an array,
> > > > > + that is, the number of elements in the array. */
> > > > > +
> > > > > +tree
> > > > > +c_lengthof_type (location_t loc, tree type)
> > > > > +{
> > > > > + 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);
> > > > > + return error_mark_node;
> > > > > + }
> > > >
> > > > I would swap these two errors, because the first is more specific and
> > > > less helpful if you pass an incomplete struct, where it would be better
> > > > to get the second error.
> > >
> > > Agree.
> > >
> > > BTW, I still don't understand what `if (! TYPE_DOMAIN (type))` means,
> > > within array_type_nelts_minus_one(). What code triggers that condition?
> > > Am I missing error handling for that? Thanks!
> >
> > For incomplete arrays, basically we have the following different
> > variants for arrays:
>
> Thanks! This list is very useful.
>
> > T[ ] incomplete: !TYPE_DOMAIN
> > T[1] constant size: TYPE_MAX_VALUE == INTEGER_CST
>
> I guess that old flexible-array members using [1] are understood as
> normal arrays [42], right?
I think so.
>
> > T[n] variable size: TYPE_MAX_VALUE != INTEGER_CST
> > T[0] flexible array member: !TYPE_MAX_VALUE && !C_TYPE_VARIABLE_SIZE
> > (ISO version T[0] has TYPE_SIZE == NULL_TREE)
>
> ISO version is T[], right? Did ISO add support for zero-sized arrays?
No, my fault. ISO FAMs are T[].
>
> > T[*] unspecified variable size: !TYPE_MAX_VALUE && C_TYPE_VARIABLE_SIZE
>
> This is not allowed aoutside of function-prototype scope. And there it
> decays to pointer way before reaching __lengthof__. So we can't handle
> that at the moment.
But __lengthof__ can occur at function prototype scope,
although this is then not evaluated
> However, we'll have to keep it in mind for when you
> do the change to keep the array types of function prototypes. When that
> happens, I guess we'll have to reject these arrays.
I am not yet sure this will work, but let's see.
>
> >
> > The first should give an error.
>
> Agree (and already implemented []).
>
> > The next two should work giving an
> > integer constant expression or run-time size, respectively.
>
> Agree (and already implemented [42] and [n]).
>
> > The ISO FAM case should also give an error,
>
> Agree (and already implemented []). (Although I didn't really
> distinguish it from an incomplete type.)
>
> Although, if attributed with counted_by, we'd like it to work. But this
> is not yet implemented.
>
> > while the GNU fam case
> > could return zero to be consistent with sizeof (not sure).
>
> Agree. I've made it consistent with sizeof, and it returns 0.
>
> BTW, I'd like to add full support for zero-sized arrays in the language.
> I was discussing it with Jens Gustedt last week, and will start some
> discussion about it in a separate thread.
Ok, I would support this, but there are plenty of issues.
> > The last
> > case should return a non-constant.
>
> The last case [*] is only allowed in prototypes. How should we get the
> non-constant value? It's just another way to say [], isn't it?
No, it is the same as [n] but can be used only where the
length is not needed because it is never evaluated. So
you do not get a value at run-time, but as shown below it
matters that the value you would get is not an integer constant.
Basically, you need to check whether the first dimension is
variable and this case should be handled correctly. You
can look at comptypes_internal etc. how this could be done.
Martin
>
> > If you reuse the sizeof code, it should be mostly correct, but
> > maybe the last case needs to be revisted. In the following
> > examples
> >
> > void foo(char (*a)[3][*], int (*x)[__lengthof__(*a)]);
> > void bar(char (*a)[*][3], int (*x)[__lengthof__(*a)]);
> >
> > the array '*x' should be a regular fixed size array in foo
> > but a VLA in 'bar'.
>
> In the function prototype, it seems to be completely ignoring
> __lengthof__, just as it ignores any expression, so I don't know if it's
> working (I could try to print some debugging values to stderr from the
> compiler, if we care about it).
>
> $ cat muecker.h
> void foo(char (*a)[3][*], int (*x)[__lengthof__(*a)]);
> void bar(char (*a)[*][3], int (*x)[__lengthof__(*a)]);
> void f(char (*a)[3][*], int (*x)[sizeof(*a)]);
> void b(char (*a)[*][3], int (*x)[sizeof(*a)]);
> $ /opt/local/gnu/gcc/lengthof/bin/gcc muecker.h -S
> $
>
> I assume the code above is not reaching my code.
>
> In the function definition, it doesn't accept [*] at all, so I can't
> handle it:
>
> $ cat muecker.c
> void foo(char (*a)[3][*], int (*x)[__lengthof__(*a)]) {}
> void bar(char (*a)[*][3], int (*x)[__lengthof__(*a)]) {}
> void f(char (*a)[3][*], int (*x)[sizeof(*a)]) {}
> void b(char (*a)[*][3], int (*x)[sizeof(*a)]) {}
> $ /opt/local/gnu/gcc/lengthof/bin/gcc muecker.c -S
> muecker.c:1:1: error: ‘[*]’ not allowed in other than function prototype scope
> 1 | void foo(char (*a)[3][*], int (*x)[__lengthof__(*a)]) {}
> | ^~~~
> muecker.c:2:1: error: ‘[*]’ not allowed in other than function prototype scope
> 2 | void bar(char (*a)[*][3], int (*x)[__lengthof__(*a)]) {}
> | ^~~~
> muecker.c:3:1: error: ‘[*]’ not allowed in other than function prototype scope
> 3 | void f(char (*a)[3][*], int (*x)[sizeof(*a)]) {}
> | ^~~~
> muecker.c:4:1: error: ‘[*]’ not allowed in other than function prototype scope
> 4 | void b(char (*a)[*][3], int (*x)[sizeof(*a)]) {}
> | ^~~~
>
>
> Have a lovely day!
> Alex
>
> > Martin
>
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [RFC v3 3/3] c: Add __lengthof__() operator
2024-08-04 16:43 ` Alejandro Colomar
@ 2024-08-04 17:49 ` Alejandro Colomar
2024-08-04 18:02 ` Martin Uecker
0 siblings, 1 reply; 248+ messages in thread
From: Alejandro Colomar @ 2024-08-04 17:49 UTC (permalink / raw)
To: Martin Uecker
Cc: gcc-patches, Xavier Del Campo Romero, Gabriel Ravier,
Joseph Myers, Jakub Jelinek
[-- Attachment #1: Type: text/plain, Size: 2360 bytes --]
Hi Martin,
On Sun, Aug 04, 2024 at 06:43:46PM GMT, Alejandro Colomar wrote:
> On Sun, Aug 04, 2024 at 06:40:14PM GMT, Alejandro Colomar wrote:
> > > The last
> > > case should return a non-constant.
> >
> > The last case [*] is only allowed in prototypes. How should we get the
> > non-constant value? It's just another way to say [], isn't it?
> >
> > > If you reuse the sizeof code, it should be mostly correct, but
> > > maybe the last case needs to be revisted. In the following
> > > examples
> > >
> > > void foo(char (*a)[3][*], int (*x)[__lengthof__(*a)]);
> > > void bar(char (*a)[*][3], int (*x)[__lengthof__(*a)]);
> > >
> > > the array '*x' should be a regular fixed size array in foo
> > > but a VLA in 'bar'.
> >
> > In the function prototype, it seems to be completely ignoring
> > __lengthof__, just as it ignores any expression, so I don't know if it's
> > working (I could try to print some debugging values to stderr from the
> > compiler, if we care about it).
>
> Huh, no, my bad. It must be using the lengthof value. It needs to
> match pointers to arrays of a given size. I'll test this.
Is this missing diagnostics?
$ cat star.c
void foo(char (*a)[3][*], int (*x)[__lengthof__(*a)]);
void bar(char (*a)[*][3], int (*x)[__lengthof__(*a)]);
void foos(char (*a)[3][*], int (*x)[sizeof(*a)]);
void bars(char (*a)[*][3], int (*x)[sizeof(*a)]);
int
main(void)
{
int i3[3];
int i5[5];
char c35[3][5];
char c53[5][3];
foo(&c35, &i3);
foo(&c35, &i5); // I'd expect this to fail
bar(&c53, &i3); // I'd expect this to fail
bar(&c53, &i5);
foos(&c35, &i3);
foos(&c35, &i5); // I'd expect this to fail
bars(&c53, &i3); // I'd expect this to fail
bars(&c53, &i5);
}
$ /opt/local/gnu/gcc/lengthof/bin/gcc -Wall -Wextra star.c -S
$
Cheers,
Alex
>
> >
> > $ cat muecker.h
> > void foo(char (*a)[3][*], int (*x)[__lengthof__(*a)]);
> > void bar(char (*a)[*][3], int (*x)[__lengthof__(*a)]);
> > void f(char (*a)[3][*], int (*x)[sizeof(*a)]);
> > void b(char (*a)[*][3], int (*x)[sizeof(*a)]);
> > $ /opt/local/gnu/gcc/lengthof/bin/gcc muecker.h -S
> > $
> >
> > I assume the code above is not reaching my code.
>
> --
> <https://www.alejandro-colomar.es/>
--
<https://www.alejandro-colomar.es/>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [RFC v3 3/3] c: Add __lengthof__() operator
2024-08-04 17:49 ` Alejandro Colomar
@ 2024-08-04 18:02 ` Martin Uecker
2024-08-04 18:34 ` Alejandro Colomar
0 siblings, 1 reply; 248+ messages in thread
From: Martin Uecker @ 2024-08-04 18:02 UTC (permalink / raw)
To: Alejandro Colomar
Cc: gcc-patches, Xavier Del Campo Romero, Gabriel Ravier,
Joseph Myers, Jakub Jelinek
Hi Alex,
Am Sonntag, dem 04.08.2024 um 19:49 +0200 schrieb Alejandro Colomar:
> Hi Martin,
>
> On Sun, Aug 04, 2024 at 06:43:46PM GMT, Alejandro Colomar wrote:
> > On Sun, Aug 04, 2024 at 06:40:14PM GMT, Alejandro Colomar wrote:
> > > > The last
> > > > case should return a non-constant.
> > >
> > > The last case [*] is only allowed in prototypes. How should we get the
> > > non-constant value? It's just another way to say [], isn't it?
> > >
> > > > If you reuse the sizeof code, it should be mostly correct, but
> > > > maybe the last case needs to be revisted. In the following
> > > > examples
> > > >
> > > > void foo(char (*a)[3][*], int (*x)[__lengthof__(*a)]);
> > > > void bar(char (*a)[*][3], int (*x)[__lengthof__(*a)]);
> > > >
> > > > the array '*x' should be a regular fixed size array in foo
> > > > but a VLA in 'bar'.
> > >
> > > In the function prototype, it seems to be completely ignoring
> > > __lengthof__, just as it ignores any expression, so I don't know if it's
> > > working (I could try to print some debugging values to stderr from the
> > > compiler, if we care about it).
> >
> > Huh, no, my bad. It must be using the lengthof value. It needs to
> > match pointers to arrays of a given size. I'll test this.
>
> Is this missing diagnostics?
>
> $ cat star.c
> void foo(char (*a)[3][*], int (*x)[__lengthof__(*a)]);
> void bar(char (*a)[*][3], int (*x)[__lengthof__(*a)]);
> void foos(char (*a)[3][*], int (*x)[sizeof(*a)]);
> void bars(char (*a)[*][3], int (*x)[sizeof(*a)]);
>
> int
> main(void)
> {
> int i3[3];
> int i5[5];
> char c35[3][5];
> char c53[5][3];
>
> foo(&c35, &i3);
> foo(&c35, &i5); // I'd expect this to fail
Yes, this should fail. The int (*)[5] is not
compatible with int(*)[3].
> bar(&c53, &i3); // I'd expect this to fail
This is no contraint violation, because int (*)[5] is
compatible with int (*i)[*], so this needs to be accepted.
It is then UB at run-time and the patches I posted recently
would catch this. When possible, a compile time warning
would be nice and I am also looking into this.
It would also be good if we could allow a compiler to
reject this at compile time... also something I am
thinking about.
> bar(&c53, &i5);
>
> foos(&c35, &i3);
> foos(&c35, &i5); // I'd expect this to fail
> bars(&c53, &i3); // I'd expect this to fail
These are both okay, because the sizeof is not an integer
constant expressions (both int[*][3] and int[3][*] have
variable size), so the last argument has to be compatible
with int[*] which they both are. Both would trigger
run-time UB then because the size is then 15.
Martin
> bars(&c53, &i5);
> }
> $ /opt/local/gnu/gcc/lengthof/bin/gcc -Wall -Wextra star.c -S
> $
>
> Cheers,
> Alex
>
> >
> > >
> > > $ cat muecker.h
> > > void foo(char (*a)[3][*], int (*x)[__lengthof__(*a)]);
> > > void bar(char (*a)[*][3], int (*x)[__lengthof__(*a)]);
> > > void f(char (*a)[3][*], int (*x)[sizeof(*a)]);
> > > void b(char (*a)[*][3], int (*x)[sizeof(*a)]);
> > > $ /opt/local/gnu/gcc/lengthof/bin/gcc muecker.h -S
> > > $
> > >
> > > I assume the code above is not reaching my code.
> >
> > --
> > <https://www.alejandro-colomar.es/>
>
>
>
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [RFC v3 3/3] c: Add __lengthof__() operator
2024-08-04 18:02 ` Martin Uecker
@ 2024-08-04 18:34 ` Alejandro Colomar
2024-08-04 19:10 ` Martin Uecker
2024-08-05 9:45 ` Alejandro Colomar
0 siblings, 2 replies; 248+ messages in thread
From: Alejandro Colomar @ 2024-08-04 18:34 UTC (permalink / raw)
To: Martin Uecker
Cc: gcc-patches, Xavier Del Campo Romero, Gabriel Ravier,
Joseph Myers, Jakub Jelinek
[-- Attachment #1: Type: text/plain, Size: 2574 bytes --]
On Sun, Aug 04, 2024 at 08:02:25PM GMT, Martin Uecker wrote:
> Hi Alex,
Hi Martin,
> > Is this missing diagnostics?
> >
> > $ cat star.c
> > void foo(char (*a)[3][*], int (*x)[__lengthof__(*a)]);
> > void bar(char (*a)[*][3], int (*x)[__lengthof__(*a)]);
> > void foos(char (*a)[3][*], int (*x)[sizeof(*a)]);
> > void bars(char (*a)[*][3], int (*x)[sizeof(*a)]);
> >
> > int
> > main(void)
> > {
> > int i3[3];
> > int i5[5];
> > char c35[3][5];
> > char c53[5][3];
> >
> > foo(&c35, &i3);
> > foo(&c35, &i5); // I'd expect this to fail
>
> Yes, this should fail. The int (*)[5] is not
> compatible with int(*)[3].
>
> > bar(&c53, &i3); // I'd expect this to fail
>
> This is no contraint violation, because int (*)[5] is
> compatible with int (*i)[*], so this needs to be accepted.
No constraint, but I'd expect a diagnostic from -Wextra (array-bounds?).
> It is then UB at run-time and the patches I posted recently
Can you please send a link to those patches?
> would catch this. When possible, a compile time warning
> would be nice and I am also looking into this.
>
> It would also be good if we could allow a compiler to
> reject this at compile time... also something I am
> thinking about.
Thanks!
>
> > bar(&c53, &i5);
> >
> > foos(&c35, &i3);
> > foos(&c35, &i5); // I'd expect this to fail
> > bars(&c53, &i3); // I'd expect this to fail
>
> These are both okay, because the sizeof is not an integer
> constant expressions (both int[*][3] and int[3][*] have
> variable size), so the last argument has to be compatible
> with int[*] which they both are. Both would trigger
> run-time UB then because the size is then 15.
D'oh! I screwed it. I wanted to have written this:
$ cat star.c
void foo(char (*a)[3][*], int (*x)[__lengthof__(*a)]);
void bar(char (*a)[*][3], int (*x)[__lengthof__(*a)]);
void foo2(char (*a)[3][*], int (*x)[sizeof(**a)]);
void bar2(char (*a)[*][3], int (*x)[sizeof(**a)]);
int
main(void)
{
int i3[3];
int i5[5];
char c35[3][5];
char c53[5][3];
foo(&c35, &i3);
foo(&c35, &i5); // I'd expect this to err
bar(&c53, &i3); // I'd expect this to warn
bar(&c53, &i5);
foo2(&c35, &i3); // I'd expect this to warn
foo2(&c35, &i5);
bar2(&c53, &i3);
//bar2(&c53, &i5); // error: -Wincompatible-pointer-types
}
$ /opt/local/gnu/gcc/lengthof/bin/gcc -Wall -Wextra star.c -S
$
>
> Martin
Cheers,
Alex
--
<https://www.alejandro-colomar.es/>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [RFC v3 3/3] c: Add __lengthof__() operator
2024-08-04 18:34 ` Alejandro Colomar
@ 2024-08-04 19:10 ` Martin Uecker
2024-08-05 9:45 ` Alejandro Colomar
1 sibling, 0 replies; 248+ messages in thread
From: Martin Uecker @ 2024-08-04 19:10 UTC (permalink / raw)
To: Alejandro Colomar
Cc: gcc-patches, Xavier Del Campo Romero, Gabriel Ravier,
Joseph Myers, Jakub Jelinek
Am Sonntag, dem 04.08.2024 um 20:34 +0200 schrieb Alejandro Colomar:
> On Sun, Aug 04, 2024 at 08:02:25PM GMT, Martin Uecker wrote:
> > Hi Alex,
>
> Hi Martin,
>
> > > Is this missing diagnostics?
> > >
> > > $ cat star.c
> > > void foo(char (*a)[3][*], int (*x)[__lengthof__(*a)]);
> > > void bar(char (*a)[*][3], int (*x)[__lengthof__(*a)]);
> > > void foos(char (*a)[3][*], int (*x)[sizeof(*a)]);
> > > void bars(char (*a)[*][3], int (*x)[sizeof(*a)]);
> > >
> > > int
> > > main(void)
> > > {
> > > int i3[3];
> > > int i5[5];
> > > char c35[3][5];
> > > char c53[5][3];
> > >
> > > foo(&c35, &i3);
> > > foo(&c35, &i5); // I'd expect this to fail
> >
> > Yes, this should fail. The int (*)[5] is not
> > compatible with int(*)[3].
> >
> > > bar(&c53, &i3); // I'd expect this to fail
> >
> > This is no contraint violation, because int (*)[5] is
> > compatible with int (*i)[*], so this needs to be accepted.
>
> No constraint, but I'd expect a diagnostic from -Wextra (array-bounds?).
>
> > It is then UB at run-time and the patches I posted recently
>
> Can you please send a link to those patches?
https://gcc.gnu.org/pipermail/gcc-patches/2024-July/657253.html
Martin
>
> > would catch this. When possible, a compile time warning
> > would be nice and I am also looking into this.
> >
> > It would also be good if we could allow a compiler to
> > reject this at compile time... also something I am
> > thinking about.
>
> Thanks!
>
> >
> > > bar(&c53, &i5);
> > >
> > > foos(&c35, &i3);
> > > foos(&c35, &i5); // I'd expect this to fail
> > > bars(&c53, &i3); // I'd expect this to fail
> >
> > These are both okay, because the sizeof is not an integer
> > constant expressions (both int[*][3] and int[3][*] have
> > variable size), so the last argument has to be compatible
> > with int[*] which they both are. Both would trigger
> > run-time UB then because the size is then 15.
>
> D'oh! I screwed it. I wanted to have written this:
>
> $ cat star.c
> void foo(char (*a)[3][*], int (*x)[__lengthof__(*a)]);
> void bar(char (*a)[*][3], int (*x)[__lengthof__(*a)]);
> void foo2(char (*a)[3][*], int (*x)[sizeof(**a)]);
> void bar2(char (*a)[*][3], int (*x)[sizeof(**a)]);
>
> int
> main(void)
> {
> int i3[3];
> int i5[5];
> char c35[3][5];
> char c53[5][3];
>
> foo(&c35, &i3);
> foo(&c35, &i5); // I'd expect this to err
> bar(&c53, &i3); // I'd expect this to warn
> bar(&c53, &i5);
>
> foo2(&c35, &i3); // I'd expect this to warn
> foo2(&c35, &i5);
> bar2(&c53, &i3);
> //bar2(&c53, &i5); // error: -Wincompatible-pointer-types
> }
> $ /opt/local/gnu/gcc/lengthof/bin/gcc -Wall -Wextra star.c -S
> $
>
>
> >
> > Martin
>
> Cheers,
> Alex
>
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [RFC v3 3/3] c: Add __lengthof__() operator
2024-08-04 18:34 ` Alejandro Colomar
2024-08-04 19:10 ` Martin Uecker
@ 2024-08-05 9:45 ` Alejandro Colomar
2024-08-05 9:50 ` Jakub Jelinek
1 sibling, 1 reply; 248+ messages in thread
From: Alejandro Colomar @ 2024-08-05 9:45 UTC (permalink / raw)
To: Joseph Myers
Cc: Martin Uecker, gcc-patches, Xavier Del Campo Romero,
Gabriel Ravier, Jakub Jelinek, Kees Cook, Qing Zhao
[-- Attachment #1: Type: text/plain, Size: 1478 bytes --]
[CC += Kees, Qing]
Hi Joseph,
On Sun, Aug 04, 2024 at 08:34:24PM GMT, Alejandro Colomar wrote:
> On Sun, Aug 04, 2024 at 08:02:25PM GMT, Martin Uecker wrote:
> D'oh! I screwed it. I wanted to have written this:
>
> $ cat star.c
> void foo(char (*a)[3][*], int (*x)[__lengthof__(*a)]);
I think this answers your question of if we want __lengthof__ to
evaluate its operand if the top-level array is non-VLA but an inner
array is VLA.
We clearly want it to not evaluate, because we want this __lengthof__
to be a constant expression, ...
> void bar(char (*a)[*][3], int (*x)[__lengthof__(*a)]);
> void foo2(char (*a)[3][*], int (*x)[sizeof(**a)]);
> void bar2(char (*a)[*][3], int (*x)[sizeof(**a)]);
>
> int
> main(void)
> {
> int i3[3];
> int i5[5];
> char c35[3][5];
> char c53[5][3];
>
> foo(&c35, &i3);
> foo(&c35, &i5); // I'd expect this to err
... and thus cause a compile-time error here
(-Wincompatible-pointer-types).
I suspect we need to modify array_type_nelts_minus_one() for that; I'm
going to investigate.
Have a lovely day!
Alex
> bar(&c53, &i3); // I'd expect this to warn
> bar(&c53, &i5);
>
> foo2(&c35, &i3); // I'd expect this to warn
> foo2(&c35, &i5);
> bar2(&c53, &i3);
> //bar2(&c53, &i5); // error: -Wincompatible-pointer-types
> }
> $ /opt/local/gnu/gcc/lengthof/bin/gcc -Wall -Wextra star.c -S
> $
--
<https://www.alejandro-colomar.es/>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [RFC v3 3/3] c: Add __lengthof__() operator
2024-08-05 9:45 ` Alejandro Colomar
@ 2024-08-05 9:50 ` Jakub Jelinek
2024-08-05 10:33 ` Martin Uecker
0 siblings, 1 reply; 248+ messages in thread
From: Jakub Jelinek @ 2024-08-05 9:50 UTC (permalink / raw)
To: Alejandro Colomar
Cc: Joseph Myers, Martin Uecker, gcc-patches,
Xavier Del Campo Romero, Gabriel Ravier, Kees Cook, Qing Zhao
On Mon, Aug 05, 2024 at 11:45:56AM +0200, Alejandro Colomar wrote:
> [CC += Kees, Qing]
>
> Hi Joseph,
>
> On Sun, Aug 04, 2024 at 08:34:24PM GMT, Alejandro Colomar wrote:
> > On Sun, Aug 04, 2024 at 08:02:25PM GMT, Martin Uecker wrote:
> > D'oh! I screwed it. I wanted to have written this:
> >
> > $ cat star.c
> > void foo(char (*a)[3][*], int (*x)[__lengthof__(*a)]);
>
> I think this answers your question of if we want __lengthof__ to
> evaluate its operand if the top-level array is non-VLA but an inner
> array is VLA.
>
> We clearly want it to not evaluate, because we want this __lengthof__
> to be a constant expression, ...
But if you don't evaluate the argument, you can't handle counted_by.
Because for counted_by you need the expression (the object on which it is
used).
Jakub
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [RFC v3 3/3] c: Add __lengthof__() operator
2024-08-05 9:50 ` Jakub Jelinek
@ 2024-08-05 10:33 ` Martin Uecker
2024-08-05 20:10 ` Qing Zhao
0 siblings, 1 reply; 248+ messages in thread
From: Martin Uecker @ 2024-08-05 10:33 UTC (permalink / raw)
To: Jakub Jelinek, Alejandro Colomar
Cc: Joseph Myers, gcc-patches, Xavier Del Campo Romero,
Gabriel Ravier, Kees Cook, Qing Zhao
Am Montag, dem 05.08.2024 um 11:50 +0200 schrieb Jakub Jelinek:
> On Mon, Aug 05, 2024 at 11:45:56AM +0200, Alejandro Colomar wrote:
> > [CC += Kees, Qing]
> >
> > Hi Joseph,
> >
> > On Sun, Aug 04, 2024 at 08:34:24PM GMT, Alejandro Colomar wrote:
> > > On Sun, Aug 04, 2024 at 08:02:25PM GMT, Martin Uecker wrote:
> > > D'oh! I screwed it. I wanted to have written this:
> > >
> > > $ cat star.c
> > > void foo(char (*a)[3][*], int (*x)[__lengthof__(*a)]);
> >
> > I think this answers your question of if we want __lengthof__ to
> > evaluate its operand if the top-level array is non-VLA but an inner
> > array is VLA.
> >
> > We clearly want it to not evaluate, because we want this __lengthof__
> > to be a constant expression, ...
>
> But if you don't evaluate the argument, you can't handle counted_by.
> Because for counted_by you need the expression (the object on which it is
> used).
You would not evaluate only when the size is an integer constant
expression, which would not apply to counted_by.
Martin
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [RFC v3 3/3] c: Add __lengthof__() operator
2024-08-04 9:39 ` Martin Uecker
2024-08-04 16:40 ` Alejandro Colomar
@ 2024-08-05 11:55 ` Alejandro Colomar
2024-08-05 11:57 ` Alejandro Colomar
1 sibling, 1 reply; 248+ messages in thread
From: Alejandro Colomar @ 2024-08-05 11:55 UTC (permalink / raw)
To: Martin Uecker
Cc: gcc-patches, Xavier Del Campo Romero, Gabriel Ravier,
Joseph Myers, Jakub Jelinek
[-- Attachment #1: Type: text/plain, Size: 1537 bytes --]
Hi Martin,
On Sun, Aug 04, 2024 at 11:39:26AM GMT, Martin Uecker wrote:
> > BTW, I still don't understand what `if (! TYPE_DOMAIN (type))` means,
> > within array_type_nelts_minus_one(). What code triggers that condition?
> > Am I missing error handling for that? Thanks!
>
> For incomplete arrays, basically we have the following different
> variants for arrays:
>
> T[ ] incomplete: !TYPE_DOMAIN
> T[1] constant size: TYPE_MAX_VALUE == INTEGER_CST
> T[n] variable size: TYPE_MAX_VALUE != INTEGER_CST
> T[0] flexible array member: !TYPE_MAX_VALUE && !C_TYPE_VARIABLE_SIZE
> (ISO version T[0] has TYPE_SIZE == NULL_TREE)
> T[*] unspecified variable size: !TYPE_MAX_VALUE && C_TYPE_VARIABLE_SIZE
Could you describe the following types? I've repeated the ones you
already described, deduplicated some that have a different meaning in
different contexts, and added some multi-dimensional arrays.
T[ ] (incomplete type; function parameter)
T[ ] (flexible array member)
T[0] (zero-size array)
T[0] (GNU flexible array member)
T[1] (old flexible array member)
T[7] (constant size)
T[7][n] (constant size with inner variable size)
T[7][*] (constant size with inner unspecified size)
T[n] (variable size)
T[*] (unspecified size)
That would help with the [*] issues I'm investigating. I think
array_type_nelts_minus_one(T[7][*]) is not giving a constant expression,
and I'd like to fix that.
Have a lovely day!
Alex
--
<https://www.alejandro-colomar.es/>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [RFC v3 3/3] c: Add __lengthof__() operator
2024-08-05 11:55 ` Alejandro Colomar
@ 2024-08-05 11:57 ` Alejandro Colomar
2024-08-05 11:58 ` Alejandro Colomar
0 siblings, 1 reply; 248+ messages in thread
From: Alejandro Colomar @ 2024-08-05 11:57 UTC (permalink / raw)
To: Martin Uecker
Cc: gcc-patches, Xavier Del Campo Romero, Gabriel Ravier,
Joseph Myers, Jakub Jelinek
[-- Attachment #1: Type: text/plain, Size: 1825 bytes --]
On Mon, Aug 05, 2024 at 01:55:50PM GMT, Alejandro Colomar wrote:
> Hi Martin,
>
> On Sun, Aug 04, 2024 at 11:39:26AM GMT, Martin Uecker wrote:
> > > BTW, I still don't understand what `if (! TYPE_DOMAIN (type))` means,
> > > within array_type_nelts_minus_one(). What code triggers that condition?
> > > Am I missing error handling for that? Thanks!
> >
> > For incomplete arrays, basically we have the following different
> > variants for arrays:
> >
> > T[ ] incomplete: !TYPE_DOMAIN
> > T[1] constant size: TYPE_MAX_VALUE == INTEGER_CST
> > T[n] variable size: TYPE_MAX_VALUE != INTEGER_CST
> > T[0] flexible array member: !TYPE_MAX_VALUE && !C_TYPE_VARIABLE_SIZE
> > (ISO version T[0] has TYPE_SIZE == NULL_TREE)
> > T[*] unspecified variable size: !TYPE_MAX_VALUE && C_TYPE_VARIABLE_SIZE
>
> Could you describe the following types? I've repeated the ones you
> already described, deduplicated some that have a different meaning in
> different contexts, and added some multi-dimensional arrays.
>
> T[ ] (incomplete type; function parameter)
> T[ ] (flexible array member)
> T[0] (zero-size array)
> T[0] (GNU flexible array member)
> T[1] (old flexible array member)
> T[7] (constant size)
> T[7][n] (constant size with inner variable size)
> T[7][*] (constant size with inner unspecified size)
And please also describe T[7][4], although I expect that to be just the
same as T[7].
> T[n] (variable size)
> T[*] (unspecified size)
>
> That would help with the [*] issues I'm investigating. I think
> array_type_nelts_minus_one(T[7][*]) is not giving a constant expression,
> and I'd like to fix that.
>
> Have a lovely day!
> Alex
>
> --
> <https://www.alejandro-colomar.es/>
--
<https://www.alejandro-colomar.es/>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [RFC v3 3/3] c: Add __lengthof__() operator
2024-08-05 11:57 ` Alejandro Colomar
@ 2024-08-05 11:58 ` Alejandro Colomar
2024-08-05 11:59 ` Alejandro Colomar
0 siblings, 1 reply; 248+ messages in thread
From: Alejandro Colomar @ 2024-08-05 11:58 UTC (permalink / raw)
To: Martin Uecker
Cc: gcc-patches, Xavier Del Campo Romero, Gabriel Ravier,
Joseph Myers, Jakub Jelinek
[-- Attachment #1: Type: text/plain, Size: 2100 bytes --]
On Mon, Aug 05, 2024 at 01:57:35PM GMT, Alejandro Colomar wrote:
> On Mon, Aug 05, 2024 at 01:55:50PM GMT, Alejandro Colomar wrote:
> > Hi Martin,
> >
> > On Sun, Aug 04, 2024 at 11:39:26AM GMT, Martin Uecker wrote:
> > > > BTW, I still don't understand what `if (! TYPE_DOMAIN (type))` means,
> > > > within array_type_nelts_minus_one(). What code triggers that condition?
> > > > Am I missing error handling for that? Thanks!
> > >
> > > For incomplete arrays, basically we have the following different
> > > variants for arrays:
> > >
> > > T[ ] incomplete: !TYPE_DOMAIN
> > > T[1] constant size: TYPE_MAX_VALUE == INTEGER_CST
> > > T[n] variable size: TYPE_MAX_VALUE != INTEGER_CST
> > > T[0] flexible array member: !TYPE_MAX_VALUE && !C_TYPE_VARIABLE_SIZE
> > > (ISO version T[0] has TYPE_SIZE == NULL_TREE)
> > > T[*] unspecified variable size: !TYPE_MAX_VALUE && C_TYPE_VARIABLE_SIZE
> >
> > Could you describe the following types? I've repeated the ones you
> > already described, deduplicated some that have a different meaning in
> > different contexts, and added some multi-dimensional arrays.
> >
> > T[ ] (incomplete type; function parameter)
> > T[ ] (flexible array member)
> > T[0] (zero-size array)
> > T[0] (GNU flexible array member)
> > T[1] (old flexible array member)
> > T[7] (constant size)
> > T[7][n] (constant size with inner variable size)
> > T[7][*] (constant size with inner unspecified size)
>
> And please also describe T[7][4], although I expect that to be just the
> same as T[7].
And it would also be interesting to describe T[7][ ].
>
> > T[n] (variable size)
> > T[*] (unspecified size)
> >
> > That would help with the [*] issues I'm investigating. I think
> > array_type_nelts_minus_one(T[7][*]) is not giving a constant expression,
> > and I'd like to fix that.
> >
> > Have a lovely day!
> > Alex
> >
> > --
> > <https://www.alejandro-colomar.es/>
>
>
>
> --
> <https://www.alejandro-colomar.es/>
--
<https://www.alejandro-colomar.es/>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [RFC v3 3/3] c: Add __lengthof__() operator
2024-08-05 11:58 ` Alejandro Colomar
@ 2024-08-05 11:59 ` Alejandro Colomar
2024-08-05 13:35 ` Martin Uecker
0 siblings, 1 reply; 248+ messages in thread
From: Alejandro Colomar @ 2024-08-05 11:59 UTC (permalink / raw)
To: Martin Uecker
Cc: gcc-patches, Xavier Del Campo Romero, Gabriel Ravier,
Joseph Myers, Jakub Jelinek
[-- Attachment #1: Type: text/plain, Size: 2393 bytes --]
On Mon, Aug 05, 2024 at 01:58:18PM GMT, Alejandro Colomar wrote:
> On Mon, Aug 05, 2024 at 01:57:35PM GMT, Alejandro Colomar wrote:
> > On Mon, Aug 05, 2024 at 01:55:50PM GMT, Alejandro Colomar wrote:
> > > Hi Martin,
> > >
> > > On Sun, Aug 04, 2024 at 11:39:26AM GMT, Martin Uecker wrote:
> > > > > BTW, I still don't understand what `if (! TYPE_DOMAIN (type))` means,
> > > > > within array_type_nelts_minus_one(). What code triggers that condition?
> > > > > Am I missing error handling for that? Thanks!
> > > >
> > > > For incomplete arrays, basically we have the following different
> > > > variants for arrays:
> > > >
> > > > T[ ] incomplete: !TYPE_DOMAIN
> > > > T[1] constant size: TYPE_MAX_VALUE == INTEGER_CST
> > > > T[n] variable size: TYPE_MAX_VALUE != INTEGER_CST
> > > > T[0] flexible array member: !TYPE_MAX_VALUE && !C_TYPE_VARIABLE_SIZE
> > > > (ISO version T[0] has TYPE_SIZE == NULL_TREE)
> > > > T[*] unspecified variable size: !TYPE_MAX_VALUE && C_TYPE_VARIABLE_SIZE
> > >
> > > Could you describe the following types? I've repeated the ones you
> > > already described, deduplicated some that have a different meaning in
> > > different contexts, and added some multi-dimensional arrays.
> > >
> > > T[ ] (incomplete type; function parameter)
> > > T[ ] (flexible array member)
> > > T[0] (zero-size array)
> > > T[0] (GNU flexible array member)
> > > T[1] (old flexible array member)
> > > T[7] (constant size)
> > > T[7][n] (constant size with inner variable size)
> > > T[7][*] (constant size with inner unspecified size)
> >
> > And please also describe T[7][4], although I expect that to be just the
> > same as T[7].
>
> And it would also be interesting to describe T[7][ ].
And maybe also:
T[n][m]
T[n][*]
T[n][ ]
T[n][7]
>
> >
> > > T[n] (variable size)
> > > T[*] (unspecified size)
> > >
> > > That would help with the [*] issues I'm investigating. I think
> > > array_type_nelts_minus_one(T[7][*]) is not giving a constant expression,
> > > and I'd like to fix that.
> > >
> > > Have a lovely day!
> > > Alex
> > >
> > > --
> > > <https://www.alejandro-colomar.es/>
> >
> >
> >
> > --
> > <https://www.alejandro-colomar.es/>
>
>
>
> --
> <https://www.alejandro-colomar.es/>
--
<https://www.alejandro-colomar.es/>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [RFC v3 3/3] c: Add __lengthof__() operator
2024-08-05 11:59 ` Alejandro Colomar
@ 2024-08-05 13:35 ` Martin Uecker
2024-08-05 15:27 ` Alejandro Colomar
0 siblings, 1 reply; 248+ messages in thread
From: Martin Uecker @ 2024-08-05 13:35 UTC (permalink / raw)
To: Alejandro Colomar
Cc: gcc-patches, Xavier Del Campo Romero, Gabriel Ravier,
Joseph Myers, Jakub Jelinek
Am Montag, dem 05.08.2024 um 13:59 +0200 schrieb Alejandro Colomar:
> On Mon, Aug 05, 2024 at 01:58:18PM GMT, Alejandro Colomar wrote:
> > On Mon, Aug 05, 2024 at 01:57:35PM GMT, Alejandro Colomar wrote:
> > > On Mon, Aug 05, 2024 at 01:55:50PM GMT, Alejandro Colomar wrote:
> > > > Hi Martin,
> > > >
> > > > On Sun, Aug 04, 2024 at 11:39:26AM GMT, Martin Uecker wrote:
> > > > > > BTW, I still don't understand what `if (! TYPE_DOMAIN (type))` means,
> > > > > > within array_type_nelts_minus_one(). What code triggers that condition?
> > > > > > Am I missing error handling for that? Thanks!
> > > > >
> > > > > For incomplete arrays, basically we have the following different
> > > > > variants for arrays:
> > > > >
> > > > > T[ ] incomplete: !TYPE_DOMAIN
> > > > > T[1] constant size: TYPE_MAX_VALUE == INTEGER_CST
> > > > > T[n] variable size: TYPE_MAX_VALUE != INTEGER_CST
> > > > > T[0] flexible array member: !TYPE_MAX_VALUE && !C_TYPE_VARIABLE_SIZE
> > > > > (ISO version T[0] has TYPE_SIZE == NULL_TREE)
> > > > > T[*] unspecified variable size: !TYPE_MAX_VALUE && C_TYPE_VARIABLE_SIZE
> > > >
> > > > Could you describe the following types? I've repeated the ones you
> > > > already described, deduplicated some that have a different meaning in
> > > > different contexts, and added some multi-dimensional arrays.
> > > >
> > > > T[ ] (incomplete type; function parameter)
> > > > T[ ] (flexible array member)
> > > > T[0] (zero-size array)
> > > > T[0] (GNU flexible array member)
> > > > T[1] (old flexible array member)
> > > > T[7] (constant size)
> > > > T[7][n] (constant size with inner variable size)
> > > > T[7][*] (constant size with inner unspecified size)
> > >
> > > And please also describe T[7][4], although I expect that to be just the
> > > same as T[7].
> >
> > And it would also be interesting to describe T[7][ ].
>
> And maybe also:
>
> T[n][m]
> T[n][*]
> T[n][ ]
> T[n][7]
I do not understand your question. What do you mean by
"describe the type"?
But I think you might make it unnecessarily complicated. It
should be sufficient to look at the outermost size. You
can completely ignore thatever happens There
should be three cases if I am not mistaken:
- incomplete (includes ISO FAM) -> error
- constant (includes GNU FAM) -> return fixed size
- variable (includes unspecified) -> evaluate the
argument and return the size, while making sure it is
visibly non-constant.
To check that the array has a variable length, you can use
the same logic as in comptypes_internal (cf. d1_variable).
It is possible that you can not properly distinguish between
int a[0][n];
int a[*][n];
those two cases. The logic will treat the first as the second.
I think this is ok for now. All this array stuff should be
implified and refactored anyway, but this is for another time.
I am also not sure you even need to use array_type_nelts in C
because there is never a non-zero minimum size.
Martin
>
> >
> > >
> > > > T[n] (variable size)
> > > > T[*] (unspecified size)
> > > >
> > > > That would help with the [*] issues I'm investigating. I think
> > > > array_type_nelts_minus_one(T[7][*]) is not giving a constant expression,
> > > > and I'd like to fix that.
> > > >
> > > > Have a lovely day!
> > > > Alex
> > > >
> > > > --
> > > > <https://www.alejandro-colomar.es/>
> > >
> > >
> > >
> > > --
> > > <https://www.alejandro-colomar.es/>
> >
> >
> >
> > --
> > <https://www.alejandro-colomar.es/>
>
>
>
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [RFC v3 3/3] c: Add __lengthof__() operator
2024-08-05 13:35 ` Martin Uecker
@ 2024-08-05 15:27 ` Alejandro Colomar
2024-08-05 16:05 ` Martin Uecker
0 siblings, 1 reply; 248+ messages in thread
From: Alejandro Colomar @ 2024-08-05 15:27 UTC (permalink / raw)
To: Martin Uecker
Cc: gcc-patches, Xavier Del Campo Romero, Gabriel Ravier,
Joseph Myers, Jakub Jelinek
[-- Attachment #1: Type: text/plain, Size: 6381 bytes --]
Hi Martin,
On Mon, Aug 05, 2024 at 03:35:06PM GMT, Martin Uecker wrote:
> > > > > > For incomplete arrays, basically we have the following different
> > > > > > variants for arrays:
> > > > > >
> > > > > > T[ ] incomplete: !TYPE_DOMAIN
> > > > > > T[1] constant size: TYPE_MAX_VALUE == INTEGER_CST
> > > > > > T[n] variable size: TYPE_MAX_VALUE != INTEGER_CST
> > > > > > T[0] flexible array member: !TYPE_MAX_VALUE && !C_TYPE_VARIABLE_SIZE
> > > > > > (ISO version T[0] has TYPE_SIZE == NULL_TREE)
> > > > > > T[*] unspecified variable size: !TYPE_MAX_VALUE && C_TYPE_VARIABLE_SIZE
> > > > >
> > > > > Could you describe the following types? I've repeated the ones you
> > > > > already described, deduplicated some that have a different meaning in
> > > > > different contexts, and added some multi-dimensional arrays.
> > > > >
> > > > > T[ ] (incomplete type; function parameter)
> > > > > T[ ] (flexible array member)
> > > > > T[0] (zero-size array)
> > > > > T[0] (GNU flexible array member)
> > > > > T[1] (old flexible array member)
> > > > > T[7] (constant size)
> > > > > T[7][n] (constant size with inner variable size)
> > > > > T[7][*] (constant size with inner unspecified size)
> > > >
> > > > And please also describe T[7][4], although I expect that to be just the
> > > > same as T[7].
> > >
> > > And it would also be interesting to describe T[7][ ].
> >
> > And maybe also:
> >
> > T[n][m]
> > T[n][*]
> > T[n][ ]
> > T[n][7]
>
> I do not understand your question. What do you mean by
> "describe the type"?
I had in mind what you already did above, (e.g.,
T[1] constant size: TYPE_MAX_VALUE == INTEGER_CST), but with a more
comprehensive list. comptypes_internal() seems what I wanted.
> But I think you might make it unnecessarily complicated. It
> should be sufficient to look at the outermost size. You
> can completely ignore thatever happens There
> should be three cases if I am not mistaken:
>
> - incomplete (includes ISO FAM) -> error
> - constant (includes GNU FAM) -> return fixed size
> - variable (includes unspecified) -> evaluate the
> argument and return the size, while making sure it is
> visibly non-constant.
>
> To check that the array has a variable length, you can use
> the same logic as in comptypes_internal (cf. d1_variable).
Hmmm, comptypes_internal() has taught me what I was asking here.
However, it seems to not be enough for what I actually need.
Here's my problem:
The array is correctly considered a fixed-length array. I know it
because the following debugging code:
+fprintf(stderr, "ALX: %s() %d\n", __func__, __LINE__);
+tree dom = TYPE_DOMAIN (type);
+int zero = !TYPE_MAX_VALUE (dom);
+fprintf(stderr, "ALX: zero: %d\n", zero);
+int var0 = !zero
+ && (TREE_CODE (TYPE_MIN_VALUE (dom)) != INTEGER_CST
+ || TREE_CODE (TYPE_MAX_VALUE (dom)) != INTEGER_CST);
+fprintf(stderr, "ALX: var: %d\n", var0);
+int var = var0 || (zero && TYPE_LANG_FLAG_1(type));
+fprintf(stderr, "ALX: var: %d\n", var);
+ ret = array_type_nelts_top (type);
+fprintf(stderr, "ALX: %s() %d\n", __func__, __LINE__);
prints:
ALX: c_lengthof_type() 4098
ALX: zero: 0
ALX: var: 0
ALX: var: 0
ALX: c_lengthof_type() 4109
for
void foo(char (*a)[3][*], int (*x)[__lengthof__(*a)]);
That differs from
ALX: c_lengthof_type() 4098
ALX: zero: 1
ALX: var: 0
ALX: var: 1
ALX: c_lengthof_type() 4109
for
void bar(char (*a)[*][3], int (*x)[__lengthof__(*a)]);
However, if I turn on -Wvla, both get a warning:
len.c: At top level:
len.c:288:1: warning: ISO C90 forbids variable length array ‘x’ [-Wvla]
288 | void foo(char (*a)[3][*], int (*x)[__lengthof__(*a)]);
| ^~~~
len.c:289:1: warning: ISO C90 forbids variable length array ‘x’ [-Wvla]
289 | void bar(char (*a)[*][3], int (*x)[__lengthof__(*a)]);
| ^~~~
I suspect that the problem is in:
$ grepc -tfd array_type_nelts_minus_one gcc
gcc/tree.cc:tree
array_type_nelts_minus_one (const_tree type)
{
tree index_type, min, max;
/* If they did it with unspecified bounds, then we should have already
given an error about it before we got here. */
if (! TYPE_DOMAIN (type))
return error_mark_node;
index_type = TYPE_DOMAIN (type);
min = TYPE_MIN_VALUE (index_type);
max = TYPE_MAX_VALUE (index_type);
/* TYPE_MAX_VALUE may not be set if the array has unknown length. */
if (!max)
{
/* zero sized arrays are represented from C FE as complete types with
NULL TYPE_MAX_VALUE and zero TYPE_SIZE, while C++ FE represents
them as min 0, max -1. */
if (COMPLETE_TYPE_P (type)
&& integer_zerop (TYPE_SIZE (type))
&& integer_zerop (min))
return build_int_cst (TREE_TYPE (min), -1);
return error_mark_node;
}
return (integer_zerop (min)
? max
: fold_build2 (MINUS_EXPR, TREE_TYPE (max), max, min));
}
With some debugging code, I've seen that in the fixed-length case, this
reaches the last return (integer_zerop() is true, so it returns max),
which is exactly the same as with any normal fixed-length array.
In the variable-length case (i.e., [*][3]), it returns build_int_cst().
So, it seems my problem is that 'max' does not represent an integer
constant, even though we know it is. Can we coerce it to an integer
constant somehow? Or maybe it's some of the in_lengthof that's messing
with me?
>
> It is possible that you can not properly distinguish between
>
> int a[0][n];
> int a[*][n];
>
> those two cases. The logic will treat the first as the second.
Those can be distinguished. [0] triggers the zero test, while [*]
triggers the second var test.
> I think this is ok for now. All this array stuff should be
> implified and refactored anyway, but this is for another time.
>
>
> I am also not sure you even need to use array_type_nelts in C
> because there is never a non-zero minimum size.
How should I get the number of elements without array_type_nelts()? Is
there any other existing way to get it? It just had a good name that
matched my grep, but maybe I'm missing something easier.
Thanks!
Cheers,
Alex
> Martin
--
<https://www.alejandro-colomar.es/>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [RFC v3 3/3] c: Add __lengthof__() operator
2024-08-05 15:27 ` Alejandro Colomar
@ 2024-08-05 16:05 ` Martin Uecker
2024-08-05 17:47 ` Alejandro Colomar
0 siblings, 1 reply; 248+ messages in thread
From: Martin Uecker @ 2024-08-05 16:05 UTC (permalink / raw)
To: Alejandro Colomar
Cc: gcc-patches, Xavier Del Campo Romero, Gabriel Ravier,
Joseph Myers, Jakub Jelinek
Am Montag, dem 05.08.2024 um 17:27 +0200 schrieb Alejandro Colomar:
> Hi Martin,
>
...
> > But I think you might make it unnecessarily complicated. It
> > should be sufficient to look at the outermost size. You
> > can completely ignore thatever happens There
> > should be three cases if I am not mistaken:
> >
> > - incomplete (includes ISO FAM) -> error
> > - constant (includes GNU FAM) -> return fixed size
> > - variable (includes unspecified) -> evaluate the
> > argument and return the size, while making sure it is
> > visibly non-constant.
> >
> > To check that the array has a variable length, you can use
> > the same logic as in comptypes_internal (cf. d1_variable).
>
> Hmmm, comptypes_internal() has taught me what I was asking here.
> However, it seems to not be enough for what I actually need.
>
> Here's my problem:
>
> The array is correctly considered a fixed-length array. I know it
> because the following debugging code:
>
> +fprintf(stderr, "ALX: %s() %d\n", __func__, __LINE__);
> +tree dom = TYPE_DOMAIN (type);
> +int zero = !TYPE_MAX_VALUE (dom);
> +fprintf(stderr, "ALX: zero: %d\n", zero);
> +int var0 = !zero
> + && (TREE_CODE (TYPE_MIN_VALUE (dom)) != INTEGER_CST
> + || TREE_CODE (TYPE_MAX_VALUE (dom)) != INTEGER_CST);
> +fprintf(stderr, "ALX: var: %d\n", var0);
> +int var = var0 || (zero && TYPE_LANG_FLAG_1(type));
> +fprintf(stderr, "ALX: var: %d\n", var);
> + ret = array_type_nelts_top (type);
> +fprintf(stderr, "ALX: %s() %d\n", __func__, __LINE__);
>
> prints:
>
> ALX: c_lengthof_type() 4098
> ALX: zero: 0
> ALX: var: 0
> ALX: var: 0
> ALX: c_lengthof_type() 4109
>
> for
> void foo(char (*a)[3][*], int (*x)[__lengthof__(*a)]);
>
> That differs from
>
> ALX: c_lengthof_type() 4098
> ALX: zero: 1
> ALX: var: 0
> ALX: var: 1
> ALX: c_lengthof_type() 4109
>
> for
> void bar(char (*a)[*][3], int (*x)[__lengthof__(*a)]);
That looks good.
>
> However, if I turn on -Wvla, both get a warning:
>
> len.c: At top level:
> len.c:288:1: warning: ISO C90 forbids variable length array ‘x’ [-Wvla]
> 288 | void foo(char (*a)[3][*], int (*x)[__lengthof__(*a)]);
> | ^~~~
> len.c:289:1: warning: ISO C90 forbids variable length array ‘x’ [-Wvla]
> 289 | void bar(char (*a)[*][3], int (*x)[__lengthof__(*a)]);
> | ^~~~
>
You should check the the result you get from __lengthof__
is an integer constant expression in the first case.
> I suspect that the problem is in:
>
> $ grepc -tfd array_type_nelts_minus_one gcc
> gcc/tree.cc:tree
> array_type_nelts_minus_one (const_tree type)
> {
> tree index_type, min, max;
>
> /* If they did it with unspecified bounds, then we should have already
> given an error about it before we got here. */
> if (! TYPE_DOMAIN (type))
> return error_mark_node;
>
> index_type = TYPE_DOMAIN (type);
> min = TYPE_MIN_VALUE (index_type);
> max = TYPE_MAX_VALUE (index_type);
>
> /* TYPE_MAX_VALUE may not be set if the array has unknown length. */
> if (!max)
> {
> /* zero sized arrays are represented from C FE as complete types with
> NULL TYPE_MAX_VALUE and zero TYPE_SIZE, while C++ FE represents
> them as min 0, max -1. */
> if (COMPLETE_TYPE_P (type)
> && integer_zerop (TYPE_SIZE (type))
> && integer_zerop (min))
> return build_int_cst (TREE_TYPE (min), -1);
>
> return error_mark_node;
> }
>
> return (integer_zerop (min)
> ? max
> : fold_build2 (MINUS_EXPR, TREE_TYPE (max), max, min));
> }
>
> With some debugging code, I've seen that in the fixed-length case, this
> reaches the last return (integer_zerop() is true, so it returns max),
> which is exactly the same as with any normal fixed-length array.
>
> In the variable-length case (i.e., [*][3]), it returns build_int_cst().
>
> So, it seems my problem is that 'max' does not represent an integer
> constant, even though we know it is. Can we coerce it to an integer
> constant somehow? Or maybe it's some of the in_lengthof that's messing
> with me?
>
I would suspect the logic related to the C_MAYBE_CONST_EXPR.
In your original patch this still used C_TYPE_VARIABLE_SIZE,
which is not what we want for lengthof.
> >
> > It is possible that you can not properly distinguish between
> >
> > int a[0][n];
> > int a[*][n];
> >
> > those two cases. The logic will treat the first as the second.
>
> Those can be distinguished. [0] triggers the zero test, while [*]
> triggers the second var test.
Are you sure? Both types should have C_TYPE_VARIABLE_SIZE set to 1.
>
> > I think this is ok for now. All this array stuff should be
> > implified and refactored anyway, but this is for another time.
> >
> >
> > I am also not sure you even need to use array_type_nelts in C
> > because there is never a non-zero minimum size.
>
> How should I get the number of elements without array_type_nelts()? Is
> there any other existing way to get it? It just had a good name that
> matched my grep, but maybe I'm missing something easier.
Maybe it is ok, but there is also code which just adds one
to TYPE_MAX_VALUE.
Martin
>
> Thanks!
>
> Cheers,
> Alex
>
> > Martin
>
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [RFC v3 3/3] c: Add __lengthof__() operator
2024-08-05 16:05 ` Martin Uecker
@ 2024-08-05 17:47 ` Alejandro Colomar
0 siblings, 0 replies; 248+ messages in thread
From: Alejandro Colomar @ 2024-08-05 17:47 UTC (permalink / raw)
To: Martin Uecker
Cc: gcc-patches, Xavier Del Campo Romero, Gabriel Ravier,
Joseph Myers, Jakub Jelinek
[-- Attachment #1: Type: text/plain, Size: 4031 bytes --]
Hi Martin,
On Mon, Aug 05, 2024 at 06:05:15PM GMT, Martin Uecker wrote:
> >
> > However, if I turn on -Wvla, both get a warning:
> >
> > len.c: At top level:
> > len.c:288:1: warning: ISO C90 forbids variable length array ‘x’ [-Wvla]
> > 288 | void foo(char (*a)[3][*], int (*x)[__lengthof__(*a)]);
> > | ^~~~
> > len.c:289:1: warning: ISO C90 forbids variable length array ‘x’ [-Wvla]
> > 289 | void bar(char (*a)[*][3], int (*x)[__lengthof__(*a)]);
> > | ^~~~
> >
>
> You should check the the result you get from __lengthof__
> is an integer constant expression in the first case.
>
> > I suspect that the problem is in:
> >
> > $ grepc -tfd array_type_nelts_minus_one gcc
> > gcc/tree.cc:tree
> > array_type_nelts_minus_one (const_tree type)
> > {
> > tree index_type, min, max;
> >
> > /* If they did it with unspecified bounds, then we should have already
> > given an error about it before we got here. */
> > if (! TYPE_DOMAIN (type))
> > return error_mark_node;
> >
> > index_type = TYPE_DOMAIN (type);
> > min = TYPE_MIN_VALUE (index_type);
> > max = TYPE_MAX_VALUE (index_type);
> >
> > /* TYPE_MAX_VALUE may not be set if the array has unknown length. */
> > if (!max)
> > {
> > /* zero sized arrays are represented from C FE as complete types with
> > NULL TYPE_MAX_VALUE and zero TYPE_SIZE, while C++ FE represents
> > them as min 0, max -1. */
> > if (COMPLETE_TYPE_P (type)
> > && integer_zerop (TYPE_SIZE (type))
> > && integer_zerop (min))
> > return build_int_cst (TREE_TYPE (min), -1);
> >
> > return error_mark_node;
> > }
> >
> > return (integer_zerop (min)
> > ? max
> > : fold_build2 (MINUS_EXPR, TREE_TYPE (max), max, min));
> > }
> >
> > With some debugging code, I've seen that in the fixed-length case, this
> > reaches the last return (integer_zerop() is true, so it returns max),
> > which is exactly the same as with any normal fixed-length array.
> >
> > In the variable-length case (i.e., [*][3]), it returns build_int_cst().
> >
> > So, it seems my problem is that 'max' does not represent an integer
> > constant, even though we know it is. Can we coerce it to an integer
> > constant somehow? Or maybe it's some of the in_lengthof that's messing
> > with me?
> >
>
> I would suspect the logic related to the C_MAYBE_CONST_EXPR.
> In your original patch this still used C_TYPE_VARIABLE_SIZE,
> which is not what we want for lengthof.
Ahhh, I blindly pasted that from sizeof, IIRC. I'll check.
Thanks a lot!
> > > It is possible that you can not properly distinguish between
> > >
> > > int a[0][n];
> > > int a[*][n];
> > >
> > > those two cases. The logic will treat the first as the second.
> >
> > Those can be distinguished. [0] triggers the zero test, while [*]
> > triggers the second var test.
>
> Are you sure? Both types should have C_TYPE_VARIABLE_SIZE set to 1.
You were right. They're the same. I was thinking of [0] vs [*], but
[0][n] is bad. It gets treated as a VLA.
I won't worry too much about it, since GCC doesn't properly support
0-length arrays. We'll have to worry about it if we start discussing
full support for 0-length arrays.
> > > I think this is ok for now. All this array stuff should be
> > > implified and refactored anyway, but this is for another time.
> > >
> > >
> > > I am also not sure you even need to use array_type_nelts in C
> > > because there is never a non-zero minimum size.
> >
> > How should I get the number of elements without array_type_nelts()? Is
> > there any other existing way to get it? It just had a good name that
> > matched my grep, but maybe I'm missing something easier.
>
> Maybe it is ok, but there is also code which just adds one
> to TYPE_MAX_VALUE.
Hmmm. I'll check.
>
> Martin
Cheers,
Alex
--
<https://www.alejandro-colomar.es/>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [RFC v3 3/3] c: Add __lengthof__() operator
2024-08-05 10:33 ` Martin Uecker
@ 2024-08-05 20:10 ` Qing Zhao
2024-08-05 20:41 ` Martin Uecker
0 siblings, 1 reply; 248+ messages in thread
From: Qing Zhao @ 2024-08-05 20:10 UTC (permalink / raw)
To: Martin Uecker, Jakub Jelinek
Cc: Alejandro Colomar, Joseph Myers, GCC Patches,
Xavier Del Campo Romero, Gabriel Ravier, Kees Cook
On Aug 5, 2024, at 06:33, Martin Uecker <uecker@tugraz.at> wrote:
>
> Am Montag, dem 05.08.2024 um 11:50 +0200 schrieb Jakub Jelinek:
>> On Mon, Aug 05, 2024 at 11:45:56AM +0200, Alejandro Colomar wrote:
>>> [CC += Kees, Qing]
>>>
>>> Hi Joseph,
>>>
>>> On Sun, Aug 04, 2024 at 08:34:24PM GMT, Alejandro Colomar wrote:
>>>> On Sun, Aug 04, 2024 at 08:02:25PM GMT, Martin Uecker wrote:
>>>> D'oh! I screwed it. I wanted to have written this:
>>>>
>>>> $ cat star.c
>>>> void foo(char (*a)[3][*], int (*x)[__lengthof__(*a)]);
>>>
>>> I think this answers your question of if we want __lengthof__ to
>>> evaluate its operand if the top-level array is non-VLA but an inner
>>> array is VLA.
>>>
>>> We clearly want it to not evaluate, because we want this __lengthof__
>>> to be a constant expression, ...
>>
>> But if you don't evaluate the argument, you can't handle counted_by.
>> Because for counted_by you need the expression (the object on which it is
>> used).
>
> You would not evaluate only when the size is an integer constant
> expression, which would not apply to counted_by.
I still don’t feel very comfortable on the idea of applying “__lengthof__()” operator on flexible array members with “counted_by” attributes. My major concerns are:
1. I thought that the new operator “__lengthof__(expr)" might need to stick to the TYPE of the expr just as the operator sizeof (expr). Sizeof will just error when the TYPE of the expr does not include the size information (for Incomplete types including flexible array members), I expect the same behavior for the new operator “__lenghof__(expr)”.
The “counted-by” attribute currently is not in the TYPE system, and we plan to add it into the TYPE system later through language standard (or an GCC extension). If that happens, then both the “sizeof” and the “__lengthof__” operators should be automatically evaluate the “size" or the “length” for the expr through its TYPE. (Just as the current VLA, its size and length already in the TYPE, therefore both “sizeof” and “__lengthof__” should evaluate VLA.
however, at this time, it’s not a good idea to mess up the operator “sizeof” or the new operator “__lengthof__” with the information outside of the TYPE system. (Even though the information outside of TYPE can provide the size or length info).
2. For the purpose of PR116016 (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=116016): add __builtin_set_counted_by(P->FAM, COUNT) or equivalent
The most important functionality the kernel needs from compilers is a way to SET the counted_by field. Unless the new operator “__lengthof__” returns a LVALUE that can be assigned to, it cannot meet the requirement from kernel.
However, from my understanding of the new “__lengthof__”, it will be similar as “sizeof”, will not be a Lvalue.
Therefore, for PR116016, we still need a new builtin, specific for the counted_by attribute.
Just my 2 cents.
Qing
> Martin
>
>
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [RFC v3 3/3] c: Add __lengthof__() operator
2024-08-05 20:10 ` Qing Zhao
@ 2024-08-05 20:41 ` Martin Uecker
2024-08-05 20:59 ` Alejandro Colomar
0 siblings, 1 reply; 248+ messages in thread
From: Martin Uecker @ 2024-08-05 20:41 UTC (permalink / raw)
To: Qing Zhao, Jakub Jelinek
Cc: Alejandro Colomar, Joseph Myers, GCC Patches,
Xavier Del Campo Romero, Gabriel Ravier, Kees Cook
Am Montag, dem 05.08.2024 um 20:10 +0000 schrieb Qing Zhao:
> On Aug 5, 2024, at 06:33, Martin Uecker <uecker@tugraz.at> wrote:
> >
> > Am Montag, dem 05.08.2024 um 11:50 +0200 schrieb Jakub Jelinek:
> > > On Mon, Aug 05, 2024 at 11:45:56AM +0200, Alejandro Colomar wrote:
> > > > [CC += Kees, Qing]
> > > >
> > > > Hi Joseph,
> > > >
> > > > On Sun, Aug 04, 2024 at 08:34:24PM GMT, Alejandro Colomar wrote:
> > > > > On Sun, Aug 04, 2024 at 08:02:25PM GMT, Martin Uecker wrote:
> > > > > D'oh! I screwed it. I wanted to have written this:
> > > > >
> > > > > $ cat star.c
> > > > > void foo(char (*a)[3][*], int (*x)[__lengthof__(*a)]);
> > > >
> > > > I think this answers your question of if we want __lengthof__ to
> > > > evaluate its operand if the top-level array is non-VLA but an inner
> > > > array is VLA.
> > > >
> > > > We clearly want it to not evaluate, because we want this __lengthof__
> > > > to be a constant expression, ...
> > >
> > > But if you don't evaluate the argument, you can't handle counted_by.
> > > Because for counted_by you need the expression (the object on which it is
> > > used).
> >
> > You would not evaluate only when the size is an integer constant
> > expression, which would not apply to counted_by.
>
> I still don’t feel very comfortable on the idea of applying “__lengthof__()” operator on flexible array members with “counted_by” attributes. My major concerns are:
>
> 1. I thought that the new operator “__lengthof__(expr)" might need to stick to the TYPE of the expr just as the operator sizeof (expr). Sizeof will just error when the TYPE of the expr does not include the size information (for Incomplete types including flexible array members), I expect the same behavior for the new operator “__lenghof__(expr)”.
>
> The “counted-by” attribute currently is not in the TYPE system, and we plan to add it into the TYPE system later through language standard (or an GCC extension). If that happens, then both the “sizeof” and the “__lengthof__” operators should be automatically evaluate the “size" or the “length” for the expr through its TYPE. (Just as the current VLA, its size and length already in the TYPE, therefore both “sizeof” and “__lengthof__” should evaluate VLA.
>
> however, at this time, it’s not a good idea to mess up the operator “sizeof” or the new operator “__lengthof__” with the information outside of the TYPE system. (Even though the information outside of TYPE can provide the size or length info).
I agree with this. I would also much prefer to see a proper language extension,
we should not really be any harder to implement than "counted_by" itself.
Martin
>
> 2. For the purpose of PR116016 (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=116016): add __builtin_set_counted_by(P->FAM, COUNT) or equivalent
>
> The most important functionality the kernel needs from compilers is a way to SET the counted_by field. Unless the new operator “__lengthof__” returns a LVALUE that can be assigned to, it cannot meet the requirement from kernel.
>
> However, from my understanding of the new “__lengthof__”, it will be similar as “sizeof”, will not be a Lvalue.
>
> Therefore, for PR116016, we still need a new builtin, specific for the counted_by attribute.
> Just my 2 cents.
>
> Qing
>
Martin
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [RFC v3 3/3] c: Add __lengthof__() operator
2024-08-05 20:41 ` Martin Uecker
@ 2024-08-05 20:59 ` Alejandro Colomar
2024-08-06 15:23 ` Qing Zhao
0 siblings, 1 reply; 248+ messages in thread
From: Alejandro Colomar @ 2024-08-05 20:59 UTC (permalink / raw)
To: Martin Uecker
Cc: Qing Zhao, Jakub Jelinek, Joseph Myers, GCC Patches,
Xavier Del Campo Romero, Gabriel Ravier, Kees Cook
[-- Attachment #1: Type: text/plain, Size: 4357 bytes --]
Hi Qing,
On Mon, Aug 05, 2024 at 10:41:43PM GMT, Martin Uecker wrote:
> Am Montag, dem 05.08.2024 um 20:10 +0000 schrieb Qing Zhao:
> > On Aug 5, 2024, at 06:33, Martin Uecker <uecker@tugraz.at> wrote:
> > >
> > > Am Montag, dem 05.08.2024 um 11:50 +0200 schrieb Jakub Jelinek:
> > > > On Mon, Aug 05, 2024 at 11:45:56AM +0200, Alejandro Colomar wrote:
> > > > > [CC += Kees, Qing]
> > > > >
> > > > > Hi Joseph,
> > > > >
> > > > > On Sun, Aug 04, 2024 at 08:34:24PM GMT, Alejandro Colomar wrote:
> > > > > > On Sun, Aug 04, 2024 at 08:02:25PM GMT, Martin Uecker wrote:
> > > > > > D'oh! I screwed it. I wanted to have written this:
> > > > > >
> > > > > > $ cat star.c
> > > > > > void foo(char (*a)[3][*], int (*x)[__lengthof__(*a)]);
> > > > >
> > > > > I think this answers your question of if we want __lengthof__ to
> > > > > evaluate its operand if the top-level array is non-VLA but an inner
> > > > > array is VLA.
> > > > >
> > > > > We clearly want it to not evaluate, because we want this __lengthof__
> > > > > to be a constant expression, ...
> > > >
> > > > But if you don't evaluate the argument, you can't handle counted_by.
> > > > Because for counted_by you need the expression (the object on which it is
> > > > used).
> > >
> > > You would not evaluate only when the size is an integer constant
> > > expression, which would not apply to counted_by.
> >
> > I still don’t feel very comfortable on the idea of applying
> > “__lengthof__()” operator on flexible array members with
> > “counted_by” attributes. My major concerns are:
> >
> > 1. I thought that the new operator “__lengthof__(expr)" might need
> > to stick to the TYPE of the expr just as the operator
> > sizeof (expr). Sizeof will just error when the TYPE of the expr
> > does not include the size information (for Incomplete types
> > including flexible array members), I expect the same behavior for
> > the new operator “__lenghof__(expr)”.
Let's be cautious, and start by having an error on FAMs in the first
implementation. We can discuss support for attributes in a later
iteration. So, I agree.
> >
> > The “counted-by” attribute currently is not in the TYPE system, and
> > we plan to add it into the TYPE system later through language
> > standard (or an GCC extension). If that happens, then both the
> > “sizeof” and the “__lengthof__” operators should be automatically
> > evaluate the “size" or the “length” for the expr through its TYPE.
> > (Just as the current VLA, its size and length already in the TYPE,
> > therefore both “sizeof” and “__lengthof__” should evaluate VLA.
I'm curious; how do you plan to make counted_by as part of the type
system? I've read the paper for using a .identifier length designator
(n3188; <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3188.htm>),
but that's a constant, and doesn't use an attribute.
> >
> > however, at this time, it’s not a good idea to mess up the operator
> > “sizeof” or the new operator “__lengthof__” with the information
> > outside of the TYPE system. (Even though the information outside of
> > TYPE can provide the size or length info).
Okay.
> I agree with this. I would also much prefer to see a proper language extension,
> we should not really be any harder to implement than "counted_by" itself.
>
> Martin
>
> >
> > 2. For the purpose of PR116016
> > (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=116016): add
> > __builtin_set_counted_by(P->FAM, COUNT) or equivalent
> >
> > The most important functionality the kernel needs from compilers is
> > a way to SET the counted_by field. Unless the new operator
> > “__lengthof__” returns a LVALUE that can be assigned to,
No; it won't be an lvalue; and the approach with an lvalue gives you a
way to both read and write in a single feature, so it's quite nice. ;)
> > it cannot meet the requirement from kernel.
> >
> > However, from my understanding of the new “__lengthof__”, it will be
> > similar as “sizeof”, will not be a Lvalue.
Yep.
> >
> > Therefore, for PR116016, we still need a new builtin, specific for
> > the counted_by attribute.
Yep.
Have a lovely night!
Alex
--
<https://www.alejandro-colomar.es/>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 248+ messages in thread
* [RFC v4 0/4] c: Add __lengthof__ operator
2024-07-28 14:15 ` [RFC v1 0/2] c: Add _Lengthof operator Alejandro Colomar
` (5 preceding siblings ...)
2024-08-03 23:17 ` [RFC v3 0/3] c: Add __lengthof__ operator Alejandro Colomar
@ 2024-08-06 12:22 ` Alejandro Colomar
2024-08-06 12:22 ` [RFC v4 1/4] gcc/: Rename array_type_nelts() => array_type_nelts_minus_one() Alejandro Colomar
` (7 more replies)
2024-08-06 23:11 ` [PATCH v5 0/3] " Alejandro Colomar
` (15 subsequent siblings)
22 siblings, 8 replies; 248+ messages in thread
From: Alejandro Colomar @ 2024-08-06 12:22 UTC (permalink / raw)
To: gcc-patches, Martin Uecker
Cc: Alejandro Colomar, Xavier Del Campo Romero, Gabriel Ravier,
Joseph Myers, Jakub Jelinek, Kees Cook, Qing Zhao, Jens Gustedt
[-- Attachment #1: Type: text/plain, Size: 24897 bytes --]
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
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 <alx@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.dcr@tutanota.com>
+ Link: <https://inbox.sourceware.org/gcc/M8S4oQy--3-2@tutanota.com/T/>
+ Suggested-by: Xavier Del Campo Romero <xavi.dcr@tutanota.com>
+ Co-developed-by: Martin Uecker <uecker@tugraz.at>
Cc: Gabriel Ravier <gabravier@gmail.com>
- Cc: Martin Uecker <uecker@tugraz.at>
Cc: Joseph Myers <josmyers@redhat.com>
Cc: Jakub Jelinek <jakub@redhat.com>
+ Cc: Kees Cook <keescook@chromium.org>
+ Cc: Qing Zhao <qing.zhao@oracle.com>
+ Cc: Jens Gustedt <jens.gustedt@inria.fr>
Signed-off-by: Alejandro Colomar <alx@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
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 248+ messages in thread
* [RFC v4 1/4] gcc/: Rename array_type_nelts() => array_type_nelts_minus_one()
2024-08-06 12:22 ` [RFC v4 0/4] c: Add __lengthof__ operator Alejandro Colomar
@ 2024-08-06 12:22 ` Alejandro Colomar
2024-08-06 12:22 ` [RFC v4 2/4] Merge definitions of array_type_nelts_top() Alejandro Colomar
` (6 subsequent siblings)
7 siblings, 0 replies; 248+ messages in thread
From: Alejandro Colomar @ 2024-08-06 12:22 UTC (permalink / raw)
To: gcc-patches
Cc: Alejandro Colomar, Xavier Del Campo Romero, Martin Uecker,
Gabriel Ravier, Joseph Myers, Jakub Jelinek, Kees Cook,
Qing Zhao, Jens Gustedt, Richard Biener
[-- Attachment #1: Type: text/plain, Size: 12983 bytes --]
The old name was misleading.
While at it, also rename some temporary variables that are used with
this function, for consistency.
Link: https://inbox.sourceware.org/gcc-patches/9fffd80-dca-2c7e-14b-6c9b509a7215@redhat.com/T/#m2f661c67c8f7b2c405c8c7fc3152dd85dc729120
Cc: Gabriel Ravier <gabravier@gmail.com>
Cc: Martin Uecker <uecker@tugraz.at>
Cc: Joseph Myers <josmyers@redhat.com>
Cc: Xavier Del Campo Romero <xavi.dcr@tutanota.com>
Cc: Jakub Jelinek <jakub@redhat.com>
gcc/ChangeLog:
* tree.cc (array_type_nelts): Rename function ...
(array_type_nelts_minus_one): ... to this name. The old name
was misleading.
* tree.h (array_type_nelts): Rename function ...
(array_type_nelts_minus_one): ... to this name. The old name
was misleading.
* expr.cc (count_type_elements):
Rename array_type_nelts() => array_type_nelts_minus_one()
* config/aarch64/aarch64.cc
(pure_scalable_type_info::analyze_array): Likewise.
* config/i386/i386.cc (ix86_canonical_va_list_type): Likewise.
gcc/c/ChangeLog:
* c-decl.cc (one_element_array_type_p, get_parm_array_spec):
Rename array_type_nelts() => array_type_nelts_minus_one()
* c-fold.cc (c_fold_array_ref): Likewise.
gcc/cp/ChangeLog:
* decl.cc (reshape_init_array):
Rename array_type_nelts() => array_type_nelts_minus_one()
* init.cc (build_zero_init_1): Likewise.
(build_value_init_noctor): Likewise.
(build_vec_init): Likewise.
(build_delete): Likewise.
* lambda.cc (add_capture): Likewise.
* tree.cc (array_type_nelts_top): Likewise.
gcc/fortran/ChangeLog:
* trans-array.cc (structure_alloc_comps):
Rename array_type_nelts() => array_type_nelts_minus_one()
* trans-openmp.cc (gfc_walk_alloc_comps): Likewise.
(gfc_omp_clause_linear_ctor): Likewise.
gcc/rust/ChangeLog:
* backend/rust-tree.cc (array_type_nelts_top):
Rename array_type_nelts() => array_type_nelts_minus_one()
Suggested-by: Richard Biener <richard.guenther@gmail.com>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
---
gcc/c/c-decl.cc | 10 +++++-----
gcc/c/c-fold.cc | 7 ++++---
gcc/config/aarch64/aarch64.cc | 2 +-
gcc/config/i386/i386.cc | 2 +-
gcc/cp/decl.cc | 2 +-
gcc/cp/init.cc | 8 ++++----
gcc/cp/lambda.cc | 3 ++-
gcc/cp/tree.cc | 2 +-
gcc/expr.cc | 8 ++++----
gcc/fortran/trans-array.cc | 2 +-
gcc/fortran/trans-openmp.cc | 4 ++--
gcc/rust/backend/rust-tree.cc | 2 +-
gcc/tree.cc | 4 ++--
gcc/tree.h | 2 +-
14 files changed, 30 insertions(+), 28 deletions(-)
diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 97f1d346835..4dced430d1f 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -5309,7 +5309,7 @@ one_element_array_type_p (const_tree type)
{
if (TREE_CODE (type) != ARRAY_TYPE)
return false;
- return integer_zerop (array_type_nelts (type));
+ return integer_zerop (array_type_nelts_minus_one (type));
}
/* Determine whether TYPE is a zero-length array type "[0]". */
@@ -6257,15 +6257,15 @@ get_parm_array_spec (const struct c_parm *parm, tree attrs)
for (tree type = parm->specs->type; TREE_CODE (type) == ARRAY_TYPE;
type = TREE_TYPE (type))
{
- tree nelts = array_type_nelts (type);
- if (error_operand_p (nelts))
+ tree nelts_minus_one = array_type_nelts_minus_one (type);
+ if (error_operand_p (nelts_minus_one))
return attrs;
- if (TREE_CODE (nelts) != INTEGER_CST)
+ if (TREE_CODE (nelts_minus_one) != INTEGER_CST)
{
/* Each variable VLA bound is represented by the dollar
sign. */
spec += "$";
- tpbnds = tree_cons (NULL_TREE, nelts, tpbnds);
+ tpbnds = tree_cons (NULL_TREE, nelts_minus_one, tpbnds);
}
}
tpbnds = nreverse (tpbnds);
diff --git a/gcc/c/c-fold.cc b/gcc/c/c-fold.cc
index 57b67c74bd8..9ea174f79c4 100644
--- a/gcc/c/c-fold.cc
+++ b/gcc/c/c-fold.cc
@@ -73,11 +73,12 @@ c_fold_array_ref (tree type, tree ary, tree index)
unsigned elem_nchars = (TYPE_PRECISION (elem_type)
/ TYPE_PRECISION (char_type_node));
unsigned len = (unsigned) TREE_STRING_LENGTH (ary) / elem_nchars;
- tree nelts = array_type_nelts (TREE_TYPE (ary));
+ tree nelts_minus_one = array_type_nelts_minus_one (TREE_TYPE (ary));
bool dummy1 = true, dummy2 = true;
- nelts = c_fully_fold_internal (nelts, true, &dummy1, &dummy2, false, false);
+ nelts_minus_one = c_fully_fold_internal (nelts_minus_one, true, &dummy1,
+ &dummy2, false, false);
unsigned HOST_WIDE_INT i = tree_to_uhwi (index);
- if (!tree_int_cst_le (index, nelts)
+ if (!tree_int_cst_le (index, nelts_minus_one)
|| i >= len
|| i + elem_nchars > len)
return NULL_TREE;
diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
index 0d41a193ec1..eaef2a0e985 100644
--- a/gcc/config/aarch64/aarch64.cc
+++ b/gcc/config/aarch64/aarch64.cc
@@ -1082,7 +1082,7 @@ pure_scalable_type_info::analyze_array (const_tree type)
/* An array of unknown, flexible or variable length will be passed and
returned by reference whatever we do. */
- tree nelts_minus_one = array_type_nelts (type);
+ tree nelts_minus_one = array_type_nelts_minus_one (type);
if (!tree_fits_uhwi_p (nelts_minus_one))
return DOESNT_MATTER;
diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc
index 9c2ebe74fc9..298d8c9131a 100644
--- a/gcc/config/i386/i386.cc
+++ b/gcc/config/i386/i386.cc
@@ -24519,7 +24519,7 @@ ix86_canonical_va_list_type (tree type)
return ms_va_list_type_node;
if ((TREE_CODE (type) == ARRAY_TYPE
- && integer_zerop (array_type_nelts (type)))
+ && integer_zerop (array_type_nelts_minus_one (type)))
|| POINTER_TYPE_P (type))
{
tree elem_type = TREE_TYPE (type);
diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index e7bb4fa3089..fc3e28c4dec 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -6936,7 +6936,7 @@ reshape_init_array (tree type, reshape_iter *d, tree first_initializer_p,
gcc_assert (TREE_CODE (type) == ARRAY_TYPE);
if (TYPE_DOMAIN (type))
- max_index = array_type_nelts (type);
+ max_index = array_type_nelts_minus_one (type);
return reshape_init_array_1 (TREE_TYPE (type), max_index, d,
first_initializer_p, complain);
diff --git a/gcc/cp/init.cc b/gcc/cp/init.cc
index e9561c146d7..4558151b4c2 100644
--- a/gcc/cp/init.cc
+++ b/gcc/cp/init.cc
@@ -260,7 +260,7 @@ build_zero_init_1 (tree type, tree nelts, bool static_storage_p,
else if (TYPE_DOMAIN (type) == NULL_TREE)
return NULL_TREE;
else
- max_index = array_type_nelts (type);
+ max_index = array_type_nelts_minus_one (type);
/* If we have an error_mark here, we should just return error mark
as we don't know the size of the array yet. */
@@ -471,7 +471,7 @@ build_value_init_noctor (tree type, tsubst_flags_t complain)
vec<constructor_elt, va_gc> *v = NULL;
/* Iterate over the array elements, building initializations. */
- tree max_index = array_type_nelts (type);
+ tree max_index = array_type_nelts_minus_one (type);
/* If we have an error_mark here, we should just return error mark
as we don't know the size of the array yet. */
@@ -4516,7 +4516,7 @@ build_vec_init (tree base, tree maxindex, tree init,
: location_of (base));
if (TREE_CODE (atype) == ARRAY_TYPE && TYPE_DOMAIN (atype))
- maxindex = array_type_nelts (atype);
+ maxindex = array_type_nelts_minus_one (atype);
if (maxindex == NULL_TREE || maxindex == error_mark_node)
return error_mark_node;
@@ -5172,7 +5172,7 @@ build_delete (location_t loc, tree otype, tree addr,
error_at (loc, "unknown array size in delete");
return error_mark_node;
}
- return build_vec_delete (loc, addr, array_type_nelts (type),
+ return build_vec_delete (loc, addr, array_type_nelts_minus_one (type),
auto_delete, use_global_delete, complain);
}
diff --git a/gcc/cp/lambda.cc b/gcc/cp/lambda.cc
index 0770417810e..065113bc122 100644
--- a/gcc/cp/lambda.cc
+++ b/gcc/cp/lambda.cc
@@ -556,7 +556,8 @@ add_capture (tree lambda, tree id, tree orig_init, bool by_reference_p,
integer_zero_node, tf_warning_or_error);
initializer = build_constructor_va (init_list_type_node, 2,
NULL_TREE, build_address (elt),
- NULL_TREE, array_type_nelts (type));
+ NULL_TREE,
+ array_type_nelts_minus_one (type));
type = vla_capture_type (type);
}
else if (!dependent_type_p (type)
diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
index dfd4a3a948b..3baeb8fa252 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -3080,7 +3080,7 @@ array_type_nelts_top (tree type)
{
return fold_build2_loc (input_location,
PLUS_EXPR, sizetype,
- array_type_nelts (type),
+ array_type_nelts_minus_one (type),
size_one_node);
}
diff --git a/gcc/expr.cc b/gcc/expr.cc
index ffbac513692..cba8b365856 100644
--- a/gcc/expr.cc
+++ b/gcc/expr.cc
@@ -6970,14 +6970,14 @@ count_type_elements (const_tree type, bool for_ctor_p)
{
case ARRAY_TYPE:
{
- tree nelts;
+ tree nelts_minus_one;
- nelts = array_type_nelts (type);
- if (nelts && tree_fits_uhwi_p (nelts))
+ nelts_minus_one = array_type_nelts_minus_one (type);
+ if (nelts_minus_one && tree_fits_uhwi_p (nelts_minus_one))
{
unsigned HOST_WIDE_INT n;
- n = tree_to_uhwi (nelts) + 1;
+ n = tree_to_uhwi (nelts_minus_one) + 1;
if (n == 0 || for_ctor_p)
return n;
else
diff --git a/gcc/fortran/trans-array.cc b/gcc/fortran/trans-array.cc
index 140d933e45d..b7927bcdf01 100644
--- a/gcc/fortran/trans-array.cc
+++ b/gcc/fortran/trans-array.cc
@@ -9572,7 +9572,7 @@ structure_alloc_comps (gfc_symbol * der_type, tree decl, tree dest,
else
{
/* Otherwise use the TYPE_DOMAIN information. */
- tmp = array_type_nelts (decl_type);
+ tmp = array_type_nelts_minus_one (decl_type);
tmp = fold_convert (gfc_array_index_type, tmp);
}
diff --git a/gcc/fortran/trans-openmp.cc b/gcc/fortran/trans-openmp.cc
index df1bf144e23..14cd2f9fad7 100644
--- a/gcc/fortran/trans-openmp.cc
+++ b/gcc/fortran/trans-openmp.cc
@@ -582,7 +582,7 @@ gfc_walk_alloc_comps (tree decl, tree dest, tree var,
tem = size_binop (MINUS_EXPR, tem, size_one_node);
}
else
- tem = array_type_nelts (type);
+ tem = array_type_nelts_minus_one (type);
tem = fold_convert (gfc_array_index_type, tem);
}
@@ -1309,7 +1309,7 @@ gfc_omp_clause_linear_ctor (tree clause, tree dest, tree src, tree add)
nelems = size_binop (MINUS_EXPR, nelems, size_one_node);
}
else
- nelems = array_type_nelts (type);
+ nelems = array_type_nelts_minus_one (type);
nelems = fold_convert (gfc_array_index_type, nelems);
gfc_omp_linear_clause_add_loop (&block, dest, src, add, nelems);
diff --git a/gcc/rust/backend/rust-tree.cc b/gcc/rust/backend/rust-tree.cc
index 2a5ffcbf895..a2c12204667 100644
--- a/gcc/rust/backend/rust-tree.cc
+++ b/gcc/rust/backend/rust-tree.cc
@@ -869,7 +869,7 @@ tree
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
diff --git a/gcc/tree.cc b/gcc/tree.cc
index 2d2d5b6db6e..dcaccc4c362 100644
--- a/gcc/tree.cc
+++ b/gcc/tree.cc
@@ -3698,7 +3698,7 @@ int_byte_position (const_tree field)
ARRAY_TYPE) minus one. This counts only elements of the top array. */
tree
-array_type_nelts (const_tree type)
+array_type_nelts_minus_one (const_tree type)
{
tree index_type, min, max;
@@ -14797,7 +14797,7 @@ is_empty_type (const_tree type)
return true;
}
else if (TREE_CODE (type) == ARRAY_TYPE)
- return (integer_minus_onep (array_type_nelts (type))
+ return (integer_minus_onep (array_type_nelts_minus_one (type))
|| TYPE_DOMAIN (type) == NULL_TREE
|| is_empty_type (TREE_TYPE (type)));
return false;
diff --git a/gcc/tree.h b/gcc/tree.h
index 28e8e71b036..fdddbcf408e 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -4921,7 +4921,7 @@ extern tree build_method_type_directly (tree, tree, tree);
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 value_member (tree, tree);
extern tree purpose_member (const_tree, tree);
--
2.45.2
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 248+ messages in thread
* [RFC v4 2/4] Merge definitions of array_type_nelts_top()
2024-08-06 12:22 ` [RFC v4 0/4] c: Add __lengthof__ operator Alejandro Colomar
2024-08-06 12:22 ` [RFC v4 1/4] gcc/: Rename array_type_nelts() => array_type_nelts_minus_one() Alejandro Colomar
@ 2024-08-06 12:22 ` Alejandro Colomar
2024-08-06 12:22 ` [RFC v4 3/4] c: Add __lengthof__() operator (n2529) Alejandro Colomar
` (5 subsequent siblings)
7 siblings, 0 replies; 248+ messages in thread
From: Alejandro Colomar @ 2024-08-06 12:22 UTC (permalink / raw)
To: gcc-patches
Cc: Alejandro Colomar, Xavier Del Campo Romero, Martin Uecker,
Gabriel Ravier, Joseph Myers, Jakub Jelinek, Kees Cook,
Qing Zhao, Jens Gustedt
[-- Attachment #1: Type: text/plain, Size: 4433 bytes --]
There were two identical definitions, and none of them are available
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__().
Signed-off-by: Alejandro Colomar <alx@kernel.org>
---
gcc/cp/cp-tree.h | 1 -
gcc/cp/tree.cc | 13 -------------
gcc/rust/backend/rust-tree.cc | 13 -------------
gcc/rust/backend/rust-tree.h | 2 --
gcc/tree.cc | 13 +++++++++++++
gcc/tree.h | 1 +
6 files changed, 14 insertions(+), 29 deletions(-)
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index c1a371bc721..e6c1c63f872 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -8099,7 +8099,6 @@ extern tree build_exception_variant (tree, tree);
extern void fixup_deferred_exception_variants (tree, tree);
extern tree bind_template_template_parm (tree, tree);
extern tree array_type_nelts_total (tree);
-extern tree array_type_nelts_top (tree);
extern bool array_of_unknown_bound_p (const_tree);
extern tree break_out_target_exprs (tree, bool = false);
extern tree build_ctor_subob_ref (tree, tree, tree);
diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
index 3baeb8fa252..1f3ecff1a21 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -3071,19 +3071,6 @@ cxx_print_statistics (void)
depth_reached);
}
-/* Return, as an INTEGER_CST node, the number of elements for TYPE
- (which is an ARRAY_TYPE). This counts only elements of the top
- array. */
-
-tree
-array_type_nelts_top (tree type)
-{
- return fold_build2_loc (input_location,
- PLUS_EXPR, sizetype,
- array_type_nelts_minus_one (type),
- size_one_node);
-}
-
/* Return, as an INTEGER_CST node, the number of elements for TYPE
(which is an ARRAY_TYPE). This one is a recursive count of all
ARRAY_TYPEs that are clumped together. */
diff --git a/gcc/rust/backend/rust-tree.cc b/gcc/rust/backend/rust-tree.cc
index a2c12204667..dd8eda84f9b 100644
--- a/gcc/rust/backend/rust-tree.cc
+++ b/gcc/rust/backend/rust-tree.cc
@@ -859,19 +859,6 @@ is_empty_class (tree type)
return CLASSTYPE_EMPTY_P (type);
}
-// forked from gcc/cp/tree.cc array_type_nelts_top
-
-/* Return, as an INTEGER_CST node, the number of elements for TYPE
- (which is an ARRAY_TYPE). This counts only elements of the top
- array. */
-
-tree
-array_type_nelts_top (tree type)
-{
- return fold_build2_loc (input_location, PLUS_EXPR, sizetype,
- array_type_nelts_minus_one (type), size_one_node);
-}
-
// forked from gcc/cp/tree.cc builtin_valid_in_constant_expr_p
/* Test whether DECL is a builtin that may appear in a
diff --git a/gcc/rust/backend/rust-tree.h b/gcc/rust/backend/rust-tree.h
index 26c8b653ac6..e597c3ab81d 100644
--- a/gcc/rust/backend/rust-tree.h
+++ b/gcc/rust/backend/rust-tree.h
@@ -2993,8 +2993,6 @@ extern location_t rs_expr_location (const_tree);
extern int
is_empty_class (tree type);
-extern tree array_type_nelts_top (tree);
-
extern bool
is_really_empty_class (tree, bool);
diff --git a/gcc/tree.cc b/gcc/tree.cc
index dcaccc4c362..cbbc7627ad6 100644
--- a/gcc/tree.cc
+++ b/gcc/tree.cc
@@ -3729,6 +3729,19 @@ array_type_nelts_minus_one (const_tree type)
? max
: fold_build2 (MINUS_EXPR, TREE_TYPE (max), max, min));
}
+
+/* Return, as an INTEGER_CST node, the number of elements for TYPE
+ (which is an ARRAY_TYPE). This counts only elements of the top
+ array. */
+
+tree
+array_type_nelts_top (tree type)
+{
+ return fold_build2_loc (input_location,
+ PLUS_EXPR, sizetype,
+ array_type_nelts_minus_one (type),
+ size_one_node);
+}
\f
/* If arg is static -- a reference to an object in static storage -- then
return the object. This is not the same as the C meaning of `static'.
diff --git a/gcc/tree.h b/gcc/tree.h
index fdddbcf408e..a6c46440b1a 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -4922,6 +4922,7 @@ 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_minus_one (const_tree);
+extern tree array_type_nelts_top (tree);
extern tree value_member (tree, tree);
extern tree purpose_member (const_tree, tree);
--
2.45.2
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 248+ messages in thread
* [RFC v4 3/4] c: Add __lengthof__() operator (n2529)
2024-08-06 12:22 ` [RFC v4 0/4] c: Add __lengthof__ operator Alejandro Colomar
2024-08-06 12:22 ` [RFC v4 1/4] gcc/: Rename array_type_nelts() => array_type_nelts_minus_one() Alejandro Colomar
2024-08-06 12:22 ` [RFC v4 2/4] Merge definitions of array_type_nelts_top() Alejandro Colomar
@ 2024-08-06 12:22 ` Alejandro Colomar
2024-08-06 20:15 ` Qing Zhao
2024-08-06 12:22 ` [RFC v4 4/4] testsuite: Add tests for __lengthof__ Alejandro Colomar
` (4 subsequent siblings)
7 siblings, 1 reply; 248+ messages in thread
From: Alejandro Colomar @ 2024-08-06 12:22 UTC (permalink / raw)
To: gcc-patches
Cc: Alejandro Colomar, Xavier Del Campo Romero, Martin Uecker,
Gabriel Ravier, Joseph Myers, Jakub Jelinek, Kees Cook,
Qing Zhao, Jens Gustedt
[-- Attachment #1: Type: text/plain, Size: 20852 bytes --]
This operator is similar to sizeof() but can only be applied to an
array, and returns its length (number of elements).
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.
Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2529.pdf>
Link: <https://inbox.sourceware.org/gcc/M8S4oQy--3-2@tutanota.com/T/>
Suggested-by: Xavier Del Campo Romero <xavi.dcr@tutanota.com>
Co-developed-by: Martin Uecker <uecker@tugraz.at>
Cc: Gabriel Ravier <gabravier@gmail.com>
Cc: Joseph Myers <josmyers@redhat.com>
Cc: Jakub Jelinek <jakub@redhat.com>
Cc: Kees Cook <keescook@chromium.org>
Cc: Qing Zhao <qing.zhao@oracle.com>
Cc: Jens Gustedt <jens.gustedt@inria.fr>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
---
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 | 20 +++++--
gcc/c/c-parser.cc | 61 +++++++++++++++-----
gcc/c/c-tree.h | 4 ++
gcc/c/c-typeck.cc | 114 ++++++++++++++++++++++++++++++++++++--
gcc/cp/operators.def | 1 +
gcc/doc/extend.texi | 27 +++++++++
gcc/target.h | 3 +
10 files changed, 237 insertions(+), 24 deletions(-)
diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
index e7e371fd26f..9f5feb83345 100644
--- a/gcc/c-family/c-common.cc
+++ b/gcc/c-family/c-common.cc
@@ -465,6 +465,7 @@ const struct c_common_resword c_common_reswords[] =
{ "__inline", RID_INLINE, 0 },
{ "__inline__", RID_INLINE, 0 },
{ "__label__", RID_LABEL, 0 },
+ { "__lengthof__", RID_LENGTHOF, 0 },
{ "__null", RID_NULL, 0 },
{ "__real", RID_REALPART, 0 },
{ "__real__", RID_REALPART, 0 },
@@ -4070,6 +4071,31 @@ c_alignof_expr (location_t loc, tree expr)
return fold_convert_loc (loc, size_type_node, t);
}
+
+/* Implement the lengthof keyword: Return the length of an array,
+ that is, the number of elements in the array. */
+
+tree
+c_lengthof_type (location_t loc, tree type)
+{
+ 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,
+ "invalid application of %<lengthof%> to incomplete type %qT",
+ type);
+ return error_mark_node;
+ }
+
+ return array_type_nelts_top (type);
+}
\f
/* Handle C and C++ default attributes. */
diff --git a/gcc/c-family/c-common.def b/gcc/c-family/c-common.def
index 5de96e5d4a8..6d162f67104 100644
--- a/gcc/c-family/c-common.def
+++ b/gcc/c-family/c-common.def
@@ -50,6 +50,9 @@ DEFTREECODE (EXCESS_PRECISION_EXPR, "excess_precision_expr", tcc_expression, 1)
number. */
DEFTREECODE (USERDEF_LITERAL, "userdef_literal", tcc_exceptional, 3)
+/* Represents a 'lengthof' expression. */
+DEFTREECODE (LENGTHOF_EXPR, "lengthof_expr", tcc_expression, 1)
+
/* Represents a 'sizeof' expression during C++ template expansion,
or for the purpose of -Wsizeof-pointer-memaccess warning. */
DEFTREECODE (SIZEOF_EXPR, "sizeof_expr", tcc_expression, 1)
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index ccaea27c2b9..f815a4cf3bc 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -105,6 +105,7 @@ enum rid
/* C extensions */
RID_ASM, RID_TYPEOF, RID_TYPEOF_UNQUAL, RID_ALIGNOF, RID_ATTRIBUTE,
+ RID_LENGTHOF,
RID_VA_ARG,
RID_EXTENSION, RID_IMAGPART, RID_REALPART, RID_LABEL, RID_CHOOSE_EXPR,
RID_TYPES_COMPATIBLE_P, RID_BUILTIN_COMPLEX, RID_BUILTIN_SHUFFLE,
@@ -885,6 +886,7 @@ extern tree c_common_truthvalue_conversion (location_t, tree);
extern void c_apply_type_quals_to_decl (int, tree);
extern tree c_sizeof_or_alignof_type (location_t, tree, bool, bool, int);
extern tree c_alignof_expr (location_t, tree);
+extern tree c_lengthof_type (location_t, tree);
/* Print an error message for invalid operands to arith operation CODE.
NOP_EXPR is used as a special case (see truthvalue_conversion). */
extern void binary_op_error (rich_location *, enum tree_code, tree, tree);
diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 4dced430d1f..790c58b2558 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -8937,12 +8937,16 @@ start_struct (location_t loc, enum tree_code code, tree name,
within a statement expr used within sizeof, et. al. This is not
terribly serious as C++ doesn't permit statement exprs within
sizeof anyhow. */
- if (warn_cxx_compat && (in_sizeof || in_typeof || in_alignof))
+ if (warn_cxx_compat && (in_sizeof || in_typeof || in_alignof || in_lengthof))
warning_at (loc, OPT_Wc___compat,
"defining type in %qs expression is invalid in C++",
(in_sizeof
? "sizeof"
- : (in_typeof ? "typeof" : "alignof")));
+ : (in_typeof
+ ? "typeof"
+ : (in_alignof
+ ? "alignof"
+ : "lengthof"))));
if (in_underspecified_init)
error_at (loc, "%qT defined in underspecified object initializer", ref);
@@ -9897,7 +9901,7 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes,
struct_types. */
if (warn_cxx_compat
&& struct_parse_info != NULL
- && !in_sizeof && !in_typeof && !in_alignof)
+ && !in_sizeof && !in_typeof && !in_alignof && !in_lengthof)
struct_parse_info->struct_types.safe_push (t);
}
@@ -10071,12 +10075,16 @@ start_enum (location_t loc, struct c_enum_contents *the_enum, tree name,
/* FIXME: This will issue a warning for a use of a type defined
within sizeof in a statement expr. This is not terribly serious
as C++ doesn't permit statement exprs within sizeof anyhow. */
- if (warn_cxx_compat && (in_sizeof || in_typeof || in_alignof))
+ if (warn_cxx_compat && (in_sizeof || in_typeof || in_alignof || in_lengthof))
warning_at (loc, OPT_Wc___compat,
"defining type in %qs expression is invalid in C++",
(in_sizeof
? "sizeof"
- : (in_typeof ? "typeof" : "alignof")));
+ : (in_typeof
+ ? "typeof"
+ : (in_alignof
+ ? "alignof"
+ : "lengthof"))));
if (in_underspecified_init)
error_at (loc, "%qT defined in underspecified object initializer",
@@ -10270,7 +10278,7 @@ finish_enum (tree enumtype, tree values, tree attributes)
struct_types. */
if (warn_cxx_compat
&& struct_parse_info != NULL
- && !in_sizeof && !in_typeof && !in_alignof)
+ && !in_sizeof && !in_typeof && !in_alignof && !in_lengthof)
struct_parse_info->struct_types.safe_push (enumtype);
/* Check for consistency with previous definition */
diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
index 12c5ed5d92c..09bb19f9299 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -74,7 +74,17 @@ along with GCC; see the file COPYING3. If not see
#include "bitmap.h"
#include "analyzer/analyzer-language.h"
#include "toplev.h"
+\f
+#define c_parser_sizeof_expression(parser) \
+( \
+ c_parser_sizeof_or_lengthof_expression (parser, RID_SIZEOF) \
+)
+#define c_parser_lengthof_expression(parser) \
+( \
+ c_parser_sizeof_or_lengthof_expression (parser, RID_LENGTHOF) \
+)
+\f
/* We need to walk over decls with incomplete struct/union/enum types
after parsing the whole translation unit.
In finish_decl(), if the decl is static, has incomplete
@@ -1687,7 +1697,7 @@ static struct c_expr c_parser_binary_expression (c_parser *, struct c_expr *,
tree);
static struct c_expr c_parser_cast_expression (c_parser *, struct c_expr *);
static struct c_expr c_parser_unary_expression (c_parser *);
-static struct c_expr c_parser_sizeof_expression (c_parser *);
+static struct c_expr c_parser_sizeof_or_lengthof_expression (c_parser *, enum rid);
static struct c_expr c_parser_alignof_expression (c_parser *);
static struct c_expr c_parser_postfix_expression (c_parser *);
static struct c_expr c_parser_postfix_expression_after_paren_type (c_parser *,
@@ -9864,6 +9874,8 @@ c_parser_unary_expression (c_parser *parser)
case CPP_KEYWORD:
switch (c_parser_peek_token (parser)->keyword)
{
+ case RID_LENGTHOF:
+ return c_parser_lengthof_expression (parser);
case RID_SIZEOF:
return c_parser_sizeof_expression (parser);
case RID_ALIGNOF:
@@ -9903,12 +9915,13 @@ c_parser_unary_expression (c_parser *parser)
/* Parse a sizeof expression. */
static struct c_expr
-c_parser_sizeof_expression (c_parser *parser)
+c_parser_sizeof_or_lengthof_expression (c_parser *parser, enum rid rid)
{
+ const char *op_name = (rid == RID_LENGTHOF) ? "lengthof" : "sizeof";
struct c_expr expr;
struct c_expr result;
location_t expr_loc;
- gcc_assert (c_parser_next_token_is_keyword (parser, RID_SIZEOF));
+ gcc_assert (c_parser_next_token_is_keyword (parser, rid));
location_t start;
location_t finish = UNKNOWN_LOCATION;
@@ -9917,7 +9930,10 @@ c_parser_sizeof_expression (c_parser *parser)
c_parser_consume_token (parser);
c_inhibit_evaluation_warnings++;
- in_sizeof++;
+ if (rid == RID_LENGTHOF)
+ in_lengthof++;
+ else
+ in_sizeof++;
if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)
&& c_token_starts_compound_literal (c_parser_peek_2nd_token (parser)))
{
@@ -9936,7 +9952,10 @@ c_parser_sizeof_expression (c_parser *parser)
{
struct c_expr ret;
c_inhibit_evaluation_warnings--;
- in_sizeof--;
+ if (rid == RID_LENGTHOF)
+ in_lengthof--;
+ else
+ in_sizeof--;
ret.set_error ();
ret.original_code = ERROR_MARK;
ret.original_type = NULL;
@@ -9948,31 +9967,45 @@ c_parser_sizeof_expression (c_parser *parser)
type_name,
expr_loc);
finish = expr.get_finish ();
- goto sizeof_expr;
+ goto Xof_expr;
}
/* sizeof ( type-name ). */
if (scspecs)
- error_at (expr_loc, "storage class specifier in %<sizeof%>");
+ error_at (expr_loc, "storage class specifier in %qs", op_name);
if (type_name->specs->alignas_p)
error_at (type_name->specs->locations[cdw_alignas],
- "alignment specified for type name in %<sizeof%>");
+ "alignment specified for type name in %qs", op_name);
c_inhibit_evaluation_warnings--;
- in_sizeof--;
- result = c_expr_sizeof_type (expr_loc, type_name);
+ if (rid == RID_LENGTHOF)
+ {
+ in_lengthof--;
+ result = c_expr_lengthof_type (expr_loc, type_name);
+ }
+ else
+ {
+ in_sizeof--;
+ result = c_expr_sizeof_type (expr_loc, type_name);
+ }
}
else
{
expr_loc = c_parser_peek_token (parser)->location;
expr = c_parser_unary_expression (parser);
finish = expr.get_finish ();
- sizeof_expr:
+ Xof_expr:
c_inhibit_evaluation_warnings--;
- in_sizeof--;
+ if (rid == RID_LENGTHOF)
+ in_lengthof--;
+ else
+ in_sizeof--;
mark_exp_read (expr.value);
if (TREE_CODE (expr.value) == COMPONENT_REF
&& DECL_C_BIT_FIELD (TREE_OPERAND (expr.value, 1)))
- error_at (expr_loc, "%<sizeof%> applied to a bit-field");
- result = c_expr_sizeof_expr (expr_loc, expr);
+ error_at (expr_loc, "%qs applied to a bit-field", op_name);
+ if (rid == RID_LENGTHOF)
+ result = c_expr_lengthof_expr (expr_loc, expr);
+ else
+ result = c_expr_sizeof_expr (expr_loc, expr);
}
if (finish == UNKNOWN_LOCATION)
finish = start;
diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h
index 15da875a029..102fcfefea6 100644
--- a/gcc/c/c-tree.h
+++ b/gcc/c/c-tree.h
@@ -736,6 +736,7 @@ extern int c_type_dwarf_attribute (const_tree, int);
/* in c-typeck.cc */
extern int in_alignof;
extern int in_sizeof;
+extern int in_lengthof;
extern int in_typeof;
extern bool c_in_omp_for;
extern bool c_omp_array_section_p;
@@ -786,6 +787,9 @@ extern tree build_external_ref (location_t, tree, bool, tree *);
extern void pop_maybe_used (bool);
extern struct c_expr c_expr_sizeof_expr (location_t, struct c_expr);
extern struct c_expr c_expr_sizeof_type (location_t, struct c_type_name *);
+extern struct c_expr c_expr_lengthof_expr (location_t, struct c_expr);
+extern struct c_expr c_expr_lengthof_type (location_t loc,
+ struct c_type_name *);
extern struct c_expr parser_build_unary_op (location_t, enum tree_code,
struct c_expr);
extern struct c_expr parser_build_binary_op (location_t,
diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index 7e0f01ed22b..69b9f1171ae 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -71,6 +71,9 @@ int in_alignof;
/* The level of nesting inside "sizeof". */
int in_sizeof;
+/* The level of nesting inside "sizeof". */
+int in_lengthof;
+
/* The level of nesting inside "typeof". */
int in_typeof;
@@ -3255,7 +3258,7 @@ build_external_ref (location_t loc, tree id, bool fun, tree *type)
if (TREE_CODE (ref) == FUNCTION_DECL && !in_alignof)
{
- if (!in_sizeof && !in_typeof)
+ if (!in_sizeof && !in_typeof && !in_lengthof)
C_DECL_USED (ref) = 1;
else if (DECL_INITIAL (ref) == NULL_TREE
&& DECL_EXTERNAL (ref)
@@ -3311,7 +3314,7 @@ struct maybe_used_decl
{
/* The decl. */
tree decl;
- /* The level seen at (in_sizeof + in_typeof). */
+ /* The level seen at (in_sizeof + in_typeof + in_lengthof). */
int level;
/* The next one at this level or above, or NULL. */
struct maybe_used_decl *next;
@@ -3329,7 +3332,7 @@ record_maybe_used_decl (tree decl)
{
struct maybe_used_decl *t = XOBNEW (&parser_obstack, struct maybe_used_decl);
t->decl = decl;
- t->level = in_sizeof + in_typeof;
+ t->level = in_sizeof + in_typeof + in_lengthof;
t->next = maybe_used_decls;
maybe_used_decls = t;
}
@@ -3343,7 +3346,7 @@ void
pop_maybe_used (bool used)
{
struct maybe_used_decl *p = maybe_used_decls;
- int cur_level = in_sizeof + in_typeof;
+ int cur_level = in_sizeof + in_typeof + in_lengthof;
while (p && p->level > cur_level)
{
if (used)
@@ -3453,6 +3456,109 @@ 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
+c_expr_lengthof_expr (location_t loc, struct c_expr expr)
+{
+ struct c_expr ret;
+ if (expr.value == error_mark_node)
+ {
+ ret.value = error_mark_node;
+ ret.original_code = ERROR_MARK;
+ ret.original_type = NULL;
+ ret.m_decimal = 0;
+ pop_maybe_used (false);
+ }
+ else
+ {
+ bool expr_const_operands = true;
+
+ tree folded_expr = c_fully_fold (expr.value, require_constant_value,
+ &expr_const_operands);
+ ret.value = c_lengthof_type (loc, TREE_TYPE (folded_expr));
+ c_last_sizeof_arg = expr.value;
+ c_last_sizeof_loc = loc;
+ ret.original_code = LENGTHOF_EXPR;
+ ret.original_type = NULL;
+ ret.m_decimal = 0;
+ 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),
+ folded_expr, ret.value);
+ C_MAYBE_CONST_EXPR_NON_CONST (ret.value) = !expr_const_operands;
+ SET_EXPR_LOCATION (ret.value, loc);
+ }
+ pop_maybe_used (is_top_array_vla (TREE_TYPE (folded_expr)));
+ }
+ return ret;
+}
+
+/* Return the result of lengthof applied to T, a structure for the type
+ name passed to _lengthof (rather than the type itself). LOC is the
+ location of the original expression. */
+
+struct c_expr
+c_expr_lengthof_type (location_t loc, struct c_type_name *t)
+{
+ tree type;
+ struct c_expr ret;
+ tree type_expr = NULL_TREE;
+ bool type_expr_const = true;
+ type = groktypename (t, &type_expr, &type_expr_const);
+ ret.value = c_lengthof_type (loc, type);
+ c_last_sizeof_arg = type;
+ c_last_sizeof_loc = loc;
+ ret.original_code = LENGTHOF_EXPR;
+ ret.original_type = NULL;
+ ret.m_decimal = 0;
+ if (type == error_mark_node)
+ {
+ ret.value = error_mark_node;
+ ret.original_code = ERROR_MARK;
+ }
+ else
+ if ((type_expr || TREE_CODE (ret.value) == INTEGER_CST)
+ && 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
+ the result of lengthof does not get folded to a constant by
+ c_fully_fold, because if the length is evaluated the result is
+ not constant and so constraints on zero or negative size
+ arrays must not be applied when this lengthof call is inside
+ another array declarator. */
+ if (!type_expr)
+ type_expr = integer_zero_node;
+ ret.value = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (ret.value),
+ type_expr, ret.value);
+ C_MAYBE_CONST_EXPR_NON_CONST (ret.value) = !type_expr_const;
+ }
+ pop_maybe_used (type != error_mark_node ? is_top_array_vla (type) : false);
+ return ret;
+}
+
/* Build a function call to function FUNCTION with parameters PARAMS.
The function call is at LOC.
PARAMS is a list--a chain of TREE_LIST nodes--in which the
diff --git a/gcc/cp/operators.def b/gcc/cp/operators.def
index d8878923602..d640ed8bd91 100644
--- a/gcc/cp/operators.def
+++ b/gcc/cp/operators.def
@@ -91,6 +91,7 @@ DEF_OPERATOR ("co_await", CO_AWAIT_EXPR, "aw", OVL_OP_FLAG_UNARY)
/* These are extensions. */
DEF_OPERATOR ("alignof", ALIGNOF_EXPR, "az", OVL_OP_FLAG_UNARY)
+DEF_OPERATOR ("__lengthof__", LENGTHOF_EXPR, "lz", OVL_OP_FLAG_UNARY)
DEF_OPERATOR ("__imag__", IMAGPART_EXPR, "v18__imag__", OVL_OP_FLAG_UNARY)
DEF_OPERATOR ("__real__", REALPART_EXPR, "v18__real__", OVL_OP_FLAG_UNARY)
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 0b572afca72..6e1d302150d 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -10391,6 +10391,33 @@ 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 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}.
+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
@cindex inline functions
diff --git a/gcc/target.h b/gcc/target.h
index c1f99b97b86..79890ae9944 100644
--- a/gcc/target.h
+++ b/gcc/target.h
@@ -245,6 +245,9 @@ enum type_context_kind {
/* Directly measuring the alignment of T. */
TCTX_ALIGNOF,
+ /* Directly measuring the length of array T. */
+ TCTX_LENGTHOF,
+
/* Creating objects of type T with static storage duration. */
TCTX_STATIC_STORAGE,
--
2.45.2
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 248+ messages in thread
* [RFC v4 4/4] testsuite: Add tests for __lengthof__
2024-08-06 12:22 ` [RFC v4 0/4] c: Add __lengthof__ operator Alejandro Colomar
` (2 preceding siblings ...)
2024-08-06 12:22 ` [RFC v4 3/4] c: Add __lengthof__() operator (n2529) Alejandro Colomar
@ 2024-08-06 12:22 ` Alejandro Colomar
2024-08-06 12:24 ` [RFC v4 0/4] c: Add __lengthof__ operator Alejandro Colomar
` (3 subsequent siblings)
7 siblings, 0 replies; 248+ messages in thread
From: Alejandro Colomar @ 2024-08-06 12:22 UTC (permalink / raw)
To: gcc-patches
Cc: Alejandro Colomar, Xavier Del Campo Romero, Martin Uecker,
Gabriel Ravier, Joseph Myers, Jakub Jelinek, Kees Cook,
Qing Zhao, Jens Gustedt
[-- Attachment #1: Type: text/plain, Size: 3955 bytes --]
I've compiled those files manually, and they behave as expected. But
within the test-suite, they don't seem to work:
FAIL: gcc.dg/lengthof-compile.c (test for excess errors)
FAIL: gcc.dg/lengthof.c (test for excess errors)
Signed-off-by: Alejandro Colomar <alx@kernel.org>
---
gcc/testsuite/gcc.dg/lengthof-compile.c | 48 +++++++++
gcc/testsuite/gcc.dg/lengthof.c | 126 ++++++++++++++++++++++++
2 files changed, 174 insertions(+)
create mode 100644 gcc/testsuite/gcc.dg/lengthof-compile.c
create mode 100644 gcc/testsuite/gcc.dg/lengthof.c
diff --git a/gcc/testsuite/gcc.dg/lengthof-compile.c b/gcc/testsuite/gcc.dg/lengthof-compile.c
new file mode 100644
index 00000000000..b5ca8978a99
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/lengthof-compile.c
@@ -0,0 +1,48 @@
+/* { dg-do compile } */
+
+extern int x[];
+
+void
+incomplete(int p[])
+{
+ unsigned n;
+
+ n = __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" } */
+}
+
+void
+fam(void)
+{
+ struct {
+ int x;
+ int fam[];
+ } s;
+ unsigned n;
+
+ n = __lengthof__(s.fam); /* { dg-error "incomplete" } */
+}
+
+void fix_fix(int i, char (*a)[3][5], int (*x)[__lengthof__(*a)]);
+void fix_var(int i, char (*a)[3][i], int (*x)[__lengthof__(*a)]);
+void fix_uns(int i, char (*a)[3][*], int (*x)[__lengthof__(*a)]);
+
+void
+func(void)
+{
+ int i3[3];
+ int i5[5];
+ char c35[3][5];
+
+ fix_fix(5, &c35, &i3);
+ fix_fix(5, &c35, &i5); /* { dg-error "incompatible-pointer-types" } */
+
+ fix_var(5, &c35, &i3);
+ fix_var(5, &c35, &i5); /* { dg-error "incompatible-pointer-types" } */
+
+ fix_uns(5, &c35, &i3);
+ fix_uns(5, &c35, &i5); /* { dg-error "incompatible-pointer-types" } */
+}
diff --git a/gcc/testsuite/gcc.dg/lengthof.c b/gcc/testsuite/gcc.dg/lengthof.c
new file mode 100644
index 00000000000..6aec558749c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/lengthof.c
@@ -0,0 +1,126 @@
+/* { dg-do run } */
+
+#undef NDEBUG
+#include <assert.h>
+
+void
+array(void)
+{
+ short a[7];
+
+ assert(__lengthof__(a) == 7);
+ assert(__lengthof__(long [0]) == 0);
+ assert(__lengthof__(unsigned [99]) == 99);
+}
+
+void
+vla(void)
+{
+ unsigned n;
+
+ n = 99;
+ assert(__lengthof__(short [n - 10]) == 99 - 10);
+
+ int v[n / 2];
+ assert(__lengthof__(v) == 99 / 2);
+
+ n = 0;
+ int z[n];
+ assert(__lengthof__(z) == 0);
+}
+
+void
+member(void)
+{
+ struct {
+ int a[8];
+ } s;
+
+ assert(__lengthof__(s.a) == 8);
+}
+
+void
+vla_eval(void)
+{
+ int i;
+
+ i = 7;
+ assert(__lengthof__(struct {int x;}[i++]) == 7);
+ assert(i == 7 + 1);
+
+ int v[i];
+ int (*p)[i];
+ p = &v;
+ assert(__lengthof__(*p++) == i);
+ assert(p - 1 == &v);
+}
+
+void
+inner_vla_noeval(void)
+{
+ int i;
+
+ i = 3;
+ assert(__lengthof__(struct {int x[i++];}[3]) == 3);
+ assert(i == 3);
+}
+
+void
+array_noeval(void)
+{
+ long a[5];
+ long (*p)[__lengthof__(a)];
+
+ p = &a;
+ assert(__lengthof__(*p++) == 5);
+ assert(p == &a);
+}
+
+void
+matrix_zero(void)
+{
+ int i;
+
+ assert(__lengthof__(int [0][4]) == 0);
+ i = 3;
+ assert(__lengthof__(int [0][i]) == 0);
+}
+
+void
+matrix_fixed(void)
+{
+ int i;
+
+ assert(__lengthof__(int [7][4]) == 7);
+ i = 3;
+ assert(__lengthof__(int [7][i]) == 7);
+}
+
+void
+matrix_vla(void)
+{
+ int i, j;
+
+ i = 7;
+ assert(__lengthof__(int [i++][4]) == 7);
+ assert(i == 7 + 1);
+
+ i = 9;
+ j = 3;
+ assert(__lengthof__(int [i++][j]) == 9);
+ assert(i == 9 + 1);
+}
+
+int
+main(void)
+{
+ array();
+ vla();
+ member();
+ vla_eval();
+ inner_vla_noeval();
+ array_noeval();
+ matrix_zero();
+ matrix_fixed();
+ matrix_vla();
+}
--
2.45.2
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [RFC v4 0/4] c: Add __lengthof__ operator
2024-08-06 12:22 ` [RFC v4 0/4] c: Add __lengthof__ operator Alejandro Colomar
` (3 preceding siblings ...)
2024-08-06 12:22 ` [RFC v4 4/4] testsuite: Add tests for __lengthof__ Alejandro Colomar
@ 2024-08-06 12:24 ` Alejandro Colomar
2024-08-06 13:37 ` Martin Uecker
` (2 subsequent siblings)
7 siblings, 0 replies; 248+ messages in thread
From: Alejandro Colomar @ 2024-08-06 12:24 UTC (permalink / raw)
To: gcc-patches, Martin Uecker
Cc: Xavier Del Campo Romero, Gabriel Ravier, Joseph Myers,
Jakub Jelinek, Kees Cook, Qing Zhao, Jens Gustedt
[-- Attachment #1: Type: text/plain, Size: 26738 bytes --]
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 <alx@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.dcr@tutanota.com>
> + Link: <https://inbox.sourceware.org/gcc/M8S4oQy--3-2@tutanota.com/T/>
> + Suggested-by: Xavier Del Campo Romero <xavi.dcr@tutanota.com>
> + Co-developed-by: Martin Uecker <uecker@tugraz.at>
> Cc: Gabriel Ravier <gabravier@gmail.com>
> - Cc: Martin Uecker <uecker@tugraz.at>
> Cc: Joseph Myers <josmyers@redhat.com>
> Cc: Jakub Jelinek <jakub@redhat.com>
> + Cc: Kees Cook <keescook@chromium.org>
> + Cc: Qing Zhao <qing.zhao@oracle.com>
> + Cc: Jens Gustedt <jens.gustedt@inria.fr>
> Signed-off-by: Alejandro Colomar <alx@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/>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [RFC v4 0/4] c: Add __lengthof__ operator
2024-08-06 12:22 ` [RFC v4 0/4] c: Add __lengthof__ operator Alejandro Colomar
` (4 preceding siblings ...)
2024-08-06 12:24 ` [RFC v4 0/4] c: Add __lengthof__ operator Alejandro Colomar
@ 2024-08-06 13:37 ` Martin Uecker
2024-08-06 14:12 ` Alejandro Colomar
2024-08-06 15:59 ` Qing Zhao
2024-08-06 17:38 ` Joseph Myers
7 siblings, 1 reply; 248+ messages in thread
From: Martin Uecker @ 2024-08-06 13:37 UTC (permalink / raw)
To: Alejandro Colomar, gcc-patches
Cc: Xavier Del Campo Romero, Gabriel Ravier, Joseph Myers,
Jakub Jelinek, Kees Cook, Qing Zhao, Jens Gustedt
Am Dienstag, dem 06.08.2024 um 14:22 +0200 schrieb Alejandro Colomar:
> Hi!
>
> - 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?
What is the output? You get an additional warning / error.
>
> - 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?
The C++ frontend encodes zero-sized arrays using a range of [0,-1].
I have a half-finished patch which implements this for the C FE.
Martin
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [RFC v4 0/4] c: Add __lengthof__ operator
2024-08-06 13:37 ` Martin Uecker
@ 2024-08-06 14:12 ` Alejandro Colomar
2024-08-06 14:43 ` Martin Uecker
0 siblings, 1 reply; 248+ messages in thread
From: Alejandro Colomar @ 2024-08-06 14:12 UTC (permalink / raw)
To: Martin Uecker
Cc: gcc-patches, Xavier Del Campo Romero, Gabriel Ravier,
Joseph Myers, Jakub Jelinek, Kees Cook, Qing Zhao, Jens Gustedt
[-- Attachment #1: Type: text/plain, Size: 6159 bytes --]
Hi Martin,
On Tue, Aug 06, 2024 at 03:37:13PM GMT, Martin Uecker wrote:
> Am Dienstag, dem 06.08.2024 um 14:22 +0200 schrieb Alejandro Colomar:
> > Hi!
> >
> > - 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?
>
> What is the output? You get an additional warning / error.
$ /opt/local/gnu/gcc/lengthof/bin/gcc gcc/testsuite/gcc.dg/lengthof-compile.c
gcc/testsuite/gcc.dg/lengthof-compile.c: In function ‘incomplete’:
gcc/testsuite/gcc.dg/lengthof-compile.c:10:19: error: invalid application of ‘lengthof’ to incomplete type ‘int[]’
10 | n = __lengthof__(x); /* { dg-error "incomplete" } */
| ^
gcc/testsuite/gcc.dg/lengthof-compile.c:14:19: error: invalid application of ‘lengthof’ to type ‘int *’
14 | n = __lengthof__(p); /* { dg-error "invalid" } */
| ^
gcc/testsuite/gcc.dg/lengthof-compile.c: In function ‘fam’:
gcc/testsuite/gcc.dg/lengthof-compile.c:26:19: error: invalid application of ‘lengthof’ to incomplete type ‘int[]’
26 | n = __lengthof__(s.fam); /* { dg-error "incomplete" } */
| ^
gcc/testsuite/gcc.dg/lengthof-compile.c: In function ‘func’:
gcc/testsuite/gcc.dg/lengthof-compile.c:41:20: error: passing argument 3 of ‘fix_fix’ from incompatible pointer type [-Wincompatible-pointer-types]
41 | fix_fix(5, &c35, &i5); /* { dg-error "incompatible-pointer-types" } */
| ^~~
| |
| int (*)[5]
gcc/testsuite/gcc.dg/lengthof-compile.c:29:44: note: expected ‘int (*)[3]’ but argument is of type ‘int (*)[5]’
29 | void fix_fix(int i, char (*a)[3][5], int (*x)[__lengthof__(*a)]);
| ~~~~~~^~~~~~~~~~~~~~~~~~~~
gcc/testsuite/gcc.dg/lengthof-compile.c:44:20: error: passing argument 3 of ‘fix_var’ from incompatible pointer type [-Wincompatible-pointer-types]
44 | fix_var(5, &c35, &i5); /* { dg-error "incompatible-pointer-types" } */
| ^~~
| |
| int (*)[5]
gcc/testsuite/gcc.dg/lengthof-compile.c:30:44: note: expected ‘int (*)[3]’ but argument is of type ‘int (*)[5]’
30 | void fix_var(int i, char (*a)[3][i], int (*x)[__lengthof__(*a)]);
| ~~~~~~^~~~~~~~~~~~~~~~~~~~
gcc/testsuite/gcc.dg/lengthof-compile.c:47:20: error: passing argument 3 of ‘fix_uns’ from incompatible pointer type [-Wincompatible-pointer-types]
47 | fix_uns(5, &c35, &i5); /* { dg-error "incompatible-pointer-types" } */
| ^~~
| |
| int (*)[5]
gcc/testsuite/gcc.dg/lengthof-compile.c:31:44: note: expected ‘int (*)[3]’ but argument is of type ‘int (*)[5]’
31 | void fix_uns(int i, char (*a)[3][*], int (*x)[__lengthof__(*a)]);
| ~~~~~~^~~~~~~~~~~~~~~~~~~~
$ /opt/local/gnu/gcc/lengthof/bin/gcc gcc/testsuite/gcc.dg/lengthof-compile.c |& grep ' error: '
gcc/testsuite/gcc.dg/lengthof-compile.c:10:19: error: invalid application of ‘lengthof’ to incomplete type ‘int[]’
gcc/testsuite/gcc.dg/lengthof-compile.c:14:19: error: invalid application of ‘lengthof’ to type ‘int *’
gcc/testsuite/gcc.dg/lengthof-compile.c:26:19: error: invalid application of ‘lengthof’ to incomplete type ‘int[]’
gcc/testsuite/gcc.dg/lengthof-compile.c:41:20: error: passing argument 3 of ‘fix_fix’ from incompatible pointer type [-Wincompatible-pointer-types]
gcc/testsuite/gcc.dg/lengthof-compile.c:44:20: error: passing argument 3 of ‘fix_var’ from incompatible pointer type [-Wincompatible-pointer-types]
gcc/testsuite/gcc.dg/lengthof-compile.c:47:20: error: passing argument 3 of ‘fix_uns’ from incompatible pointer type [-Wincompatible-pointer-types]
$ /opt/local/gnu/gcc/lengthof/bin/gcc gcc/testsuite/gcc.dg/lengthof-compile.c |& grep ' error: ' | wc -l
6
I count 6, which is what I expect:
$ grep dg-error gcc/testsuite/gcc.dg/lengthof-compile.c
n = __lengthof__(x); /* { dg-error "incomplete" } */
n = __lengthof__(p); /* { dg-error "invalid" } */
n = __lengthof__(s.fam); /* { dg-error "incomplete" } */
fix_fix(5, &c35, &i5); /* { dg-error "incompatible-pointer-types" } */
fix_var(5, &c35, &i5); /* { dg-error "incompatible-pointer-types" } */
fix_uns(5, &c35, &i5); /* { dg-error "incompatible-pointer-types" } */
$ grep dg-error gcc/testsuite/gcc.dg/lengthof-compile.c | wc -l
6
When running `make check -j24 -Orecurse |& tee log`, this is what I see:
FAIL: gcc.dg/lengthof-compile.c (test for excess errors)
Is there any way to see more details?
> > - 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?
>
> The C++ frontend encodes zero-sized arrays using a range of [0,-1].
> I have a half-finished patch which implements this for the C FE.
Thanks! I guess your patch will be merged before mine, so please ping
me when that happens so I update mine for it.
BTW, do you allow me to use Co-developed-by: you?
Have a lovely day!
Alex
--
<https://www.alejandro-colomar.es/>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [RFC v4 0/4] c: Add __lengthof__ operator
2024-08-06 14:12 ` Alejandro Colomar
@ 2024-08-06 14:43 ` Martin Uecker
2024-08-06 15:40 ` Alejandro Colomar
2024-08-06 21:46 ` Alejandro Colomar
0 siblings, 2 replies; 248+ messages in thread
From: Martin Uecker @ 2024-08-06 14:43 UTC (permalink / raw)
To: Alejandro Colomar
Cc: gcc-patches, Xavier Del Campo Romero, Gabriel Ravier,
Joseph Myers, Jakub Jelinek, Kees Cook, Qing Zhao, Jens Gustedt
Am Dienstag, dem 06.08.2024 um 16:12 +0200 schrieb Alejandro Colomar:
> Hi Martin,
>
> On Tue, Aug 06, 2024 at 03:37:13PM GMT, Martin Uecker wrote:
> > Am Dienstag, dem 06.08.2024 um 14:22 +0200 schrieb Alejandro Colomar:
> > > Hi!
> > >
> > > - 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?
> >
> > What is the output? You get an additional warning / error.
>
> $ /opt/local/gnu/gcc/lengthof/bin/gcc gcc/testsuite/gcc.dg/lengthof-compile.c
> gcc/testsuite/gcc.dg/lengthof-compile.c: In function ‘incomplete’:
> gcc/testsuite/gcc.dg/lengthof-compile.c:10:19: error: invalid application of ‘lengthof’ to incomplete type ‘int[]’
> 10 | n = __lengthof__(x); /* { dg-error "incomplete" } */
> | ^
> gcc/testsuite/gcc.dg/lengthof-compile.c:14:19: error: invalid application of ‘lengthof’ to type ‘int *’
> 14 | n = __lengthof__(p); /* { dg-error "invalid" } */
> | ^
> gcc/testsuite/gcc.dg/lengthof-compile.c: In function ‘fam’:
> gcc/testsuite/gcc.dg/lengthof-compile.c:26:19: error: invalid application of ‘lengthof’ to incomplete type ‘int[]’
> 26 | n = __lengthof__(s.fam); /* { dg-error "incomplete" } */
> | ^
> gcc/testsuite/gcc.dg/lengthof-compile.c: In function ‘func’:
> gcc/testsuite/gcc.dg/lengthof-compile.c:41:20: error: passing argument 3 of ‘fix_fix’ from incompatible pointer type [-Wincompatible-pointer-types]
> 41 | fix_fix(5, &c35, &i5); /* { dg-error "incompatible-pointer-types" } */
> | ^~~
> | |
> | int (*)[5]
> gcc/testsuite/gcc.dg/lengthof-compile.c:29:44: note: expected ‘int (*)[3]’ but argument is of type ‘int (*)[5]’
> 29 | void fix_fix(int i, char (*a)[3][5], int (*x)[__lengthof__(*a)]);
> | ~~~~~~^~~~~~~~~~~~~~~~~~~~
> gcc/testsuite/gcc.dg/lengthof-compile.c:44:20: error: passing argument 3 of ‘fix_var’ from incompatible pointer type [-Wincompatible-pointer-types]
> 44 | fix_var(5, &c35, &i5); /* { dg-error "incompatible-pointer-types" } */
> | ^~~
> | |
> | int (*)[5]
> gcc/testsuite/gcc.dg/lengthof-compile.c:30:44: note: expected ‘int (*)[3]’ but argument is of type ‘int (*)[5]’
> 30 | void fix_var(int i, char (*a)[3][i], int (*x)[__lengthof__(*a)]);
> | ~~~~~~^~~~~~~~~~~~~~~~~~~~
> gcc/testsuite/gcc.dg/lengthof-compile.c:47:20: error: passing argument 3 of ‘fix_uns’ from incompatible pointer type [-Wincompatible-pointer-types]
> 47 | fix_uns(5, &c35, &i5); /* { dg-error "incompatible-pointer-types" } */
> | ^~~
> | |
> | int (*)[5]
> gcc/testsuite/gcc.dg/lengthof-compile.c:31:44: note: expected ‘int (*)[3]’ but argument is of type ‘int (*)[5]’
> 31 | void fix_uns(int i, char (*a)[3][*], int (*x)[__lengthof__(*a)]);
> | ~~~~~~^~~~~~~~~~~~~~~~~~~~
> $ /opt/local/gnu/gcc/lengthof/bin/gcc gcc/testsuite/gcc.dg/lengthof-compile.c |& grep ' error: '
> gcc/testsuite/gcc.dg/lengthof-compile.c:10:19: error: invalid application of ‘lengthof’ to incomplete type ‘int[]’
> gcc/testsuite/gcc.dg/lengthof-compile.c:14:19: error: invalid application of ‘lengthof’ to type ‘int *’
> gcc/testsuite/gcc.dg/lengthof-compile.c:26:19: error: invalid application of ‘lengthof’ to incomplete type ‘int[]’
> gcc/testsuite/gcc.dg/lengthof-compile.c:41:20: error: passing argument 3 of ‘fix_fix’ from incompatible pointer type [-Wincompatible-pointer-types]
> gcc/testsuite/gcc.dg/lengthof-compile.c:44:20: error: passing argument 3 of ‘fix_var’ from incompatible pointer type [-Wincompatible-pointer-types]
> gcc/testsuite/gcc.dg/lengthof-compile.c:47:20: error: passing argument 3 of ‘fix_uns’ from incompatible pointer type [-Wincompatible-pointer-types]
> $ /opt/local/gnu/gcc/lengthof/bin/gcc gcc/testsuite/gcc.dg/lengthof-compile.c |& grep ' error: ' | wc -l
> 6
>
> I count 6, which is what I expect:
>
> $ grep dg-error gcc/testsuite/gcc.dg/lengthof-compile.c
> n = __lengthof__(x); /* { dg-error "incomplete" } */
> n = __lengthof__(p); /* { dg-error "invalid" } */
> n = __lengthof__(s.fam); /* { dg-error "incomplete" } */
> fix_fix(5, &c35, &i5); /* { dg-error "incompatible-pointer-types" } */
> fix_var(5, &c35, &i5); /* { dg-error "incompatible-pointer-types" } */
> fix_uns(5, &c35, &i5); /* { dg-error "incompatible-pointer-types" } */
> $ grep dg-error gcc/testsuite/gcc.dg/lengthof-compile.c | wc -l
> 6
>
> When running `make check -j24 -Orecurse |& tee log`, this is what I see:
>
> FAIL: gcc.dg/lengthof-compile.c (test for excess errors)
>
> Is there any way to see more details?
See gcc/testsuite/gcc/gcc.log
There are also *.sum files which you can diff against a build
without your patch to see whether there are any regressions.
>
> > > - 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?
> >
> > The C++ frontend encodes zero-sized arrays using a range of [0,-1].
> > I have a half-finished patch which implements this for the C FE.
>
> Thanks! I guess your patch will be merged before mine, so please ping
> me when that happens so I update mine for it.
Not sure about this...
>
> BTW, do you allow me to use Co-developed-by: you?
ok,
Martin
>
> Have a lovely day!
> Alex
>
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [RFC v3 3/3] c: Add __lengthof__() operator
2024-08-05 20:59 ` Alejandro Colomar
@ 2024-08-06 15:23 ` Qing Zhao
0 siblings, 0 replies; 248+ messages in thread
From: Qing Zhao @ 2024-08-06 15:23 UTC (permalink / raw)
To: Alejandro Colomar
Cc: Martin Uecker, Jakub Jelinek, Joseph Myers, GCC Patches,
Xavier Del Campo Romero, Gabriel Ravier, Kees Cook
[-- Attachment #1: Type: text/plain, Size: 1596 bytes --]
On Aug 5, 2024, at 16:59, Alejandro Colomar <alx@kernel.org> wrote:
The “counted-by” attribute currently is not in the TYPE system, and
we plan to add it into the TYPE system later through language
standard (or an GCC extension). If that happens, then both the
“sizeof” and the “__lengthof__” operators should be automatically
evaluate the “size" or the “length” for the expr through its TYPE.
(Just as the current VLA, its size and length already in the TYPE,
therefore both “sizeof” and “__lengthof__” should evaluate VLA.
I'm curious; how do you plan to make counted_by as part of the type
system? I've read the paper for using a .identifier length designator
(n3188; <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3188.htm>),
but that's a constant, and doesn't use an attribute.
The “counted_by” attribute is only a temporary and practical solution at this moment
to build a direct relationship between the length of the array and and array itself in the
source code level, but not touching the TYPE system at all.
The final plan is similar as the solution in the above paper you
referred.
i.e, currently, with “counted_by” attribute:
struct foo {
unsigned int count;
char array [] _attribute__ ((counted_by (count));
};
Later, when the relationship is built into TYPE, the above will become:
struct foo {
unsigned int count;
char array [.count];
};
That will be the cleanest solution to this problem.
However, might take a much longer time to final get into the compiler.
Thanks.
Qing
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [RFC v4 0/4] c: Add __lengthof__ operator
2024-08-06 14:43 ` Martin Uecker
@ 2024-08-06 15:40 ` Alejandro Colomar
2024-08-06 21:46 ` Alejandro Colomar
1 sibling, 0 replies; 248+ messages in thread
From: Alejandro Colomar @ 2024-08-06 15:40 UTC (permalink / raw)
To: Martin Uecker
Cc: gcc-patches, Xavier Del Campo Romero, Gabriel Ravier,
Joseph Myers, Jakub Jelinek, Kees Cook, Qing Zhao, Jens Gustedt
[-- Attachment #1: Type: text/plain, Size: 2321 bytes --]
Hi Martin,
On Tue, Aug 06, 2024 at 04:43:27PM GMT, Martin Uecker wrote:
> > When running `make check -j24 -Orecurse |& tee log`, this is what I see:
> >
> > FAIL: gcc.dg/lengthof-compile.c (test for excess errors)
> >
> > Is there any way to see more details?
>
> See gcc/testsuite/gcc/gcc.log
Ahhh, thanks! It seems it was only the obvious C90-compat warnings that
I need to turn off. It all seems good after that.
FAIL: gcc.dg/lengthof-compile.c (test for excess errors)
Excess errors:
/home/alx/src/gnu/gcc/len/gcc/testsuite/gcc.dg/lengthof-compile.c:22:9: error: ISO C90 does not support flexible array members [-Wpedantic]
/home/alx/src/gnu/gcc/len/gcc/testsuite/gcc.dg/lengthof-compile.c:30:1: error: ISO C90 forbids variable length array 'a' [-Wvla]
/home/alx/src/gnu/gcc/len/gcc/testsuite/gcc.dg/lengthof-compile.c:31:33: error: ISO C90 does not support '[*]' array declarators [-Wpedantic]
>
> There are also *.sum files which you can diff against a build
> without your patch to see whether there are any regressions.
Good. I'll check.
> > > > - 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?
> > >
> > > The C++ frontend encodes zero-sized arrays using a range of [0,-1].
> > > I have a half-finished patch which implements this for the C FE.
> >
> > Thanks! I guess your patch will be merged before mine, so please ping
> > me when that happens so I update mine for it.
>
> Not sure about this...
:)
> >
> > BTW, do you allow me to use Co-developed-by: you?
>
> ok,
Thanks!
Cheers,
Alex
> Martin
> >
> > Have a lovely day!
> > Alex
--
<https://www.alejandro-colomar.es/>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [RFC v4 0/4] c: Add __lengthof__ operator
2024-08-06 12:22 ` [RFC v4 0/4] c: Add __lengthof__ operator Alejandro Colomar
` (5 preceding siblings ...)
2024-08-06 13:37 ` Martin Uecker
@ 2024-08-06 15:59 ` Qing Zhao
2024-08-06 16:48 ` Alejandro Colomar
2024-08-06 17:38 ` Joseph Myers
7 siblings, 1 reply; 248+ messages in thread
From: Qing Zhao @ 2024-08-06 15:59 UTC (permalink / raw)
To: Alejandro Colomar
Cc: GCC Patches, Martin Uecker, Xavier Del Campo Romero,
Gabriel Ravier, Joseph Myers, Jakub Jelinek, Kees Cook,
Jens Gustedt
[-- Attachment #1: Type: text/plain, Size: 25815 bytes --]
Hi, Alex,
I noticed that all your 4 versions of the patches and the corresponding discussion are all in the same email thread, it’s very inconvenient to read. Can you start a new email thread for each of the new version of the patch? (i.e, Please not reply to the previous version when you have a new version of the patch).
Some more questions and comments below:
On Aug 6, 2024, at 08:22, Alejandro Colomar <alx@kernel.org> 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
was questioned the value of this operator. Below is a rationale to
defend it.
I briefly read the two links you provided as the background of your patch:
https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2529.pdf
This is a proposal submitted on 6/4/2020, do you know the current status of this proposal?
https://inbox.sourceware.org/gcc/M8S4oQy--3-2@tutanota.com/T/
This is some discussion within GCC community on this proposal around the same time (the end of May of 2020, before the submission date of the proposal).
From the discussion, I didn’t see a consistent positive opinion on the proposal itself.
So, I am wondering whether you have any new background information since then? What’s the major motivation to bring up this proposal again this time after 4 years?
- 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.
Is this one of major benefits from this new __lenghth__ operator?
If so, any rough idea now on how to implement this (i.e, the length of a function parameter array).
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.
What kind of issues are? What’s the plan to resolve those issues?
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?
You might want to check some existing testing cases in GCC’s testsuite first to see what kind of directives you are missing in your test case. (For example, any testing case in gcc/testsuite/gcc.dg/).
The documentation of the test suite is here:
https://gcc.gnu.org/onlinedocs/gccint/Testsuites.html
Adding testing case correctly into GCC’s testing suite is very important for any patch. And adding them in the beginning of the development also is very important and will save you a lot of time.
Qing
- 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 <alx@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.dcr@tutanota.com>
+ Link: <https://inbox.sourceware.org/gcc/M8S4oQy--3-2@tutanota.com/T/>
+ Suggested-by: Xavier Del Campo Romero <xavi.dcr@tutanota.com>
+ Co-developed-by: Martin Uecker <uecker@tugraz.at>
Cc: Gabriel Ravier <gabravier@gmail.com>
- Cc: Martin Uecker <uecker@tugraz.at>
Cc: Joseph Myers <josmyers@redhat.com>
Cc: Jakub Jelinek <jakub@redhat.com>
+ Cc: Kees Cook <keescook@chromium.org>
+ Cc: Qing Zhao <qing.zhao@oracle.com>
+ Cc: Jens Gustedt <jens.gustedt@inria.fr>
Signed-off-by: Alejandro Colomar <alx@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
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [RFC v4 0/4] c: Add __lengthof__ operator
2024-08-06 15:59 ` Qing Zhao
@ 2024-08-06 16:48 ` Alejandro Colomar
0 siblings, 0 replies; 248+ messages in thread
From: Alejandro Colomar @ 2024-08-06 16:48 UTC (permalink / raw)
To: Qing Zhao
Cc: GCC Patches, Martin Uecker, Xavier Del Campo Romero,
Gabriel Ravier, Joseph Myers, Jakub Jelinek, Kees Cook,
Jens Gustedt, David Brown, Florian Weimer, Andreas Schwab
[-- Attachment #1: Type: text/plain, Size: 5080 bytes --]
[CC += David, Florian, Andreas]
On Tue, Aug 06, 2024 at 03:59:11PM GMT, Qing Zhao wrote:
> Hi, Alex,
Hi Qing,
> I noticed that all your 4 versions of the patches and the
> corresponding discussion are all in the same email thread, it’s very
> inconvenient to read. Can you start a new email thread for each of the
> new version of the patch? (i.e, Please not reply to the previous
> version when you have a new version of the patch).
Hmmm; I have the opposite opinion in projects that I maintain. I prefer
when successive iterations of the same patch set are replies to the same
thread, which allows to easily go back to the previous iterations.
Is there consensus in gcc-patches@ that I should start new threads for
each revision?
I very much prefer to keep using a single thread to keep my sanity, but
I'll do whatever gcc-patches@ maintainers prefer.
> Some more questions and comments below:
Could you please use quoting character? I find it hard to distinguish
the quoted parts from your own.
> I briefly read the two links you provided as the background of your patch:
>
> https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2529.pdf
>
> This is a proposal submitted on 6/4/2020, do you know the current
> status of this proposal?
I CCed the author of that proposal, but he didn't say anything. The
proposal probably died.
>
> https://inbox.sourceware.org/gcc/M8S4oQy--3-2@tutanota.com/T/
>
> This is some discussion within GCC community on this proposal around
> the same time (the end of May of 2020, before the submission date of
> the proposal).
>
> From the discussion, I didn’t see a consistent positive opinion on the
> proposal itself.
I've read it. The feedback was basically that _Lengthof() would be
redundant with ARRAY_SIZE() for those careful enough to use it, and a
dead language feature for the cowboys that don't like seat belts.
However, it didn't take into account the possibility of including array
length information in function parameters declared with array notation,
which is a net improvement for everyone.
I've CCed David (the author of 2020's negative feedback) in case he has
any comments.
From what I've seen in these 4 revisions, feedback is not bad. I've
also been discussing several array features lately, and it seems like
the way forward. Hopefully, the general opinion has changed.
BTW, the linux kernel is starting to use macros that magically get the
array length:
<https://lore.kernel.org/all/CAHk-=wgXYkMueFpxgSY_vfCzdcCnyoaPcjS8e0BXiRfgceRHfQ@mail.gmail.com/>
This is also what shadow utils is doing (done by me). By having
__lengthof__ work on function parameters, these macros will be usable in
more places.
> So, I am wondering whether you have any new background information
> since then? What’s the major motivation to bring up this proposal
> again this time after 4 years?
When I proposed this a couple of years ago (before knowing about n2539),
there was some positive feedback. I didn't have the time back then to
implement it, but I have now. So far, I've only seen positive feedback
about it.
> 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.
>
>
> Is this one of major benefits from this new __lenghth__ operator?
I'd say the main one, yes. As in, I think C++ might have not been
invented or not have developed their own arrays if we had this
functionality in C back then.
> If so, any rough idea now on how to implement this (i.e, the length of
> a function parameter array).
By implementing the function parameters as actual arrays inside the
compiler instead of just pointers.
<https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2906.pdf>
Martin is working on several array features at the moment.
> 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.
>
>
> What kind of issues are? What’s the plan to resolve those issues?
n2906. When n2906 is implemented by Martin, __lengthof__ will be able
to work on function parameters. He may be able to talk more about it.
> - 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?
>
> You might want to check some existing testing cases in GCC’s testsuite
> first to see what kind of directives you are missing in your test
> case. (For example, any testing case in gcc/testsuite/gcc.dg/).
It was some spurious warnings. Martin helped me with those, and it's
already solved in my working copy.
Have a lovely day!
Alex
--
<https://www.alejandro-colomar.es/>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [RFC v4 0/4] c: Add __lengthof__ operator
2024-08-06 12:22 ` [RFC v4 0/4] c: Add __lengthof__ operator Alejandro Colomar
` (6 preceding siblings ...)
2024-08-06 15:59 ` Qing Zhao
@ 2024-08-06 17:38 ` Joseph Myers
2024-08-06 20:22 ` Alejandro Colomar
7 siblings, 1 reply; 248+ messages in thread
From: Joseph Myers @ 2024-08-06 17:38 UTC (permalink / raw)
To: Alejandro Colomar
Cc: gcc-patches, Martin Uecker, Xavier Del Campo Romero,
Gabriel Ravier, Jakub Jelinek, Kees Cook, Qing Zhao,
Jens Gustedt
On Tue, 6 Aug 2024, Alejandro Colomar wrote:
> - 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?
You almost certainly want to specify dg-options in the tests rather than
using the default "-ansi -pedantic" for gcc.dg.
Next question for the specification, implementation and tests: how does
this feature interact with the rules on external definitions (the contexts
in which it's OK to refer to an identifier with internal or external
linkage that's never defined - for example, a function, static or extern,
with a declaration but no definition; see 6.9.1)? My expectation would be
that the rules are analogous to those for sizeof and typeof: in the cases
where this operator does not evaluate its operand, it's also OK to
reference an identifier that's declared but not defined, but in the cases
where the operand is evaluated, that's not OK. (See gcc.dg/c99-static-1.c
for example tests of these rules for sizeof.)
--
Joseph S. Myers
josmyers@redhat.com
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [RFC v4 3/4] c: Add __lengthof__() operator (n2529)
2024-08-06 12:22 ` [RFC v4 3/4] c: Add __lengthof__() operator (n2529) Alejandro Colomar
@ 2024-08-06 20:15 ` Qing Zhao
2024-08-06 20:38 ` Alejandro Colomar
0 siblings, 1 reply; 248+ messages in thread
From: Qing Zhao @ 2024-08-06 20:15 UTC (permalink / raw)
To: Alejandro Colomar
Cc: GCC Patches, Xavier Del Campo Romero, Martin Uecker,
Gabriel Ravier, Joseph Myers, Jakub Jelinek, Kees Cook,
Jens Gustedt
Some comments on the documentation part.
(Hopefully, this time my quoting format is good, I checked the email
sent back to myself, no formatting issue, but when I checked the emails
in the archive, https://gcc.gnu.org/pipermail/gcc-patches/2024-August/659593.html,
yst, I see the quoting format issue you mentioned, adjusted my mail client setting,
hopefully this time it’s good)
> On Aug 6, 2024, at 08:22, Alejandro Colomar <alx@kernel.org> wrote:
>
> diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
> index 0b572afca72..6e1d302150d 100644
> --- a/gcc/doc/extend.texi
> +++ b/gcc/doc/extend.texi
> @@ -10391,6 +10391,33 @@ 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 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}.
> +The operand must be a complete array type.
What’s the behavior when the array operand is a VLA, or a flexible array member?
Should these be clarified in the documentation part?
> +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.
Can you add small examples to clarify the above?
> +
> +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.
For incomplete array (for example, flexible array members), as I mentioned in another email:
https://gcc.gnu.org/pipermail/gcc-patches/2024-August/659478.html
I think that it’s better to wait the Length information is finally integrated into TYPE.
thanks.
Qing
> +
> @node Inline
> @section An Inline Function is As Fast As a Macro
> @cindex inline functions
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [RFC v4 0/4] c: Add __lengthof__ operator
2024-08-06 17:38 ` Joseph Myers
@ 2024-08-06 20:22 ` Alejandro Colomar
2024-08-06 20:50 ` Joseph Myers
0 siblings, 1 reply; 248+ messages in thread
From: Alejandro Colomar @ 2024-08-06 20:22 UTC (permalink / raw)
To: Joseph Myers
Cc: gcc-patches, Martin Uecker, Xavier Del Campo Romero,
Gabriel Ravier, Jakub Jelinek, Kees Cook, Qing Zhao,
Jens Gustedt
[-- Attachment #1: Type: text/plain, Size: 2292 bytes --]
Hi Joseph!
On Tue, Aug 06, 2024 at 05:38:50PM GMT, Joseph Myers wrote:
> On Tue, 6 Aug 2024, Alejandro Colomar wrote:
>
> > - 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?
>
> You almost certainly want to specify dg-options in the tests rather than
> using the default "-ansi -pedantic" for gcc.dg.
That was the solution; yup. :)
> Next question for the specification, implementation and tests: how does
> this feature interact with the rules on external definitions (the contexts
> in which it's OK to refer to an identifier with internal or external
> linkage that's never defined - for example, a function, static or extern,
> with a declaration but no definition; see 6.9.1)?
Functions are not array types, so they don't apply. It's a constraint
violation --mandatory error-- to call __lengthof__(func).
VLAs cannot have static storage duration or file scope. Any array that
has static storage duration or extern linkage must be a normal array.
Since normal arrays operands are not evaluated, __lengthof__ returns a
constant expression, and there's no issue at all.
I can't think of any case where we'd have problems; do you have any
other example?
> My expectation would be
> that the rules are analogous to those for sizeof and typeof: in the cases
> where this operator does not evaluate its operand, it's also OK to
> reference an identifier that's declared but not defined, but in the cases
> where the operand is evaluated, that's not OK. (See gcc.dg/c99-static-1.c
> for example tests of these rules for sizeof.)
- Non-arrays are not valid operands to __lengthof__, of course.
- We only evaluate the operand if the top-level array is a VLA, which
cannot happen at file scope, nor with objects with static storage
duration, nor with objects with external linkage.
- So, everything is a constexpr in these cases, which is fine.
Thanks for being so pedantic! It helps a lot. :-)
Have a lovely night!
Alex
--
<https://www.alejandro-colomar.es/>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [RFC v4 3/4] c: Add __lengthof__() operator (n2529)
2024-08-06 20:15 ` Qing Zhao
@ 2024-08-06 20:38 ` Alejandro Colomar
2024-08-06 20:41 ` Alejandro Colomar
0 siblings, 1 reply; 248+ messages in thread
From: Alejandro Colomar @ 2024-08-06 20:38 UTC (permalink / raw)
To: Qing Zhao
Cc: GCC Patches, Xavier Del Campo Romero, Martin Uecker,
Gabriel Ravier, Joseph Myers, Jakub Jelinek, Kees Cook,
Jens Gustedt
[-- Attachment #1: Type: text/plain, Size: 4296 bytes --]
Hi Qing,
On Tue, Aug 06, 2024 at 08:15:50PM GMT, Qing Zhao wrote:
> Some comments on the documentation part.
>
> (Hopefully, this time my quoting format is good, I checked the email
> sent back to myself, no formatting issue, but when I checked the emails
> in the archive, https://gcc.gnu.org/pipermail/gcc-patches/2024-August/659593.html,
> yst, I see the quoting format issue you mentioned, adjusted my mail client setting,
> hopefully this time it’s good)
Yup; it's good now. Thanks! ;)
> > On Aug 6, 2024, at 08:22, Alejandro Colomar <alx@kernel.org> wrote:
> >
> > diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
> > index 0b572afca72..6e1d302150d 100644
> > --- a/gcc/doc/extend.texi
> > +++ b/gcc/doc/extend.texi
> > @@ -10391,6 +10391,33 @@ 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 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}.
> > +The operand must be a complete array type.
>
> What’s the behavior when the array operand is a VLA,
The number of elements in the array is returned.
The value is a run-time value; not a constant expression.
The behavior is identical to sizeof(a)/sizeof(*a), except that obviously
the operand is only written once, so it's only evaluated once.
size_t n = arc4random();
assert(n == __lengthof__(int [n]));
I think this is covered by
+The keyword @code{__lengthof__} determines the length of an array operand,
+that is, the number of elements in the array.
> or a flexible array member?
A flexible array member is an incomplete type, and so it is a constraint
violation. It results in a compile-time error.
I think this is covered by
+The operand must be a complete array type.
> Should these be clarified in the documentation part?
I don't know. I think it's already documented. I prefer keeping it
concise, as long as it's not ambiguous.
> > +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.
>
> Can you add small examples to clarify the above?
The examples would be rather confusing.
__lengthof__(int [4][n]); // constant expression
__lengthof__(int [n][4]); // run-time value
I think these would be interesting in the docs. I'll check what would
be the appropriate formatting for these. Thanks!
> > +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.
>
> For incomplete array (for example, flexible array members), as I
> mentioned in another email:
> https://gcc.gnu.org/pipermail/gcc-patches/2024-August/659478.html
>
> I think that it’s better to wait the Length information is finally
> integrated into TYPE.
Yes, I agree for a start. But I also don't want to allow any user to
rely on the fact that __lengthof__ rejects pointers to determine that
something is not a pointer, because we reserve the possibility of
extending the operator to work on certain pointers. (I'm not saying
we'll do it; but we reserve the right.)
Maybe we can just trust that nobody will do that, and complain if we see
anyone using it in that way.
I think I'll just remove that paragraph.
Have a lovely night!
Alex
>
> thanks.
>
> Qing
--
<https://www.alejandro-colomar.es/>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [RFC v4 3/4] c: Add __lengthof__() operator (n2529)
2024-08-06 20:38 ` Alejandro Colomar
@ 2024-08-06 20:41 ` Alejandro Colomar
0 siblings, 0 replies; 248+ messages in thread
From: Alejandro Colomar @ 2024-08-06 20:41 UTC (permalink / raw)
To: Qing Zhao
Cc: GCC Patches, Xavier Del Campo Romero, Martin Uecker,
Gabriel Ravier, Joseph Myers, Jakub Jelinek, Kees Cook,
Jens Gustedt
[-- Attachment #1: Type: text/plain, Size: 4744 bytes --]
On Tue, Aug 06, 2024 at 10:38:55PM GMT, Alejandro Colomar wrote:
> Hi Qing,
>
> On Tue, Aug 06, 2024 at 08:15:50PM GMT, Qing Zhao wrote:
> > Some comments on the documentation part.
> >
> > (Hopefully, this time my quoting format is good, I checked the email
> > sent back to myself, no formatting issue, but when I checked the emails
> > in the archive, https://gcc.gnu.org/pipermail/gcc-patches/2024-August/659593.html,
> > yst, I see the quoting format issue you mentioned, adjusted my mail client setting,
> > hopefully this time it’s good)
>
> Yup; it's good now. Thanks! ;)
>
> > > On Aug 6, 2024, at 08:22, Alejandro Colomar <alx@kernel.org> wrote:
> > >
> > > diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
> > > index 0b572afca72..6e1d302150d 100644
> > > --- a/gcc/doc/extend.texi
> > > +++ b/gcc/doc/extend.texi
> > > @@ -10391,6 +10391,33 @@ 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 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}.
> > > +The operand must be a complete array type.
> >
> > What’s the behavior when the array operand is a VLA,
>
> The number of elements in the array is returned.
> The value is a run-time value; not a constant expression.
> The behavior is identical to sizeof(a)/sizeof(*a), except that obviously
> the operand is only written once, so it's only evaluated once.
>
> size_t n = arc4random();
> assert(n == __lengthof__(int [n]));
>
> I think this is covered by
>
> +The keyword @code{__lengthof__} determines the length of an array operand,
> +that is, the number of elements in the array.
>
> > or a flexible array member?
>
> A flexible array member is an incomplete type, and so it is a constraint
> violation. It results in a compile-time error.
>
> I think this is covered by
>
> +The operand must be a complete array type.
>
> > Should these be clarified in the documentation part?
>
> I don't know. I think it's already documented. I prefer keeping it
> concise, as long as it's not ambiguous.
>
> > > +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.
> >
> > Can you add small examples to clarify the above?
>
> The examples would be rather confusing.
Sorry, I wanted to have removed the line above, after I came up with the
example below. :)
>
> __lengthof__(int [4][n]); // constant expression
> __lengthof__(int [n][4]); // run-time value
>
> I think these would be interesting in the docs. I'll check what would
> be the appropriate formatting for these. Thanks!
>
> > > +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.
> >
> > For incomplete array (for example, flexible array members), as I
> > mentioned in another email:
> > https://gcc.gnu.org/pipermail/gcc-patches/2024-August/659478.html
> >
> > I think that it’s better to wait the Length information is finally
> > integrated into TYPE.
>
> Yes, I agree for a start. But I also don't want to allow any user to
> rely on the fact that __lengthof__ rejects pointers to determine that
> something is not a pointer, because we reserve the possibility of
> extending the operator to work on certain pointers. (I'm not saying
> we'll do it; but we reserve the right.)
>
> Maybe we can just trust that nobody will do that, and complain if we see
> anyone using it in that way.
>
> I think I'll just remove that paragraph.
>
> Have a lovely night!
> Alex
>
> >
> > thanks.
> >
> > Qing
>
> --
> <https://www.alejandro-colomar.es/>
--
<https://www.alejandro-colomar.es/>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [RFC v4 0/4] c: Add __lengthof__ operator
2024-08-06 20:22 ` Alejandro Colomar
@ 2024-08-06 20:50 ` Joseph Myers
2024-08-06 21:09 ` Alejandro Colomar
0 siblings, 1 reply; 248+ messages in thread
From: Joseph Myers @ 2024-08-06 20:50 UTC (permalink / raw)
To: Alejandro Colomar
Cc: gcc-patches, Martin Uecker, Xavier Del Campo Romero,
Gabriel Ravier, Jakub Jelinek, Kees Cook, Qing Zhao,
Jens Gustedt
On Tue, 6 Aug 2024, Alejandro Colomar wrote:
> > Next question for the specification, implementation and tests: how does
> > this feature interact with the rules on external definitions (the contexts
> > in which it's OK to refer to an identifier with internal or external
> > linkage that's never defined - for example, a function, static or extern,
> > with a declaration but no definition; see 6.9.1)?
>
> Functions are not array types, so they don't apply. It's a constraint
> violation --mandatory error-- to call __lengthof__(func).
>
> VLAs cannot have static storage duration or file scope. Any array that
> has static storage duration or extern linkage must be a normal array.
> Since normal arrays operands are not evaluated, __lengthof__ returns a
> constant expression, and there's no issue at all.
>
> I can't think of any case where we'd have problems; do you have any
> other example?
static int f(), f2();
int a[10][10];
int x;
void
g()
{
__lengthof__ (a[f()]); // Should be valid that f is not defined.
int b[x][x];
__lengthof__ (b[f2()]); // Should be invalid that f2 is not defined.
}
--
Joseph S. Myers
josmyers@redhat.com
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [RFC v4 0/4] c: Add __lengthof__ operator
2024-08-06 20:50 ` Joseph Myers
@ 2024-08-06 21:09 ` Alejandro Colomar
0 siblings, 0 replies; 248+ messages in thread
From: Alejandro Colomar @ 2024-08-06 21:09 UTC (permalink / raw)
To: Joseph Myers
Cc: gcc-patches, Martin Uecker, Xavier Del Campo Romero,
Gabriel Ravier, Jakub Jelinek, Kees Cook, Qing Zhao,
Jens Gustedt
[-- Attachment #1: Type: text/plain, Size: 959 bytes --]
Hi Joseph,
On Tue, Aug 06, 2024 at 08:50:19PM GMT, Joseph Myers wrote:
> static int f(), f2();
> int a[10][10];
> int x;
>
> void
> g()
> {
> __lengthof__ (a[f()]); // Should be valid that f is not defined.
> int b[x][x];
> __lengthof__ (b[f2()]); // Should be invalid that f2 is not defined.
> }
Thanks! That makes sense. It works as you expect, I think.
alx@debian:~/tmp/gcc$ cat ext.c
static int f(), f2();
int a[10][10];
int x;
int
main(void)
{
int b[x][x];
__lengthof__(a[f()]);
__lengthof__(b[f2()]);
}
alx@debian:~/tmp/gcc$ /opt/local/gnu/gcc/lengthof/bin/gcc ext.c
ext.c:1:17: warning: ‘f2’ used but never defined
1 | static int f(), f2();
| ^~
/usr/bin/ld: /tmp/ccqlTYWo.o: in function `main':
ext.c:(.text+0xe0): undefined reference to `f2'
collect2: error: ld returned 1 exit status
Cheers,
Alex
--
<https://www.alejandro-colomar.es/>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [RFC v4 0/4] c: Add __lengthof__ operator
2024-08-06 14:43 ` Martin Uecker
2024-08-06 15:40 ` Alejandro Colomar
@ 2024-08-06 21:46 ` Alejandro Colomar
1 sibling, 0 replies; 248+ messages in thread
From: Alejandro Colomar @ 2024-08-06 21:46 UTC (permalink / raw)
To: Martin Uecker
Cc: gcc-patches, Xavier Del Campo Romero, Gabriel Ravier,
Joseph Myers, Jakub Jelinek, Kees Cook, Qing Zhao, Jens Gustedt
[-- Attachment #1: Type: text/plain, Size: 5696 bytes --]
Hi Martin,
On Tue, Aug 06, 2024 at 04:43:27PM GMT, Martin Uecker wrote:
> There are also *.sum files which you can diff against a build
> without your patch to see whether there are any regressions.
In my working copy, it all looks good. Thanks! I'll mention that in v5.
Have a lovely night!
Alex
alx@debian:~/src/gnu/gcc$ find len0 -type f
len0/host-x86_64-pc-linux-gnu/gcc/testsuite/gcc/gcc.sum
len0/host-x86_64-pc-linux-gnu/gcc/testsuite/gfortran/gfortran.sum
len0/host-x86_64-pc-linux-gnu/gcc/testsuite/objc/objc.sum
len0/host-x86_64-pc-linux-gnu/gcc/testsuite/g++/g++.sum
len0/x86_64-pc-linux-gnu/libitm/testsuite/libitm.sum
len0/x86_64-pc-linux-gnu/libgomp/testsuite/libgomp.sum
len0/x86_64-pc-linux-gnu/libatomic/testsuite/libatomic.sum
len0/x86_64-pc-linux-gnu/libstdc++-v3/testsuite/libstdc++.sum
alx@debian:~/src/gnu/gcc$ find len1 -type f
len1/host-x86_64-pc-linux-gnu/gcc/testsuite/gcc/gcc.sum
len1/host-x86_64-pc-linux-gnu/gcc/testsuite/gfortran/gfortran.sum
len1/host-x86_64-pc-linux-gnu/gcc/testsuite/objc/objc.sum
len1/host-x86_64-pc-linux-gnu/gcc/testsuite/g++/g++.sum
len1/x86_64-pc-linux-gnu/libitm/testsuite/libitm.sum
len1/x86_64-pc-linux-gnu/libgomp/testsuite/libgomp.sum
len1/x86_64-pc-linux-gnu/libatomic/testsuite/libatomic.sum
len1/x86_64-pc-linux-gnu/libstdc++-v3/testsuite/libstdc++.sum
alx@debian:~/src/gnu/gcc$ cat <(cd len0; find -type f) \
| while read f; do
diff -u "len0/$f" "len1/$f";
done;
--- len0/./host-x86_64-pc-linux-gnu/gcc/testsuite/gcc/gcc.sum 2024-08-06 22:22:44.514175252 +0200
+++ len1/./host-x86_64-pc-linux-gnu/gcc/testsuite/gcc/gcc.sum 2024-08-06 23:29:53.693730123 +0200
@@ -1,4 +1,4 @@
-Test run by alx on Tue Aug 6 19:28:53 2024
+Test run by alx on Tue Aug 6 22:49:12 2024
Native configuration is x86_64-pc-linux-gnu
=== gcc tests ===
@@ -86504,6 +86504,15 @@
PASS: gcc.dg/large-size-array.c (test for errors, line 19)
PASS: gcc.dg/large-size-array.c (test for excess errors)
UNSUPPORTED: gcc.dg/lazy-ptr-test.c
+PASS: gcc.dg/lengthof-compile.c (test for errors, line 11)
+PASS: gcc.dg/lengthof-compile.c (test for errors, line 15)
+PASS: gcc.dg/lengthof-compile.c (test for errors, line 27)
+PASS: gcc.dg/lengthof-compile.c (test for errors, line 42)
+PASS: gcc.dg/lengthof-compile.c (test for errors, line 45)
+PASS: gcc.dg/lengthof-compile.c (test for errors, line 48)
+PASS: gcc.dg/lengthof-compile.c (test for excess errors)
+PASS: gcc.dg/lengthof.c (test for excess errors)
+PASS: gcc.dg/lengthof.c execution test
PASS: gcc.dg/limits-width-1.c (test for excess errors)
PASS: gcc.dg/limits-width-2.c (test for excess errors)
PASS: gcc.dg/live-patching-1.c (test for excess errors)
@@ -204639,7 +204648,7 @@
=== gcc Summary ===
-# of expected passes 199780
+# of expected passes 199789
# of unexpected failures 31
# of unexpected successes 2
# of expected failures 1463
--- len0/./host-x86_64-pc-linux-gnu/gcc/testsuite/gfortran/gfortran.sum 2024-08-06 22:22:44.546175561 +0200
+++ len1/./host-x86_64-pc-linux-gnu/gcc/testsuite/gfortran/gfortran.sum 2024-08-06 23:29:53.877731933 +0200
@@ -1,4 +1,4 @@
-Test run by alx on Tue Aug 6 19:28:53 2024
+Test run by alx on Tue Aug 6 22:49:12 2024
Native configuration is x86_64-pc-linux-gnu
=== gfortran tests ===
--- len0/./host-x86_64-pc-linux-gnu/gcc/testsuite/objc/objc.sum 2024-08-06 22:22:44.462174752 +0200
+++ len1/./host-x86_64-pc-linux-gnu/gcc/testsuite/objc/objc.sum 2024-08-06 23:29:53.845731618 +0200
@@ -1,4 +1,4 @@
-Test run by alx on Tue Aug 6 19:28:53 2024
+Test run by alx on Tue Aug 6 22:49:12 2024
Native configuration is x86_64-pc-linux-gnu
=== objc tests ===
--- len0/./host-x86_64-pc-linux-gnu/gcc/testsuite/g++/g++.sum 2024-08-06 22:22:44.622176292 +0200
+++ len1/./host-x86_64-pc-linux-gnu/gcc/testsuite/g++/g++.sum 2024-08-06 23:29:53.781730989 +0200
@@ -1,4 +1,4 @@
-Test run by alx on Tue Aug 6 19:28:53 2024
+Test run by alx on Tue Aug 6 22:49:12 2024
Native configuration is x86_64-pc-linux-gnu
=== g++ tests ===
--- len0/./x86_64-pc-linux-gnu/libitm/testsuite/libitm.sum 2024-08-06 22:22:46.206191541 +0200
+++ len1/./x86_64-pc-linux-gnu/libitm/testsuite/libitm.sum 2024-08-06 23:29:55.573748613 +0200
@@ -1,4 +1,4 @@
-Test run by alx on Tue Aug 6 19:28:53 2024
+Test run by alx on Tue Aug 6 22:49:12 2024
Native configuration is x86_64-pc-linux-gnu
=== libitm tests ===
--- len0/./x86_64-pc-linux-gnu/libgomp/testsuite/libgomp.sum 2024-08-06 22:22:45.694186612 +0200
+++ len1/./x86_64-pc-linux-gnu/libgomp/testsuite/libgomp.sum 2024-08-06 23:29:54.717740194 +0200
@@ -1,4 +1,4 @@
-Test run by alx on Tue Aug 6 19:28:53 2024
+Test run by alx on Tue Aug 6 22:49:12 2024
Native configuration is x86_64-pc-linux-gnu
=== libgomp tests ===
--- len0/./x86_64-pc-linux-gnu/libatomic/testsuite/libatomic.sum 2024-08-06 22:22:46.110190617 +0200
+++ len1/./x86_64-pc-linux-gnu/libatomic/testsuite/libatomic.sum 2024-08-06 23:29:55.393746843 +0200
@@ -1,4 +1,4 @@
-Test run by alx on Tue Aug 6 19:28:53 2024
+Test run by alx on Tue Aug 6 22:49:12 2024
Native configuration is x86_64-pc-linux-gnu
=== libatomic tests ===
--- len0/./x86_64-pc-linux-gnu/libstdc++-v3/testsuite/libstdc++.sum 2024-08-06 22:22:45.998189539 +0200
+++ len1/./x86_64-pc-linux-gnu/libstdc++-v3/testsuite/libstdc++.sum 2024-08-06 23:29:55.137744325 +0200
@@ -1,4 +1,4 @@
-Test run by alx on Tue Aug 6 19:28:54 2024
+Test run by alx on Tue Aug 6 22:49:13 2024
Native configuration is x86_64-pc-linux-gnu
=== libstdc++ tests ===
--
<https://www.alejandro-colomar.es/>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 248+ messages in thread
* [PATCH v5 0/3] c: Add __lengthof__ operator
2024-07-28 14:15 ` [RFC v1 0/2] c: Add _Lengthof operator Alejandro Colomar
` (6 preceding siblings ...)
2024-08-06 12:22 ` [RFC v4 0/4] c: Add __lengthof__ operator Alejandro Colomar
@ 2024-08-06 23:11 ` Alejandro Colomar
2024-08-06 23:12 ` [PATCH v5 1/3] gcc/: Rename array_type_nelts() => array_type_nelts_minus_one() Alejandro Colomar
` (4 more replies)
2024-08-09 13:58 ` [PATCH v6 0/3] c: Add __lengthof__ operator Alejandro Colomar
` (14 subsequent siblings)
22 siblings, 5 replies; 248+ messages in thread
From: Alejandro Colomar @ 2024-08-06 23:11 UTC (permalink / raw)
To: gcc-patches
Cc: Alejandro Colomar, Martin Uecker, Xavier Del Campo Romero,
Joseph Myers, Gabriel Ravier, Jakub Jelinek, Kees Cook,
Qing Zhao, Jens Gustedt, David Brown, Florian Weimer,
Andreas Schwab
[-- Attachment #1: Type: text/plain, Size: 19766 bytes --]
Hi!
This is ready for review.
v5:
- Add changelog entries.
- Wording fixes in commit messages.
- s/sizeof/lengthof/ in comment.
- CC += David, Florian, Andreas [Qing]
- Docs: Remove some details about future directions. [Qing]
- Docs: Add examples. [Qing]
- Docs: Clarify when __lengthof__ evaluates as a constant expression
and when it evaluates as a run-time value. [Joseph, Qing]
- Tests: Use several -Wno-* flags to turn off unwanted warnings.
[Martin, Joseph]
- Tests: Merge into the same commit that adds the feature.
- Tests: Fix style (whitespace).
I won't paste the example program I used for development, since it's the
same as in v4. Check that cover letter if necessary.
When reviewing, mind that some parts of the code have been blindly
pasted from sizeof, and might not make much sense; I didn't fully
understand some parts. However, it seems to behave well, and more or
less it makes sense. Just be careful about it.
At the bottom of this message is the range-diff against v4.
Have a lovely night!
Alex
BTW, I've tested that there are no regressions:
alx@debian:~/src/gnu/gcc$ find len0 -type f
len0/host-x86_64-pc-linux-gnu/gcc/testsuite/gcc/gcc.sum
len0/host-x86_64-pc-linux-gnu/gcc/testsuite/gfortran/gfortran.sum
len0/host-x86_64-pc-linux-gnu/gcc/testsuite/objc/objc.sum
len0/host-x86_64-pc-linux-gnu/gcc/testsuite/g++/g++.sum
len0/x86_64-pc-linux-gnu/libitm/testsuite/libitm.sum
len0/x86_64-pc-linux-gnu/libgomp/testsuite/libgomp.sum
len0/x86_64-pc-linux-gnu/libatomic/testsuite/libatomic.sum
len0/x86_64-pc-linux-gnu/libstdc++-v3/testsuite/libstdc++.sum
alx@debian:~/src/gnu/gcc$ find len1 -type f
len1/host-x86_64-pc-linux-gnu/gcc/testsuite/gcc/gcc.sum
len1/host-x86_64-pc-linux-gnu/gcc/testsuite/gfortran/gfortran.sum
len1/host-x86_64-pc-linux-gnu/gcc/testsuite/objc/objc.sum
len1/host-x86_64-pc-linux-gnu/gcc/testsuite/g++/g++.sum
len1/x86_64-pc-linux-gnu/libitm/testsuite/libitm.sum
len1/x86_64-pc-linux-gnu/libgomp/testsuite/libgomp.sum
len1/x86_64-pc-linux-gnu/libatomic/testsuite/libatomic.sum
len1/x86_64-pc-linux-gnu/libstdc++-v3/testsuite/libstdc++.sum
alx@debian:~/src/gnu/gcc$ cat <(cd len0; find -type f) \
| while read f; do
diff -u "len0/$f" "len1/$f";
done;
--- len0/./host-x86_64-pc-linux-gnu/gcc/testsuite/gcc/gcc.sum 2024-08-06
+22:22:44.514175252 +0200
+++ len1/./host-x86_64-pc-linux-gnu/gcc/testsuite/gcc/gcc.sum 2024-08-06
+23:29:53.693730123 +0200
@@ -1,4 +1,4 @@
-Test run by alx on Tue Aug 6 19:28:53 2024
+Test run by alx on Tue Aug 6 22:49:12 2024
Native configuration is x86_64-pc-linux-gnu
=== gcc tests ===
@@ -86504,6 +86504,15 @@
PASS: gcc.dg/large-size-array.c (test for errors, line 19)
PASS: gcc.dg/large-size-array.c (test for excess errors)
UNSUPPORTED: gcc.dg/lazy-ptr-test.c
+PASS: gcc.dg/lengthof-compile.c (test for errors, line 11)
+PASS: gcc.dg/lengthof-compile.c (test for errors, line 15)
+PASS: gcc.dg/lengthof-compile.c (test for errors, line 27)
+PASS: gcc.dg/lengthof-compile.c (test for errors, line 42)
+PASS: gcc.dg/lengthof-compile.c (test for errors, line 45)
+PASS: gcc.dg/lengthof-compile.c (test for errors, line 48)
+PASS: gcc.dg/lengthof-compile.c (test for excess errors)
+PASS: gcc.dg/lengthof.c (test for excess errors)
+PASS: gcc.dg/lengthof.c execution test
PASS: gcc.dg/limits-width-1.c (test for excess errors)
PASS: gcc.dg/limits-width-2.c (test for excess errors)
PASS: gcc.dg/live-patching-1.c (test for excess errors)
@@ -204639,7 +204648,7 @@
=== gcc Summary ===
-# of expected passes 199780
+# of expected passes 199789
# of unexpected failures 31
# of unexpected successes 2
# of expected failures 1463
--- len0/./host-x86_64-pc-linux-gnu/gcc/testsuite/gfortran/gfortran.sum 2024-08-06
+22:22:44.546175561 +0200
+++ len1/./host-x86_64-pc-linux-gnu/gcc/testsuite/gfortran/gfortran.sum 2024-08-06
+23:29:53.877731933 +0200
@@ -1,4 +1,4 @@
-Test run by alx on Tue Aug 6 19:28:53 2024
+Test run by alx on Tue Aug 6 22:49:12 2024
Native configuration is x86_64-pc-linux-gnu
=== gfortran tests ===
--- len0/./host-x86_64-pc-linux-gnu/gcc/testsuite/objc/objc.sum 2024-08-06
+22:22:44.462174752 +0200
+++ len1/./host-x86_64-pc-linux-gnu/gcc/testsuite/objc/objc.sum 2024-08-06
+23:29:53.845731618 +0200
@@ -1,4 +1,4 @@
-Test run by alx on Tue Aug 6 19:28:53 2024
+Test run by alx on Tue Aug 6 22:49:12 2024
Native configuration is x86_64-pc-linux-gnu
=== objc tests ===
--- len0/./host-x86_64-pc-linux-gnu/gcc/testsuite/g++/g++.sum 2024-08-06
+22:22:44.622176292 +0200
+++ len1/./host-x86_64-pc-linux-gnu/gcc/testsuite/g++/g++.sum 2024-08-06
+23:29:53.781730989 +0200
@@ -1,4 +1,4 @@
-Test run by alx on Tue Aug 6 19:28:53 2024
+Test run by alx on Tue Aug 6 22:49:12 2024
Native configuration is x86_64-pc-linux-gnu
=== g++ tests ===
--- len0/./x86_64-pc-linux-gnu/libitm/testsuite/libitm.sum 2024-08-06
+22:22:46.206191541 +0200
+++ len1/./x86_64-pc-linux-gnu/libitm/testsuite/libitm.sum 2024-08-06
+23:29:55.573748613 +0200
@@ -1,4 +1,4 @@
-Test run by alx on Tue Aug 6 19:28:53 2024
+Test run by alx on Tue Aug 6 22:49:12 2024
Native configuration is x86_64-pc-linux-gnu
=== libitm tests ===
--- len0/./x86_64-pc-linux-gnu/libgomp/testsuite/libgomp.sum 2024-08-06
+22:22:45.694186612 +0200
+++ len1/./x86_64-pc-linux-gnu/libgomp/testsuite/libgomp.sum 2024-08-06
+23:29:54.717740194 +0200
@@ -1,4 +1,4 @@
-Test run by alx on Tue Aug 6 19:28:53 2024
+Test run by alx on Tue Aug 6 22:49:12 2024
Native configuration is x86_64-pc-linux-gnu
=== libgomp tests ===
--- len0/./x86_64-pc-linux-gnu/libatomic/testsuite/libatomic.sum 2024-08-06
+22:22:46.110190617 +0200
+++ len1/./x86_64-pc-linux-gnu/libatomic/testsuite/libatomic.sum 2024-08-06
+23:29:55.393746843 +0200
@@ -1,4 +1,4 @@
-Test run by alx on Tue Aug 6 19:28:53 2024
+Test run by alx on Tue Aug 6 22:49:12 2024
Native configuration is x86_64-pc-linux-gnu
=== libatomic tests ===
--- len0/./x86_64-pc-linux-gnu/libstdc++-v3/testsuite/libstdc++.sum 2024-08-06
+22:22:45.998189539 +0200
+++ len1/./x86_64-pc-linux-gnu/libstdc++-v3/testsuite/libstdc++.sum 2024-08-06
+23:29:55.137744325 +0200
@@ -1,4 +1,4 @@
-Test run by alx on Tue Aug 6 19:28:54 2024
+Test run by alx on Tue Aug 6 22:49:13 2024
Native configuration is x86_64-pc-linux-gnu
=== libstdc++ tests ===
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 | 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 | 23 +++++
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 | 49 +++++++++
gcc/testsuite/gcc.dg/lengthof.c | 127 ++++++++++++++++++++++++
gcc/tree.cc | 17 +++-
gcc/tree.h | 3 +-
27 files changed, 451 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 v4:
1: 73010cb4af6 = 1: 73010cb4af6 gcc/: Rename array_type_nelts() => array_type_nelts_minus_one()
2: 2bb966a0a89 ! 2: 9b835478721 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__, which will be added in the following commit.
+
+ gcc/ChangeLog:
+
+ * tree.h (array_type_nelts_top):
+ * tree.cc (array_type_nelts_top): Define function (moved from
+ gcc/cp/).
+
+ gcc/cp/ChangeLog:
+
+ * cp-tree.h (array_type_nelts_top):
+ * tree.cc (array_type_nelts_top): Remove function (move
+ to gcc/).
+
+ gcc/rust/ChangeLog:
+
+ * backend/rust-tree.h (array_type_nelts_top):
+ * backend/rust-tree.cc (array_type_nelts_top): Remove function.
Signed-off-by: Alejandro Colomar <alx@kernel.org>
3: e2dbfc43b14 ! 3: af05d01e68d c: Add __lengthof__() operator (n2529)
@@ Metadata
Author: Alejandro Colomar <alx@kernel.org>
## Commit message ##
- c: Add __lengthof__() operator (n2529)
+ c: Add __lengthof__ operator
- This operator is similar to sizeof() but can only be applied to an
- array, and returns its length (number of elements).
+ This operator is similar to sizeof but can only be applied to an array,
+ and returns its length (number of elements).
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 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.
- Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2529.pdf>
- Link: <https://inbox.sourceware.org/gcc/M8S4oQy--3-2@tutanota.com/T/>
- Suggested-by: Xavier Del Campo Romero <xavi.dcr@tutanota.com>
- Co-developed-by: Martin Uecker <uecker@tugraz.at>
- Cc: Gabriel Ravier <gabravier@gmail.com>
Cc: Joseph Myers <josmyers@redhat.com>
+ Cc: Gabriel Ravier <gabravier@gmail.com>
Cc: Jakub Jelinek <jakub@redhat.com>
Cc: Kees Cook <keescook@chromium.org>
Cc: Qing Zhao <qing.zhao@oracle.com>
Cc: Jens Gustedt <jens.gustedt@inria.fr>
+ Cc: David Brown <david.brown@hesbynett.no>
+ Cc: Florian Weimer <fweimer@redhat.com>
+ Cc: Andreas Schwab <schwab@linux-m68k.org>
+
+ gcc/ChangeLog:
+
+ * doc/extend.texi: Document __lengthof__ operator.
+ * target.h (enum type_context_kind): Add __lengthof__ operator.
+
+ gcc/c-family/ChangeLog:
+
+ * c-common.h:
+ * c-common.def:
+ * c-common.cc (c_lengthof_type): Add __lengthof__ operator.
+
+ gcc/c/ChangeLog:
+
+ * c-tree.h
+ (c_expr_lengthof_expr, c_expr_lengthof_type):
+ * c-decl.cc
+ (start_struct, finish_struct):
+ (start_enum, finish_enum):
+ * c-parser.cc
+ (c_parser_sizeof_expression):
+ (c_parser_lengthof_expression):
+ (c_parser_sizeof_or_lengthof_expression):
+ (c_parser_unary_expression):
+ * c-typeck.cc
+ (build_external_ref):
+ (record_maybe_used_decl, pop_maybe_used):
+ (is_top_array_vla):
+ (c_expr_lengthof_expr, c_expr_lengthof_type):
+ Add __lengthof__operator.
+
+ gcc/cp/ChangeLog:
+
+ * operators.def: Add __lengthof__ operator.
+
+ gcc/testsuite/ChangeLog:
+
+ * gcc.dg/lengthof-compile.c:
+ * gcc.dg/lengthof.c: Add tests for __lengthof__ operator.
+
+ Link: https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2529.pdf
+ Link: https://inbox.sourceware.org/gcc/M8S4oQy--3-2@tutanota.com/T/
+ Suggested-by: Xavier Del Campo Romero <xavi.dcr@tutanota.com>
+ Co-developed-by: Martin Uecker <uecker@tugraz.at>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
## gcc/c-family/c-common.cc ##
@@ gcc/c/c-typeck.cc: int in_alignof;
/* The level of nesting inside "sizeof". */
int in_sizeof;
-+/* The level of nesting inside "sizeof". */
++/* The level of nesting inside "lengthof". */
+int in_lengthof;
+
/* The level of nesting inside "typeof". */
@@ gcc/doc/extend.texi: If the operand of the @code{__alignof__} expression is a fu
+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;
++if the top-level length designator is an integer constant expression
++(in this case, the operator results in a constant expression);
+and it is evaluated
-+if the top-level length designator is not an integer constant expression.
++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:
+
-+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.
++@smallexample
++__lengthof__ (int [7][n++]); // constexpr
++__lengthof__ (int [n++][7]); // run-time value
++@end smallexample
+
@node Inline
@section An Inline Function is As Fast As a Macro
@@ gcc/target.h: enum type_context_kind {
/* Creating objects of type T with static storage duration. */
TCTX_STATIC_STORAGE,
+
+ ## gcc/testsuite/gcc.dg/lengthof-compile.c (new) ##
+@@
++/* { dg-do compile } */
++/* { dg-options "-Wno-declaration-after-statement -Wno-pedantic -Wno-vla" } */
++
++extern int x[];
++
++void
++incomplete (int p[])
++{
++ unsigned n;
++
++ n = __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" } */
++}
++
++void
++fam (void)
++{
++ struct {
++ int x;
++ int fam[];
++ } s;
++ unsigned n;
++
++ n = __lengthof__ (s.fam); /* { dg-error "incomplete" } */
++}
++
++void fix_fix (int i, char (*a)[3][5], int (*x)[__lengthof__ (*a)]);
++void fix_var (int i, char (*a)[3][i], int (*x)[__lengthof__ (*a)]);
++void fix_uns (int i, char (*a)[3][*], int (*x)[__lengthof__ (*a)]);
++
++void
++func (void)
++{
++ int i3[3];
++ int i5[5];
++ char c35[3][5];
++
++ fix_fix (5, &c35, &i3);
++ fix_fix (5, &c35, &i5); /* { dg-error "incompatible-pointer-types" } */
++
++ fix_var (5, &c35, &i3);
++ fix_var (5, &c35, &i5); /* { dg-error "incompatible-pointer-types" } */
++
++ fix_uns (5, &c35, &i3);
++ fix_uns (5, &c35, &i5); /* { dg-error "incompatible-pointer-types" } */
++}
+
+ ## gcc/testsuite/gcc.dg/lengthof.c (new) ##
+@@
++/* { dg-do run } */
++/* { dg-options "-Wno-declaration-after-statement -Wno-pedantic -Wno-vla" } */
++
++#undef NDEBUG
++#include <assert.h>
++
++void
++array (void)
++{
++ short a[7];
++
++ assert (__lengthof__ (a) == 7);
++ assert (__lengthof__ (long [0]) == 0);
++ assert (__lengthof__ (unsigned [99]) == 99);
++}
++
++void
++vla (void)
++{
++ unsigned n;
++
++ n = 99;
++ assert (__lengthof__ (short [n - 10]) == 99 - 10);
++
++ int v[n / 2];
++ assert (__lengthof__ (v) == 99 / 2);
++
++ n = 0;
++ int z[n];
++ assert (__lengthof__ (z) == 0);
++}
++
++void
++member (void)
++{
++ struct {
++ int a[8];
++ } s;
++
++ assert (__lengthof__ (s.a) == 8);
++}
++
++void
++vla_eval (void)
++{
++ int i;
++
++ i = 7;
++ assert (__lengthof__ (struct {int x;}[i++]) == 7);
++ assert (i == 7 + 1);
++
++ int v[i];
++ int (*p)[i];
++ p = &v;
++ assert (__lengthof__ (*p++) == i);
++ assert (p - 1 == &v);
++}
++
++void
++inner_vla_noeval (void)
++{
++ int i;
++
++ i = 3;
++ assert (__lengthof__ (struct {int x[i++];}[3]) == 3);
++ assert (i == 3);
++}
++
++void
++array_noeval (void)
++{
++ long a[5];
++ long (*p)[__lengthof__ (a)];
++
++ p = &a;
++ assert (__lengthof__ (*p++) == 5);
++ assert (p == &a);
++}
++
++void
++matrix_zero (void)
++{
++ int i;
++
++ assert (__lengthof__ (int [0][4]) == 0);
++ i = 3;
++ assert (__lengthof__ (int [0][i]) == 0);
++}
++
++void
++matrix_fixed (void)
++{
++ int i;
++
++ assert (__lengthof__ (int [7][4]) == 7);
++ i = 3;
++ assert (__lengthof__ (int [7][i]) == 7);
++}
++
++void
++matrix_vla (void)
++{
++ int i, j;
++
++ i = 7;
++ assert (__lengthof__ (int [i++][4]) == 7);
++ assert (i == 7 + 1);
++
++ i = 9;
++ j = 3;
++ assert (__lengthof__ (int [i++][j]) == 9);
++ assert (i == 9 + 1);
++}
++
++int
++main (void)
++{
++ array ();
++ vla ();
++ member ();
++ vla_eval ();
++ inner_vla_noeval ();
++ array_noeval ();
++ matrix_zero ();
++ matrix_fixed ();
++ matrix_vla ();
++}
4: 9a691f7f208 < -: ----------- testsuite: Add tests for __lengthof__
--
2.45.2
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 248+ messages in thread
* [PATCH v5 1/3] gcc/: Rename array_type_nelts() => array_type_nelts_minus_one()
2024-08-06 23:11 ` [PATCH v5 0/3] " Alejandro Colomar
@ 2024-08-06 23:12 ` Alejandro Colomar
2024-08-06 23:12 ` [PATCH v5 2/3] Merge definitions of array_type_nelts_top() Alejandro Colomar
` (3 subsequent siblings)
4 siblings, 0 replies; 248+ messages in thread
From: Alejandro Colomar @ 2024-08-06 23:12 UTC (permalink / raw)
To: gcc-patches
Cc: Alejandro Colomar, Martin Uecker, Xavier Del Campo Romero,
Joseph Myers, Gabriel Ravier, Jakub Jelinek, Kees Cook,
Qing Zhao, Jens Gustedt, David Brown, Florian Weimer,
Andreas Schwab, Richard Biener
[-- Attachment #1: Type: text/plain, Size: 12983 bytes --]
The old name was misleading.
While at it, also rename some temporary variables that are used with
this function, for consistency.
Link: https://inbox.sourceware.org/gcc-patches/9fffd80-dca-2c7e-14b-6c9b509a7215@redhat.com/T/#m2f661c67c8f7b2c405c8c7fc3152dd85dc729120
Cc: Gabriel Ravier <gabravier@gmail.com>
Cc: Martin Uecker <uecker@tugraz.at>
Cc: Joseph Myers <josmyers@redhat.com>
Cc: Xavier Del Campo Romero <xavi.dcr@tutanota.com>
Cc: Jakub Jelinek <jakub@redhat.com>
gcc/ChangeLog:
* tree.cc (array_type_nelts): Rename function ...
(array_type_nelts_minus_one): ... to this name. The old name
was misleading.
* tree.h (array_type_nelts): Rename function ...
(array_type_nelts_minus_one): ... to this name. The old name
was misleading.
* expr.cc (count_type_elements):
Rename array_type_nelts() => array_type_nelts_minus_one()
* config/aarch64/aarch64.cc
(pure_scalable_type_info::analyze_array): Likewise.
* config/i386/i386.cc (ix86_canonical_va_list_type): Likewise.
gcc/c/ChangeLog:
* c-decl.cc (one_element_array_type_p, get_parm_array_spec):
Rename array_type_nelts() => array_type_nelts_minus_one()
* c-fold.cc (c_fold_array_ref): Likewise.
gcc/cp/ChangeLog:
* decl.cc (reshape_init_array):
Rename array_type_nelts() => array_type_nelts_minus_one()
* init.cc (build_zero_init_1): Likewise.
(build_value_init_noctor): Likewise.
(build_vec_init): Likewise.
(build_delete): Likewise.
* lambda.cc (add_capture): Likewise.
* tree.cc (array_type_nelts_top): Likewise.
gcc/fortran/ChangeLog:
* trans-array.cc (structure_alloc_comps):
Rename array_type_nelts() => array_type_nelts_minus_one()
* trans-openmp.cc (gfc_walk_alloc_comps): Likewise.
(gfc_omp_clause_linear_ctor): Likewise.
gcc/rust/ChangeLog:
* backend/rust-tree.cc (array_type_nelts_top):
Rename array_type_nelts() => array_type_nelts_minus_one()
Suggested-by: Richard Biener <richard.guenther@gmail.com>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
---
gcc/c/c-decl.cc | 10 +++++-----
gcc/c/c-fold.cc | 7 ++++---
gcc/config/aarch64/aarch64.cc | 2 +-
gcc/config/i386/i386.cc | 2 +-
gcc/cp/decl.cc | 2 +-
gcc/cp/init.cc | 8 ++++----
gcc/cp/lambda.cc | 3 ++-
gcc/cp/tree.cc | 2 +-
gcc/expr.cc | 8 ++++----
gcc/fortran/trans-array.cc | 2 +-
gcc/fortran/trans-openmp.cc | 4 ++--
gcc/rust/backend/rust-tree.cc | 2 +-
gcc/tree.cc | 4 ++--
gcc/tree.h | 2 +-
14 files changed, 30 insertions(+), 28 deletions(-)
diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 97f1d346835..4dced430d1f 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -5309,7 +5309,7 @@ one_element_array_type_p (const_tree type)
{
if (TREE_CODE (type) != ARRAY_TYPE)
return false;
- return integer_zerop (array_type_nelts (type));
+ return integer_zerop (array_type_nelts_minus_one (type));
}
/* Determine whether TYPE is a zero-length array type "[0]". */
@@ -6257,15 +6257,15 @@ get_parm_array_spec (const struct c_parm *parm, tree attrs)
for (tree type = parm->specs->type; TREE_CODE (type) == ARRAY_TYPE;
type = TREE_TYPE (type))
{
- tree nelts = array_type_nelts (type);
- if (error_operand_p (nelts))
+ tree nelts_minus_one = array_type_nelts_minus_one (type);
+ if (error_operand_p (nelts_minus_one))
return attrs;
- if (TREE_CODE (nelts) != INTEGER_CST)
+ if (TREE_CODE (nelts_minus_one) != INTEGER_CST)
{
/* Each variable VLA bound is represented by the dollar
sign. */
spec += "$";
- tpbnds = tree_cons (NULL_TREE, nelts, tpbnds);
+ tpbnds = tree_cons (NULL_TREE, nelts_minus_one, tpbnds);
}
}
tpbnds = nreverse (tpbnds);
diff --git a/gcc/c/c-fold.cc b/gcc/c/c-fold.cc
index 57b67c74bd8..9ea174f79c4 100644
--- a/gcc/c/c-fold.cc
+++ b/gcc/c/c-fold.cc
@@ -73,11 +73,12 @@ c_fold_array_ref (tree type, tree ary, tree index)
unsigned elem_nchars = (TYPE_PRECISION (elem_type)
/ TYPE_PRECISION (char_type_node));
unsigned len = (unsigned) TREE_STRING_LENGTH (ary) / elem_nchars;
- tree nelts = array_type_nelts (TREE_TYPE (ary));
+ tree nelts_minus_one = array_type_nelts_minus_one (TREE_TYPE (ary));
bool dummy1 = true, dummy2 = true;
- nelts = c_fully_fold_internal (nelts, true, &dummy1, &dummy2, false, false);
+ nelts_minus_one = c_fully_fold_internal (nelts_minus_one, true, &dummy1,
+ &dummy2, false, false);
unsigned HOST_WIDE_INT i = tree_to_uhwi (index);
- if (!tree_int_cst_le (index, nelts)
+ if (!tree_int_cst_le (index, nelts_minus_one)
|| i >= len
|| i + elem_nchars > len)
return NULL_TREE;
diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
index 0d41a193ec1..eaef2a0e985 100644
--- a/gcc/config/aarch64/aarch64.cc
+++ b/gcc/config/aarch64/aarch64.cc
@@ -1082,7 +1082,7 @@ pure_scalable_type_info::analyze_array (const_tree type)
/* An array of unknown, flexible or variable length will be passed and
returned by reference whatever we do. */
- tree nelts_minus_one = array_type_nelts (type);
+ tree nelts_minus_one = array_type_nelts_minus_one (type);
if (!tree_fits_uhwi_p (nelts_minus_one))
return DOESNT_MATTER;
diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc
index 9c2ebe74fc9..298d8c9131a 100644
--- a/gcc/config/i386/i386.cc
+++ b/gcc/config/i386/i386.cc
@@ -24519,7 +24519,7 @@ ix86_canonical_va_list_type (tree type)
return ms_va_list_type_node;
if ((TREE_CODE (type) == ARRAY_TYPE
- && integer_zerop (array_type_nelts (type)))
+ && integer_zerop (array_type_nelts_minus_one (type)))
|| POINTER_TYPE_P (type))
{
tree elem_type = TREE_TYPE (type);
diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index e7bb4fa3089..fc3e28c4dec 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -6936,7 +6936,7 @@ reshape_init_array (tree type, reshape_iter *d, tree first_initializer_p,
gcc_assert (TREE_CODE (type) == ARRAY_TYPE);
if (TYPE_DOMAIN (type))
- max_index = array_type_nelts (type);
+ max_index = array_type_nelts_minus_one (type);
return reshape_init_array_1 (TREE_TYPE (type), max_index, d,
first_initializer_p, complain);
diff --git a/gcc/cp/init.cc b/gcc/cp/init.cc
index e9561c146d7..4558151b4c2 100644
--- a/gcc/cp/init.cc
+++ b/gcc/cp/init.cc
@@ -260,7 +260,7 @@ build_zero_init_1 (tree type, tree nelts, bool static_storage_p,
else if (TYPE_DOMAIN (type) == NULL_TREE)
return NULL_TREE;
else
- max_index = array_type_nelts (type);
+ max_index = array_type_nelts_minus_one (type);
/* If we have an error_mark here, we should just return error mark
as we don't know the size of the array yet. */
@@ -471,7 +471,7 @@ build_value_init_noctor (tree type, tsubst_flags_t complain)
vec<constructor_elt, va_gc> *v = NULL;
/* Iterate over the array elements, building initializations. */
- tree max_index = array_type_nelts (type);
+ tree max_index = array_type_nelts_minus_one (type);
/* If we have an error_mark here, we should just return error mark
as we don't know the size of the array yet. */
@@ -4516,7 +4516,7 @@ build_vec_init (tree base, tree maxindex, tree init,
: location_of (base));
if (TREE_CODE (atype) == ARRAY_TYPE && TYPE_DOMAIN (atype))
- maxindex = array_type_nelts (atype);
+ maxindex = array_type_nelts_minus_one (atype);
if (maxindex == NULL_TREE || maxindex == error_mark_node)
return error_mark_node;
@@ -5172,7 +5172,7 @@ build_delete (location_t loc, tree otype, tree addr,
error_at (loc, "unknown array size in delete");
return error_mark_node;
}
- return build_vec_delete (loc, addr, array_type_nelts (type),
+ return build_vec_delete (loc, addr, array_type_nelts_minus_one (type),
auto_delete, use_global_delete, complain);
}
diff --git a/gcc/cp/lambda.cc b/gcc/cp/lambda.cc
index 0770417810e..065113bc122 100644
--- a/gcc/cp/lambda.cc
+++ b/gcc/cp/lambda.cc
@@ -556,7 +556,8 @@ add_capture (tree lambda, tree id, tree orig_init, bool by_reference_p,
integer_zero_node, tf_warning_or_error);
initializer = build_constructor_va (init_list_type_node, 2,
NULL_TREE, build_address (elt),
- NULL_TREE, array_type_nelts (type));
+ NULL_TREE,
+ array_type_nelts_minus_one (type));
type = vla_capture_type (type);
}
else if (!dependent_type_p (type)
diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
index dfd4a3a948b..3baeb8fa252 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -3080,7 +3080,7 @@ array_type_nelts_top (tree type)
{
return fold_build2_loc (input_location,
PLUS_EXPR, sizetype,
- array_type_nelts (type),
+ array_type_nelts_minus_one (type),
size_one_node);
}
diff --git a/gcc/expr.cc b/gcc/expr.cc
index ffbac513692..cba8b365856 100644
--- a/gcc/expr.cc
+++ b/gcc/expr.cc
@@ -6970,14 +6970,14 @@ count_type_elements (const_tree type, bool for_ctor_p)
{
case ARRAY_TYPE:
{
- tree nelts;
+ tree nelts_minus_one;
- nelts = array_type_nelts (type);
- if (nelts && tree_fits_uhwi_p (nelts))
+ nelts_minus_one = array_type_nelts_minus_one (type);
+ if (nelts_minus_one && tree_fits_uhwi_p (nelts_minus_one))
{
unsigned HOST_WIDE_INT n;
- n = tree_to_uhwi (nelts) + 1;
+ n = tree_to_uhwi (nelts_minus_one) + 1;
if (n == 0 || for_ctor_p)
return n;
else
diff --git a/gcc/fortran/trans-array.cc b/gcc/fortran/trans-array.cc
index 140d933e45d..b7927bcdf01 100644
--- a/gcc/fortran/trans-array.cc
+++ b/gcc/fortran/trans-array.cc
@@ -9572,7 +9572,7 @@ structure_alloc_comps (gfc_symbol * der_type, tree decl, tree dest,
else
{
/* Otherwise use the TYPE_DOMAIN information. */
- tmp = array_type_nelts (decl_type);
+ tmp = array_type_nelts_minus_one (decl_type);
tmp = fold_convert (gfc_array_index_type, tmp);
}
diff --git a/gcc/fortran/trans-openmp.cc b/gcc/fortran/trans-openmp.cc
index df1bf144e23..14cd2f9fad7 100644
--- a/gcc/fortran/trans-openmp.cc
+++ b/gcc/fortran/trans-openmp.cc
@@ -582,7 +582,7 @@ gfc_walk_alloc_comps (tree decl, tree dest, tree var,
tem = size_binop (MINUS_EXPR, tem, size_one_node);
}
else
- tem = array_type_nelts (type);
+ tem = array_type_nelts_minus_one (type);
tem = fold_convert (gfc_array_index_type, tem);
}
@@ -1309,7 +1309,7 @@ gfc_omp_clause_linear_ctor (tree clause, tree dest, tree src, tree add)
nelems = size_binop (MINUS_EXPR, nelems, size_one_node);
}
else
- nelems = array_type_nelts (type);
+ nelems = array_type_nelts_minus_one (type);
nelems = fold_convert (gfc_array_index_type, nelems);
gfc_omp_linear_clause_add_loop (&block, dest, src, add, nelems);
diff --git a/gcc/rust/backend/rust-tree.cc b/gcc/rust/backend/rust-tree.cc
index 2a5ffcbf895..a2c12204667 100644
--- a/gcc/rust/backend/rust-tree.cc
+++ b/gcc/rust/backend/rust-tree.cc
@@ -869,7 +869,7 @@ tree
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
diff --git a/gcc/tree.cc b/gcc/tree.cc
index 2d2d5b6db6e..dcaccc4c362 100644
--- a/gcc/tree.cc
+++ b/gcc/tree.cc
@@ -3698,7 +3698,7 @@ int_byte_position (const_tree field)
ARRAY_TYPE) minus one. This counts only elements of the top array. */
tree
-array_type_nelts (const_tree type)
+array_type_nelts_minus_one (const_tree type)
{
tree index_type, min, max;
@@ -14797,7 +14797,7 @@ is_empty_type (const_tree type)
return true;
}
else if (TREE_CODE (type) == ARRAY_TYPE)
- return (integer_minus_onep (array_type_nelts (type))
+ return (integer_minus_onep (array_type_nelts_minus_one (type))
|| TYPE_DOMAIN (type) == NULL_TREE
|| is_empty_type (TREE_TYPE (type)));
return false;
diff --git a/gcc/tree.h b/gcc/tree.h
index 28e8e71b036..fdddbcf408e 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -4921,7 +4921,7 @@ extern tree build_method_type_directly (tree, tree, tree);
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 value_member (tree, tree);
extern tree purpose_member (const_tree, tree);
--
2.45.2
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 248+ messages in thread
* [PATCH v5 2/3] Merge definitions of array_type_nelts_top()
2024-08-06 23:11 ` [PATCH v5 0/3] " Alejandro Colomar
2024-08-06 23:12 ` [PATCH v5 1/3] gcc/: Rename array_type_nelts() => array_type_nelts_minus_one() Alejandro Colomar
@ 2024-08-06 23:12 ` Alejandro Colomar
2024-08-06 23:12 ` [PATCH v5 3/3] c: Add __lengthof__ operator Alejandro Colomar
` (2 subsequent siblings)
4 siblings, 0 replies; 248+ messages in thread
From: Alejandro Colomar @ 2024-08-06 23:12 UTC (permalink / raw)
To: gcc-patches
Cc: Alejandro Colomar, Martin Uecker, Xavier Del Campo Romero,
Joseph Myers, Gabriel Ravier, Jakub Jelinek, Kees Cook,
Qing Zhao, Jens Gustedt, David Brown, Florian Weimer,
Andreas Schwab
[-- Attachment #1: Type: text/plain, Size: 4875 bytes --]
There were two identical definitions, and none of them are available
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__, which will be added in the following commit.
gcc/ChangeLog:
* tree.h (array_type_nelts_top):
* tree.cc (array_type_nelts_top): Define function (moved from
gcc/cp/).
gcc/cp/ChangeLog:
* cp-tree.h (array_type_nelts_top):
* tree.cc (array_type_nelts_top): Remove function (move
to gcc/).
gcc/rust/ChangeLog:
* backend/rust-tree.h (array_type_nelts_top):
* backend/rust-tree.cc (array_type_nelts_top): Remove function.
Signed-off-by: Alejandro Colomar <alx@kernel.org>
---
gcc/cp/cp-tree.h | 1 -
gcc/cp/tree.cc | 13 -------------
gcc/rust/backend/rust-tree.cc | 13 -------------
gcc/rust/backend/rust-tree.h | 2 --
gcc/tree.cc | 13 +++++++++++++
gcc/tree.h | 1 +
6 files changed, 14 insertions(+), 29 deletions(-)
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index c1a371bc721..e6c1c63f872 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -8099,7 +8099,6 @@ extern tree build_exception_variant (tree, tree);
extern void fixup_deferred_exception_variants (tree, tree);
extern tree bind_template_template_parm (tree, tree);
extern tree array_type_nelts_total (tree);
-extern tree array_type_nelts_top (tree);
extern bool array_of_unknown_bound_p (const_tree);
extern tree break_out_target_exprs (tree, bool = false);
extern tree build_ctor_subob_ref (tree, tree, tree);
diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
index 3baeb8fa252..1f3ecff1a21 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -3071,19 +3071,6 @@ cxx_print_statistics (void)
depth_reached);
}
-/* Return, as an INTEGER_CST node, the number of elements for TYPE
- (which is an ARRAY_TYPE). This counts only elements of the top
- array. */
-
-tree
-array_type_nelts_top (tree type)
-{
- return fold_build2_loc (input_location,
- PLUS_EXPR, sizetype,
- array_type_nelts_minus_one (type),
- size_one_node);
-}
-
/* Return, as an INTEGER_CST node, the number of elements for TYPE
(which is an ARRAY_TYPE). This one is a recursive count of all
ARRAY_TYPEs that are clumped together. */
diff --git a/gcc/rust/backend/rust-tree.cc b/gcc/rust/backend/rust-tree.cc
index a2c12204667..dd8eda84f9b 100644
--- a/gcc/rust/backend/rust-tree.cc
+++ b/gcc/rust/backend/rust-tree.cc
@@ -859,19 +859,6 @@ is_empty_class (tree type)
return CLASSTYPE_EMPTY_P (type);
}
-// forked from gcc/cp/tree.cc array_type_nelts_top
-
-/* Return, as an INTEGER_CST node, the number of elements for TYPE
- (which is an ARRAY_TYPE). This counts only elements of the top
- array. */
-
-tree
-array_type_nelts_top (tree type)
-{
- return fold_build2_loc (input_location, PLUS_EXPR, sizetype,
- array_type_nelts_minus_one (type), size_one_node);
-}
-
// forked from gcc/cp/tree.cc builtin_valid_in_constant_expr_p
/* Test whether DECL is a builtin that may appear in a
diff --git a/gcc/rust/backend/rust-tree.h b/gcc/rust/backend/rust-tree.h
index 26c8b653ac6..e597c3ab81d 100644
--- a/gcc/rust/backend/rust-tree.h
+++ b/gcc/rust/backend/rust-tree.h
@@ -2993,8 +2993,6 @@ extern location_t rs_expr_location (const_tree);
extern int
is_empty_class (tree type);
-extern tree array_type_nelts_top (tree);
-
extern bool
is_really_empty_class (tree, bool);
diff --git a/gcc/tree.cc b/gcc/tree.cc
index dcaccc4c362..cbbc7627ad6 100644
--- a/gcc/tree.cc
+++ b/gcc/tree.cc
@@ -3729,6 +3729,19 @@ array_type_nelts_minus_one (const_tree type)
? max
: fold_build2 (MINUS_EXPR, TREE_TYPE (max), max, min));
}
+
+/* Return, as an INTEGER_CST node, the number of elements for TYPE
+ (which is an ARRAY_TYPE). This counts only elements of the top
+ array. */
+
+tree
+array_type_nelts_top (tree type)
+{
+ return fold_build2_loc (input_location,
+ PLUS_EXPR, sizetype,
+ array_type_nelts_minus_one (type),
+ size_one_node);
+}
\f
/* If arg is static -- a reference to an object in static storage -- then
return the object. This is not the same as the C meaning of `static'.
diff --git a/gcc/tree.h b/gcc/tree.h
index fdddbcf408e..a6c46440b1a 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -4922,6 +4922,7 @@ 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_minus_one (const_tree);
+extern tree array_type_nelts_top (tree);
extern tree value_member (tree, tree);
extern tree purpose_member (const_tree, tree);
--
2.45.2
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 248+ messages in thread
* [PATCH v5 3/3] c: Add __lengthof__ operator
2024-08-06 23:11 ` [PATCH v5 0/3] " Alejandro Colomar
2024-08-06 23:12 ` [PATCH v5 1/3] gcc/: Rename array_type_nelts() => array_type_nelts_minus_one() Alejandro Colomar
2024-08-06 23:12 ` [PATCH v5 2/3] Merge definitions of array_type_nelts_top() Alejandro Colomar
@ 2024-08-06 23:12 ` Alejandro Colomar
2024-08-06 23:14 ` Alejandro Colomar
` (2 more replies)
2024-08-06 23:25 ` [PATCH v5 0/3] " Alejandro Colomar
2024-08-08 22:41 ` Internal Compiler Error (was: [PATCH v5 0/3] c: Add __lengthof__ operator) Alejandro Colomar
4 siblings, 3 replies; 248+ messages in thread
From: Alejandro Colomar @ 2024-08-06 23:12 UTC (permalink / raw)
To: gcc-patches
Cc: Alejandro Colomar, Martin Uecker, Xavier Del Campo Romero,
Joseph Myers, Gabriel Ravier, Jakub Jelinek, Kees Cook,
Qing Zhao, Jens Gustedt, David Brown, Florian Weimer,
Andreas Schwab
[-- Attachment #1: Type: text/plain, Size: 25636 bytes --]
This operator is similar to sizeof but can only be applied to an array,
and returns its length (number of elements).
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.
Cc: Joseph Myers <josmyers@redhat.com>
Cc: Gabriel Ravier <gabravier@gmail.com>
Cc: Jakub Jelinek <jakub@redhat.com>
Cc: Kees Cook <keescook@chromium.org>
Cc: Qing Zhao <qing.zhao@oracle.com>
Cc: Jens Gustedt <jens.gustedt@inria.fr>
Cc: David Brown <david.brown@hesbynett.no>
Cc: Florian Weimer <fweimer@redhat.com>
Cc: Andreas Schwab <schwab@linux-m68k.org>
gcc/ChangeLog:
* doc/extend.texi: Document __lengthof__ operator.
* target.h (enum type_context_kind): Add __lengthof__ operator.
gcc/c-family/ChangeLog:
* c-common.h:
* c-common.def:
* c-common.cc (c_lengthof_type): Add __lengthof__ operator.
gcc/c/ChangeLog:
* c-tree.h
(c_expr_lengthof_expr, c_expr_lengthof_type):
* c-decl.cc
(start_struct, finish_struct):
(start_enum, finish_enum):
* c-parser.cc
(c_parser_sizeof_expression):
(c_parser_lengthof_expression):
(c_parser_sizeof_or_lengthof_expression):
(c_parser_unary_expression):
* c-typeck.cc
(build_external_ref):
(record_maybe_used_decl, pop_maybe_used):
(is_top_array_vla):
(c_expr_lengthof_expr, c_expr_lengthof_type):
Add __lengthof__operator.
gcc/cp/ChangeLog:
* operators.def: Add __lengthof__ operator.
gcc/testsuite/ChangeLog:
* gcc.dg/lengthof-compile.c:
* gcc.dg/lengthof.c: Add tests for __lengthof__ operator.
Link: https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2529.pdf
Link: https://inbox.sourceware.org/gcc/M8S4oQy--3-2@tutanota.com/T/
Suggested-by: Xavier Del Campo Romero <xavi.dcr@tutanota.com>
Co-developed-by: Martin Uecker <uecker@tugraz.at>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
---
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 | 20 ++--
gcc/c/c-parser.cc | 61 +++++++++---
gcc/c/c-tree.h | 4 +
gcc/c/c-typeck.cc | 114 ++++++++++++++++++++-
gcc/cp/operators.def | 1 +
gcc/doc/extend.texi | 23 +++++
gcc/target.h | 3 +
gcc/testsuite/gcc.dg/lengthof-compile.c | 49 +++++++++
gcc/testsuite/gcc.dg/lengthof.c | 127 ++++++++++++++++++++++++
12 files changed, 409 insertions(+), 24 deletions(-)
create mode 100644 gcc/testsuite/gcc.dg/lengthof-compile.c
create mode 100644 gcc/testsuite/gcc.dg/lengthof.c
diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
index e7e371fd26f..9f5feb83345 100644
--- a/gcc/c-family/c-common.cc
+++ b/gcc/c-family/c-common.cc
@@ -465,6 +465,7 @@ const struct c_common_resword c_common_reswords[] =
{ "__inline", RID_INLINE, 0 },
{ "__inline__", RID_INLINE, 0 },
{ "__label__", RID_LABEL, 0 },
+ { "__lengthof__", RID_LENGTHOF, 0 },
{ "__null", RID_NULL, 0 },
{ "__real", RID_REALPART, 0 },
{ "__real__", RID_REALPART, 0 },
@@ -4070,6 +4071,31 @@ c_alignof_expr (location_t loc, tree expr)
return fold_convert_loc (loc, size_type_node, t);
}
+
+/* Implement the lengthof keyword: Return the length of an array,
+ that is, the number of elements in the array. */
+
+tree
+c_lengthof_type (location_t loc, tree type)
+{
+ 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,
+ "invalid application of %<lengthof%> to incomplete type %qT",
+ type);
+ return error_mark_node;
+ }
+
+ return array_type_nelts_top (type);
+}
\f
/* Handle C and C++ default attributes. */
diff --git a/gcc/c-family/c-common.def b/gcc/c-family/c-common.def
index 5de96e5d4a8..6d162f67104 100644
--- a/gcc/c-family/c-common.def
+++ b/gcc/c-family/c-common.def
@@ -50,6 +50,9 @@ DEFTREECODE (EXCESS_PRECISION_EXPR, "excess_precision_expr", tcc_expression, 1)
number. */
DEFTREECODE (USERDEF_LITERAL, "userdef_literal", tcc_exceptional, 3)
+/* Represents a 'lengthof' expression. */
+DEFTREECODE (LENGTHOF_EXPR, "lengthof_expr", tcc_expression, 1)
+
/* Represents a 'sizeof' expression during C++ template expansion,
or for the purpose of -Wsizeof-pointer-memaccess warning. */
DEFTREECODE (SIZEOF_EXPR, "sizeof_expr", tcc_expression, 1)
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index ccaea27c2b9..f815a4cf3bc 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -105,6 +105,7 @@ enum rid
/* C extensions */
RID_ASM, RID_TYPEOF, RID_TYPEOF_UNQUAL, RID_ALIGNOF, RID_ATTRIBUTE,
+ RID_LENGTHOF,
RID_VA_ARG,
RID_EXTENSION, RID_IMAGPART, RID_REALPART, RID_LABEL, RID_CHOOSE_EXPR,
RID_TYPES_COMPATIBLE_P, RID_BUILTIN_COMPLEX, RID_BUILTIN_SHUFFLE,
@@ -885,6 +886,7 @@ extern tree c_common_truthvalue_conversion (location_t, tree);
extern void c_apply_type_quals_to_decl (int, tree);
extern tree c_sizeof_or_alignof_type (location_t, tree, bool, bool, int);
extern tree c_alignof_expr (location_t, tree);
+extern tree c_lengthof_type (location_t, tree);
/* Print an error message for invalid operands to arith operation CODE.
NOP_EXPR is used as a special case (see truthvalue_conversion). */
extern void binary_op_error (rich_location *, enum tree_code, tree, tree);
diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 4dced430d1f..790c58b2558 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -8937,12 +8937,16 @@ start_struct (location_t loc, enum tree_code code, tree name,
within a statement expr used within sizeof, et. al. This is not
terribly serious as C++ doesn't permit statement exprs within
sizeof anyhow. */
- if (warn_cxx_compat && (in_sizeof || in_typeof || in_alignof))
+ if (warn_cxx_compat && (in_sizeof || in_typeof || in_alignof || in_lengthof))
warning_at (loc, OPT_Wc___compat,
"defining type in %qs expression is invalid in C++",
(in_sizeof
? "sizeof"
- : (in_typeof ? "typeof" : "alignof")));
+ : (in_typeof
+ ? "typeof"
+ : (in_alignof
+ ? "alignof"
+ : "lengthof"))));
if (in_underspecified_init)
error_at (loc, "%qT defined in underspecified object initializer", ref);
@@ -9897,7 +9901,7 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes,
struct_types. */
if (warn_cxx_compat
&& struct_parse_info != NULL
- && !in_sizeof && !in_typeof && !in_alignof)
+ && !in_sizeof && !in_typeof && !in_alignof && !in_lengthof)
struct_parse_info->struct_types.safe_push (t);
}
@@ -10071,12 +10075,16 @@ start_enum (location_t loc, struct c_enum_contents *the_enum, tree name,
/* FIXME: This will issue a warning for a use of a type defined
within sizeof in a statement expr. This is not terribly serious
as C++ doesn't permit statement exprs within sizeof anyhow. */
- if (warn_cxx_compat && (in_sizeof || in_typeof || in_alignof))
+ if (warn_cxx_compat && (in_sizeof || in_typeof || in_alignof || in_lengthof))
warning_at (loc, OPT_Wc___compat,
"defining type in %qs expression is invalid in C++",
(in_sizeof
? "sizeof"
- : (in_typeof ? "typeof" : "alignof")));
+ : (in_typeof
+ ? "typeof"
+ : (in_alignof
+ ? "alignof"
+ : "lengthof"))));
if (in_underspecified_init)
error_at (loc, "%qT defined in underspecified object initializer",
@@ -10270,7 +10278,7 @@ finish_enum (tree enumtype, tree values, tree attributes)
struct_types. */
if (warn_cxx_compat
&& struct_parse_info != NULL
- && !in_sizeof && !in_typeof && !in_alignof)
+ && !in_sizeof && !in_typeof && !in_alignof && !in_lengthof)
struct_parse_info->struct_types.safe_push (enumtype);
/* Check for consistency with previous definition */
diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
index 12c5ed5d92c..09bb19f9299 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -74,7 +74,17 @@ along with GCC; see the file COPYING3. If not see
#include "bitmap.h"
#include "analyzer/analyzer-language.h"
#include "toplev.h"
+\f
+#define c_parser_sizeof_expression(parser) \
+( \
+ c_parser_sizeof_or_lengthof_expression (parser, RID_SIZEOF) \
+)
+#define c_parser_lengthof_expression(parser) \
+( \
+ c_parser_sizeof_or_lengthof_expression (parser, RID_LENGTHOF) \
+)
+\f
/* We need to walk over decls with incomplete struct/union/enum types
after parsing the whole translation unit.
In finish_decl(), if the decl is static, has incomplete
@@ -1687,7 +1697,7 @@ static struct c_expr c_parser_binary_expression (c_parser *, struct c_expr *,
tree);
static struct c_expr c_parser_cast_expression (c_parser *, struct c_expr *);
static struct c_expr c_parser_unary_expression (c_parser *);
-static struct c_expr c_parser_sizeof_expression (c_parser *);
+static struct c_expr c_parser_sizeof_or_lengthof_expression (c_parser *, enum rid);
static struct c_expr c_parser_alignof_expression (c_parser *);
static struct c_expr c_parser_postfix_expression (c_parser *);
static struct c_expr c_parser_postfix_expression_after_paren_type (c_parser *,
@@ -9864,6 +9874,8 @@ c_parser_unary_expression (c_parser *parser)
case CPP_KEYWORD:
switch (c_parser_peek_token (parser)->keyword)
{
+ case RID_LENGTHOF:
+ return c_parser_lengthof_expression (parser);
case RID_SIZEOF:
return c_parser_sizeof_expression (parser);
case RID_ALIGNOF:
@@ -9903,12 +9915,13 @@ c_parser_unary_expression (c_parser *parser)
/* Parse a sizeof expression. */
static struct c_expr
-c_parser_sizeof_expression (c_parser *parser)
+c_parser_sizeof_or_lengthof_expression (c_parser *parser, enum rid rid)
{
+ const char *op_name = (rid == RID_LENGTHOF) ? "lengthof" : "sizeof";
struct c_expr expr;
struct c_expr result;
location_t expr_loc;
- gcc_assert (c_parser_next_token_is_keyword (parser, RID_SIZEOF));
+ gcc_assert (c_parser_next_token_is_keyword (parser, rid));
location_t start;
location_t finish = UNKNOWN_LOCATION;
@@ -9917,7 +9930,10 @@ c_parser_sizeof_expression (c_parser *parser)
c_parser_consume_token (parser);
c_inhibit_evaluation_warnings++;
- in_sizeof++;
+ if (rid == RID_LENGTHOF)
+ in_lengthof++;
+ else
+ in_sizeof++;
if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)
&& c_token_starts_compound_literal (c_parser_peek_2nd_token (parser)))
{
@@ -9936,7 +9952,10 @@ c_parser_sizeof_expression (c_parser *parser)
{
struct c_expr ret;
c_inhibit_evaluation_warnings--;
- in_sizeof--;
+ if (rid == RID_LENGTHOF)
+ in_lengthof--;
+ else
+ in_sizeof--;
ret.set_error ();
ret.original_code = ERROR_MARK;
ret.original_type = NULL;
@@ -9948,31 +9967,45 @@ c_parser_sizeof_expression (c_parser *parser)
type_name,
expr_loc);
finish = expr.get_finish ();
- goto sizeof_expr;
+ goto Xof_expr;
}
/* sizeof ( type-name ). */
if (scspecs)
- error_at (expr_loc, "storage class specifier in %<sizeof%>");
+ error_at (expr_loc, "storage class specifier in %qs", op_name);
if (type_name->specs->alignas_p)
error_at (type_name->specs->locations[cdw_alignas],
- "alignment specified for type name in %<sizeof%>");
+ "alignment specified for type name in %qs", op_name);
c_inhibit_evaluation_warnings--;
- in_sizeof--;
- result = c_expr_sizeof_type (expr_loc, type_name);
+ if (rid == RID_LENGTHOF)
+ {
+ in_lengthof--;
+ result = c_expr_lengthof_type (expr_loc, type_name);
+ }
+ else
+ {
+ in_sizeof--;
+ result = c_expr_sizeof_type (expr_loc, type_name);
+ }
}
else
{
expr_loc = c_parser_peek_token (parser)->location;
expr = c_parser_unary_expression (parser);
finish = expr.get_finish ();
- sizeof_expr:
+ Xof_expr:
c_inhibit_evaluation_warnings--;
- in_sizeof--;
+ if (rid == RID_LENGTHOF)
+ in_lengthof--;
+ else
+ in_sizeof--;
mark_exp_read (expr.value);
if (TREE_CODE (expr.value) == COMPONENT_REF
&& DECL_C_BIT_FIELD (TREE_OPERAND (expr.value, 1)))
- error_at (expr_loc, "%<sizeof%> applied to a bit-field");
- result = c_expr_sizeof_expr (expr_loc, expr);
+ error_at (expr_loc, "%qs applied to a bit-field", op_name);
+ if (rid == RID_LENGTHOF)
+ result = c_expr_lengthof_expr (expr_loc, expr);
+ else
+ result = c_expr_sizeof_expr (expr_loc, expr);
}
if (finish == UNKNOWN_LOCATION)
finish = start;
diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h
index 15da875a029..102fcfefea6 100644
--- a/gcc/c/c-tree.h
+++ b/gcc/c/c-tree.h
@@ -736,6 +736,7 @@ extern int c_type_dwarf_attribute (const_tree, int);
/* in c-typeck.cc */
extern int in_alignof;
extern int in_sizeof;
+extern int in_lengthof;
extern int in_typeof;
extern bool c_in_omp_for;
extern bool c_omp_array_section_p;
@@ -786,6 +787,9 @@ extern tree build_external_ref (location_t, tree, bool, tree *);
extern void pop_maybe_used (bool);
extern struct c_expr c_expr_sizeof_expr (location_t, struct c_expr);
extern struct c_expr c_expr_sizeof_type (location_t, struct c_type_name *);
+extern struct c_expr c_expr_lengthof_expr (location_t, struct c_expr);
+extern struct c_expr c_expr_lengthof_type (location_t loc,
+ struct c_type_name *);
extern struct c_expr parser_build_unary_op (location_t, enum tree_code,
struct c_expr);
extern struct c_expr parser_build_binary_op (location_t,
diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index 7e0f01ed22b..98e8d31cb3b 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -71,6 +71,9 @@ int in_alignof;
/* The level of nesting inside "sizeof". */
int in_sizeof;
+/* The level of nesting inside "lengthof". */
+int in_lengthof;
+
/* The level of nesting inside "typeof". */
int in_typeof;
@@ -3255,7 +3258,7 @@ build_external_ref (location_t loc, tree id, bool fun, tree *type)
if (TREE_CODE (ref) == FUNCTION_DECL && !in_alignof)
{
- if (!in_sizeof && !in_typeof)
+ if (!in_sizeof && !in_typeof && !in_lengthof)
C_DECL_USED (ref) = 1;
else if (DECL_INITIAL (ref) == NULL_TREE
&& DECL_EXTERNAL (ref)
@@ -3311,7 +3314,7 @@ struct maybe_used_decl
{
/* The decl. */
tree decl;
- /* The level seen at (in_sizeof + in_typeof). */
+ /* The level seen at (in_sizeof + in_typeof + in_lengthof). */
int level;
/* The next one at this level or above, or NULL. */
struct maybe_used_decl *next;
@@ -3329,7 +3332,7 @@ record_maybe_used_decl (tree decl)
{
struct maybe_used_decl *t = XOBNEW (&parser_obstack, struct maybe_used_decl);
t->decl = decl;
- t->level = in_sizeof + in_typeof;
+ t->level = in_sizeof + in_typeof + in_lengthof;
t->next = maybe_used_decls;
maybe_used_decls = t;
}
@@ -3343,7 +3346,7 @@ void
pop_maybe_used (bool used)
{
struct maybe_used_decl *p = maybe_used_decls;
- int cur_level = in_sizeof + in_typeof;
+ int cur_level = in_sizeof + in_typeof + in_lengthof;
while (p && p->level > cur_level)
{
if (used)
@@ -3453,6 +3456,109 @@ 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
+c_expr_lengthof_expr (location_t loc, struct c_expr expr)
+{
+ struct c_expr ret;
+ if (expr.value == error_mark_node)
+ {
+ ret.value = error_mark_node;
+ ret.original_code = ERROR_MARK;
+ ret.original_type = NULL;
+ ret.m_decimal = 0;
+ pop_maybe_used (false);
+ }
+ else
+ {
+ bool expr_const_operands = true;
+
+ tree folded_expr = c_fully_fold (expr.value, require_constant_value,
+ &expr_const_operands);
+ ret.value = c_lengthof_type (loc, TREE_TYPE (folded_expr));
+ c_last_sizeof_arg = expr.value;
+ c_last_sizeof_loc = loc;
+ ret.original_code = LENGTHOF_EXPR;
+ ret.original_type = NULL;
+ ret.m_decimal = 0;
+ 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),
+ folded_expr, ret.value);
+ C_MAYBE_CONST_EXPR_NON_CONST (ret.value) = !expr_const_operands;
+ SET_EXPR_LOCATION (ret.value, loc);
+ }
+ pop_maybe_used (is_top_array_vla (TREE_TYPE (folded_expr)));
+ }
+ return ret;
+}
+
+/* Return the result of lengthof applied to T, a structure for the type
+ name passed to _lengthof (rather than the type itself). LOC is the
+ location of the original expression. */
+
+struct c_expr
+c_expr_lengthof_type (location_t loc, struct c_type_name *t)
+{
+ tree type;
+ struct c_expr ret;
+ tree type_expr = NULL_TREE;
+ bool type_expr_const = true;
+ type = groktypename (t, &type_expr, &type_expr_const);
+ ret.value = c_lengthof_type (loc, type);
+ c_last_sizeof_arg = type;
+ c_last_sizeof_loc = loc;
+ ret.original_code = LENGTHOF_EXPR;
+ ret.original_type = NULL;
+ ret.m_decimal = 0;
+ if (type == error_mark_node)
+ {
+ ret.value = error_mark_node;
+ ret.original_code = ERROR_MARK;
+ }
+ else
+ if ((type_expr || TREE_CODE (ret.value) == INTEGER_CST)
+ && 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
+ the result of lengthof does not get folded to a constant by
+ c_fully_fold, because if the length is evaluated the result is
+ not constant and so constraints on zero or negative size
+ arrays must not be applied when this lengthof call is inside
+ another array declarator. */
+ if (!type_expr)
+ type_expr = integer_zero_node;
+ ret.value = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (ret.value),
+ type_expr, ret.value);
+ C_MAYBE_CONST_EXPR_NON_CONST (ret.value) = !type_expr_const;
+ }
+ pop_maybe_used (type != error_mark_node ? is_top_array_vla (type) : false);
+ return ret;
+}
+
/* Build a function call to function FUNCTION with parameters PARAMS.
The function call is at LOC.
PARAMS is a list--a chain of TREE_LIST nodes--in which the
diff --git a/gcc/cp/operators.def b/gcc/cp/operators.def
index d8878923602..d640ed8bd91 100644
--- a/gcc/cp/operators.def
+++ b/gcc/cp/operators.def
@@ -91,6 +91,7 @@ DEF_OPERATOR ("co_await", CO_AWAIT_EXPR, "aw", OVL_OP_FLAG_UNARY)
/* These are extensions. */
DEF_OPERATOR ("alignof", ALIGNOF_EXPR, "az", OVL_OP_FLAG_UNARY)
+DEF_OPERATOR ("__lengthof__", LENGTHOF_EXPR, "lz", OVL_OP_FLAG_UNARY)
DEF_OPERATOR ("__imag__", IMAGPART_EXPR, "v18__imag__", OVL_OP_FLAG_UNARY)
DEF_OPERATOR ("__real__", REALPART_EXPR, "v18__real__", OVL_OP_FLAG_UNARY)
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 0b572afca72..21608eb43a6 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -10391,6 +10391,29 @@ 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 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}.
+The operand must be a complete array type.
+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);
+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
+@end smallexample
+
@node Inline
@section An Inline Function is As Fast As a Macro
@cindex inline functions
diff --git a/gcc/target.h b/gcc/target.h
index c1f99b97b86..79890ae9944 100644
--- a/gcc/target.h
+++ b/gcc/target.h
@@ -245,6 +245,9 @@ enum type_context_kind {
/* Directly measuring the alignment of T. */
TCTX_ALIGNOF,
+ /* Directly measuring the length of array T. */
+ TCTX_LENGTHOF,
+
/* Creating objects of type T with static storage duration. */
TCTX_STATIC_STORAGE,
diff --git a/gcc/testsuite/gcc.dg/lengthof-compile.c b/gcc/testsuite/gcc.dg/lengthof-compile.c
new file mode 100644
index 00000000000..6b44704ca7e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/lengthof-compile.c
@@ -0,0 +1,49 @@
+/* { dg-do compile } */
+/* { dg-options "-Wno-declaration-after-statement -Wno-pedantic -Wno-vla" } */
+
+extern int x[];
+
+void
+incomplete (int p[])
+{
+ unsigned n;
+
+ n = __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" } */
+}
+
+void
+fam (void)
+{
+ struct {
+ int x;
+ int fam[];
+ } s;
+ unsigned n;
+
+ n = __lengthof__ (s.fam); /* { dg-error "incomplete" } */
+}
+
+void fix_fix (int i, char (*a)[3][5], int (*x)[__lengthof__ (*a)]);
+void fix_var (int i, char (*a)[3][i], int (*x)[__lengthof__ (*a)]);
+void fix_uns (int i, char (*a)[3][*], int (*x)[__lengthof__ (*a)]);
+
+void
+func (void)
+{
+ int i3[3];
+ int i5[5];
+ char c35[3][5];
+
+ fix_fix (5, &c35, &i3);
+ fix_fix (5, &c35, &i5); /* { dg-error "incompatible-pointer-types" } */
+
+ fix_var (5, &c35, &i3);
+ fix_var (5, &c35, &i5); /* { dg-error "incompatible-pointer-types" } */
+
+ fix_uns (5, &c35, &i3);
+ fix_uns (5, &c35, &i5); /* { dg-error "incompatible-pointer-types" } */
+}
diff --git a/gcc/testsuite/gcc.dg/lengthof.c b/gcc/testsuite/gcc.dg/lengthof.c
new file mode 100644
index 00000000000..38da5df52a5
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/lengthof.c
@@ -0,0 +1,127 @@
+/* { dg-do run } */
+/* { dg-options "-Wno-declaration-after-statement -Wno-pedantic -Wno-vla" } */
+
+#undef NDEBUG
+#include <assert.h>
+
+void
+array (void)
+{
+ short a[7];
+
+ assert (__lengthof__ (a) == 7);
+ assert (__lengthof__ (long [0]) == 0);
+ assert (__lengthof__ (unsigned [99]) == 99);
+}
+
+void
+vla (void)
+{
+ unsigned n;
+
+ n = 99;
+ assert (__lengthof__ (short [n - 10]) == 99 - 10);
+
+ int v[n / 2];
+ assert (__lengthof__ (v) == 99 / 2);
+
+ n = 0;
+ int z[n];
+ assert (__lengthof__ (z) == 0);
+}
+
+void
+member (void)
+{
+ struct {
+ int a[8];
+ } s;
+
+ assert (__lengthof__ (s.a) == 8);
+}
+
+void
+vla_eval (void)
+{
+ int i;
+
+ i = 7;
+ assert (__lengthof__ (struct {int x;}[i++]) == 7);
+ assert (i == 7 + 1);
+
+ int v[i];
+ int (*p)[i];
+ p = &v;
+ assert (__lengthof__ (*p++) == i);
+ assert (p - 1 == &v);
+}
+
+void
+inner_vla_noeval (void)
+{
+ int i;
+
+ i = 3;
+ assert (__lengthof__ (struct {int x[i++];}[3]) == 3);
+ assert (i == 3);
+}
+
+void
+array_noeval (void)
+{
+ long a[5];
+ long (*p)[__lengthof__ (a)];
+
+ p = &a;
+ assert (__lengthof__ (*p++) == 5);
+ assert (p == &a);
+}
+
+void
+matrix_zero (void)
+{
+ int i;
+
+ assert (__lengthof__ (int [0][4]) == 0);
+ i = 3;
+ assert (__lengthof__ (int [0][i]) == 0);
+}
+
+void
+matrix_fixed (void)
+{
+ int i;
+
+ assert (__lengthof__ (int [7][4]) == 7);
+ i = 3;
+ assert (__lengthof__ (int [7][i]) == 7);
+}
+
+void
+matrix_vla (void)
+{
+ int i, j;
+
+ i = 7;
+ assert (__lengthof__ (int [i++][4]) == 7);
+ assert (i == 7 + 1);
+
+ i = 9;
+ j = 3;
+ assert (__lengthof__ (int [i++][j]) == 9);
+ assert (i == 9 + 1);
+}
+
+int
+main (void)
+{
+ array ();
+ vla ();
+ member ();
+ vla_eval ();
+ inner_vla_noeval ();
+ array_noeval ();
+ matrix_zero ();
+ matrix_fixed ();
+ matrix_vla ();
+}
--
2.45.2
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [PATCH v5 3/3] c: Add __lengthof__ operator
2024-08-06 23:12 ` [PATCH v5 3/3] c: Add __lengthof__ operator Alejandro Colomar
@ 2024-08-06 23:14 ` Alejandro Colomar
2024-08-07 7:13 ` Martin Uecker
2024-08-07 15:05 ` Joseph Myers
2 siblings, 0 replies; 248+ messages in thread
From: Alejandro Colomar @ 2024-08-06 23:14 UTC (permalink / raw)
To: gcc-patches
Cc: Martin Uecker, Xavier Del Campo Romero, Joseph Myers,
Gabriel Ravier, Jakub Jelinek, Kees Cook, Qing Zhao,
Jens Gustedt, David Brown, Florian Weimer, Andreas Schwab
[-- Attachment #1: Type: text/plain, Size: 27420 bytes --]
On Wed, Aug 07, 2024 at 01:12:17AM GMT, Alejandro Colomar wrote:
> This operator is similar to sizeof but can only be applied to an array,
> and returns its length (number of elements).
>
> 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.
>
> Cc: Joseph Myers <josmyers@redhat.com>
> Cc: Gabriel Ravier <gabravier@gmail.com>
> Cc: Jakub Jelinek <jakub@redhat.com>
> Cc: Kees Cook <keescook@chromium.org>
> Cc: Qing Zhao <qing.zhao@oracle.com>
> Cc: Jens Gustedt <jens.gustedt@inria.fr>
> Cc: David Brown <david.brown@hesbynett.no>
> Cc: Florian Weimer <fweimer@redhat.com>
> Cc: Andreas Schwab <schwab@linux-m68k.org>
>
> gcc/ChangeLog:
>
> * doc/extend.texi: Document __lengthof__ operator.
> * target.h (enum type_context_kind): Add __lengthof__ operator.
>
> gcc/c-family/ChangeLog:
>
> * c-common.h:
> * c-common.def:
> * c-common.cc (c_lengthof_type): Add __lengthof__ operator.
>
> gcc/c/ChangeLog:
>
> * c-tree.h
> (c_expr_lengthof_expr, c_expr_lengthof_type):
> * c-decl.cc
> (start_struct, finish_struct):
> (start_enum, finish_enum):
> * c-parser.cc
> (c_parser_sizeof_expression):
> (c_parser_lengthof_expression):
> (c_parser_sizeof_or_lengthof_expression):
> (c_parser_unary_expression):
> * c-typeck.cc
> (build_external_ref):
> (record_maybe_used_decl, pop_maybe_used):
> (is_top_array_vla):
> (c_expr_lengthof_expr, c_expr_lengthof_type):
> Add __lengthof__operator.
>
> gcc/cp/ChangeLog:
>
> * operators.def: Add __lengthof__ operator.
>
> gcc/testsuite/ChangeLog:
>
> * gcc.dg/lengthof-compile.c:
> * gcc.dg/lengthof.c: Add tests for __lengthof__ operator.
>
> Link: https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2529.pdf
> Link: https://inbox.sourceware.org/gcc/M8S4oQy--3-2@tutanota.com/T/
> Suggested-by: Xavier Del Campo Romero <xavi.dcr@tutanota.com>
> Co-developed-by: Martin Uecker <uecker@tugraz.at>
> Signed-off-by: Alejandro Colomar <alx@kernel.org>
> ---
> 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 | 20 ++--
> gcc/c/c-parser.cc | 61 +++++++++---
> gcc/c/c-tree.h | 4 +
> gcc/c/c-typeck.cc | 114 ++++++++++++++++++++-
> gcc/cp/operators.def | 1 +
> gcc/doc/extend.texi | 23 +++++
> gcc/target.h | 3 +
> gcc/testsuite/gcc.dg/lengthof-compile.c | 49 +++++++++
> gcc/testsuite/gcc.dg/lengthof.c | 127 ++++++++++++++++++++++++
> 12 files changed, 409 insertions(+), 24 deletions(-)
> create mode 100644 gcc/testsuite/gcc.dg/lengthof-compile.c
> create mode 100644 gcc/testsuite/gcc.dg/lengthof.c
>
> diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
> index e7e371fd26f..9f5feb83345 100644
> --- a/gcc/c-family/c-common.cc
> +++ b/gcc/c-family/c-common.cc
> @@ -465,6 +465,7 @@ const struct c_common_resword c_common_reswords[] =
> { "__inline", RID_INLINE, 0 },
> { "__inline__", RID_INLINE, 0 },
> { "__label__", RID_LABEL, 0 },
> + { "__lengthof__", RID_LENGTHOF, 0 },
> { "__null", RID_NULL, 0 },
> { "__real", RID_REALPART, 0 },
> { "__real__", RID_REALPART, 0 },
> @@ -4070,6 +4071,31 @@ c_alignof_expr (location_t loc, tree expr)
>
> return fold_convert_loc (loc, size_type_node, t);
> }
> +
> +/* Implement the lengthof keyword: Return the length of an array,
> + that is, the number of elements in the array. */
> +
> +tree
> +c_lengthof_type (location_t loc, tree type)
> +{
> + 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,
> + "invalid application of %<lengthof%> to incomplete type %qT",
> + type);
> + return error_mark_node;
> + }
> +
> + return array_type_nelts_top (type);
> +}
> \f
> /* Handle C and C++ default attributes. */
>
> diff --git a/gcc/c-family/c-common.def b/gcc/c-family/c-common.def
> index 5de96e5d4a8..6d162f67104 100644
> --- a/gcc/c-family/c-common.def
> +++ b/gcc/c-family/c-common.def
> @@ -50,6 +50,9 @@ DEFTREECODE (EXCESS_PRECISION_EXPR, "excess_precision_expr", tcc_expression, 1)
> number. */
> DEFTREECODE (USERDEF_LITERAL, "userdef_literal", tcc_exceptional, 3)
>
> +/* Represents a 'lengthof' expression. */
> +DEFTREECODE (LENGTHOF_EXPR, "lengthof_expr", tcc_expression, 1)
> +
> /* Represents a 'sizeof' expression during C++ template expansion,
> or for the purpose of -Wsizeof-pointer-memaccess warning. */
> DEFTREECODE (SIZEOF_EXPR, "sizeof_expr", tcc_expression, 1)
> diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
> index ccaea27c2b9..f815a4cf3bc 100644
> --- a/gcc/c-family/c-common.h
> +++ b/gcc/c-family/c-common.h
> @@ -105,6 +105,7 @@ enum rid
>
> /* C extensions */
> RID_ASM, RID_TYPEOF, RID_TYPEOF_UNQUAL, RID_ALIGNOF, RID_ATTRIBUTE,
> + RID_LENGTHOF,
> RID_VA_ARG,
> RID_EXTENSION, RID_IMAGPART, RID_REALPART, RID_LABEL, RID_CHOOSE_EXPR,
> RID_TYPES_COMPATIBLE_P, RID_BUILTIN_COMPLEX, RID_BUILTIN_SHUFFLE,
> @@ -885,6 +886,7 @@ extern tree c_common_truthvalue_conversion (location_t, tree);
> extern void c_apply_type_quals_to_decl (int, tree);
> extern tree c_sizeof_or_alignof_type (location_t, tree, bool, bool, int);
> extern tree c_alignof_expr (location_t, tree);
> +extern tree c_lengthof_type (location_t, tree);
> /* Print an error message for invalid operands to arith operation CODE.
> NOP_EXPR is used as a special case (see truthvalue_conversion). */
> extern void binary_op_error (rich_location *, enum tree_code, tree, tree);
> diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
> index 4dced430d1f..790c58b2558 100644
> --- a/gcc/c/c-decl.cc
> +++ b/gcc/c/c-decl.cc
> @@ -8937,12 +8937,16 @@ start_struct (location_t loc, enum tree_code code, tree name,
> within a statement expr used within sizeof, et. al. This is not
> terribly serious as C++ doesn't permit statement exprs within
> sizeof anyhow. */
> - if (warn_cxx_compat && (in_sizeof || in_typeof || in_alignof))
> + if (warn_cxx_compat && (in_sizeof || in_typeof || in_alignof || in_lengthof))
> warning_at (loc, OPT_Wc___compat,
> "defining type in %qs expression is invalid in C++",
> (in_sizeof
> ? "sizeof"
> - : (in_typeof ? "typeof" : "alignof")));
> + : (in_typeof
> + ? "typeof"
> + : (in_alignof
> + ? "alignof"
> + : "lengthof"))));
>
> if (in_underspecified_init)
> error_at (loc, "%qT defined in underspecified object initializer", ref);
> @@ -9897,7 +9901,7 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes,
> struct_types. */
> if (warn_cxx_compat
> && struct_parse_info != NULL
> - && !in_sizeof && !in_typeof && !in_alignof)
> + && !in_sizeof && !in_typeof && !in_alignof && !in_lengthof)
> struct_parse_info->struct_types.safe_push (t);
> }
>
> @@ -10071,12 +10075,16 @@ start_enum (location_t loc, struct c_enum_contents *the_enum, tree name,
> /* FIXME: This will issue a warning for a use of a type defined
> within sizeof in a statement expr. This is not terribly serious
> as C++ doesn't permit statement exprs within sizeof anyhow. */
> - if (warn_cxx_compat && (in_sizeof || in_typeof || in_alignof))
> + if (warn_cxx_compat && (in_sizeof || in_typeof || in_alignof || in_lengthof))
> warning_at (loc, OPT_Wc___compat,
> "defining type in %qs expression is invalid in C++",
> (in_sizeof
> ? "sizeof"
> - : (in_typeof ? "typeof" : "alignof")));
> + : (in_typeof
> + ? "typeof"
> + : (in_alignof
> + ? "alignof"
> + : "lengthof"))));
>
> if (in_underspecified_init)
> error_at (loc, "%qT defined in underspecified object initializer",
> @@ -10270,7 +10278,7 @@ finish_enum (tree enumtype, tree values, tree attributes)
> struct_types. */
> if (warn_cxx_compat
> && struct_parse_info != NULL
> - && !in_sizeof && !in_typeof && !in_alignof)
> + && !in_sizeof && !in_typeof && !in_alignof && !in_lengthof)
> struct_parse_info->struct_types.safe_push (enumtype);
>
> /* Check for consistency with previous definition */
> diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
> index 12c5ed5d92c..09bb19f9299 100644
> --- a/gcc/c/c-parser.cc
> +++ b/gcc/c/c-parser.cc
> @@ -74,7 +74,17 @@ along with GCC; see the file COPYING3. If not see
> #include "bitmap.h"
> #include "analyzer/analyzer-language.h"
> #include "toplev.h"
> +\f
> +#define c_parser_sizeof_expression(parser) \
> +( \
> + c_parser_sizeof_or_lengthof_expression (parser, RID_SIZEOF) \
> +)
>
> +#define c_parser_lengthof_expression(parser) \
> +( \
> + c_parser_sizeof_or_lengthof_expression (parser, RID_LENGTHOF) \
> +)
> +\f
> /* We need to walk over decls with incomplete struct/union/enum types
> after parsing the whole translation unit.
> In finish_decl(), if the decl is static, has incomplete
> @@ -1687,7 +1697,7 @@ static struct c_expr c_parser_binary_expression (c_parser *, struct c_expr *,
> tree);
> static struct c_expr c_parser_cast_expression (c_parser *, struct c_expr *);
> static struct c_expr c_parser_unary_expression (c_parser *);
> -static struct c_expr c_parser_sizeof_expression (c_parser *);
> +static struct c_expr c_parser_sizeof_or_lengthof_expression (c_parser *, enum rid);
> static struct c_expr c_parser_alignof_expression (c_parser *);
> static struct c_expr c_parser_postfix_expression (c_parser *);
> static struct c_expr c_parser_postfix_expression_after_paren_type (c_parser *,
> @@ -9864,6 +9874,8 @@ c_parser_unary_expression (c_parser *parser)
> case CPP_KEYWORD:
> switch (c_parser_peek_token (parser)->keyword)
> {
> + case RID_LENGTHOF:
> + return c_parser_lengthof_expression (parser);
> case RID_SIZEOF:
> return c_parser_sizeof_expression (parser);
> case RID_ALIGNOF:
> @@ -9903,12 +9915,13 @@ c_parser_unary_expression (c_parser *parser)
> /* Parse a sizeof expression. */
>
> static struct c_expr
> -c_parser_sizeof_expression (c_parser *parser)
> +c_parser_sizeof_or_lengthof_expression (c_parser *parser, enum rid rid)
> {
> + const char *op_name = (rid == RID_LENGTHOF) ? "lengthof" : "sizeof";
> struct c_expr expr;
> struct c_expr result;
> location_t expr_loc;
> - gcc_assert (c_parser_next_token_is_keyword (parser, RID_SIZEOF));
> + gcc_assert (c_parser_next_token_is_keyword (parser, rid));
>
> location_t start;
> location_t finish = UNKNOWN_LOCATION;
> @@ -9917,7 +9930,10 @@ c_parser_sizeof_expression (c_parser *parser)
>
> c_parser_consume_token (parser);
> c_inhibit_evaluation_warnings++;
> - in_sizeof++;
> + if (rid == RID_LENGTHOF)
> + in_lengthof++;
> + else
> + in_sizeof++;
> if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)
> && c_token_starts_compound_literal (c_parser_peek_2nd_token (parser)))
> {
> @@ -9936,7 +9952,10 @@ c_parser_sizeof_expression (c_parser *parser)
> {
> struct c_expr ret;
> c_inhibit_evaluation_warnings--;
> - in_sizeof--;
> + if (rid == RID_LENGTHOF)
> + in_lengthof--;
> + else
> + in_sizeof--;
> ret.set_error ();
> ret.original_code = ERROR_MARK;
> ret.original_type = NULL;
> @@ -9948,31 +9967,45 @@ c_parser_sizeof_expression (c_parser *parser)
> type_name,
> expr_loc);
> finish = expr.get_finish ();
> - goto sizeof_expr;
> + goto Xof_expr;
> }
> /* sizeof ( type-name ). */
> if (scspecs)
> - error_at (expr_loc, "storage class specifier in %<sizeof%>");
> + error_at (expr_loc, "storage class specifier in %qs", op_name);
> if (type_name->specs->alignas_p)
> error_at (type_name->specs->locations[cdw_alignas],
> - "alignment specified for type name in %<sizeof%>");
> + "alignment specified for type name in %qs", op_name);
> c_inhibit_evaluation_warnings--;
> - in_sizeof--;
> - result = c_expr_sizeof_type (expr_loc, type_name);
> + if (rid == RID_LENGTHOF)
> + {
> + in_lengthof--;
> + result = c_expr_lengthof_type (expr_loc, type_name);
> + }
> + else
> + {
> + in_sizeof--;
> + result = c_expr_sizeof_type (expr_loc, type_name);
> + }
> }
> else
> {
> expr_loc = c_parser_peek_token (parser)->location;
> expr = c_parser_unary_expression (parser);
> finish = expr.get_finish ();
> - sizeof_expr:
> + Xof_expr:
> c_inhibit_evaluation_warnings--;
> - in_sizeof--;
> + if (rid == RID_LENGTHOF)
> + in_lengthof--;
> + else
> + in_sizeof--;
> mark_exp_read (expr.value);
> if (TREE_CODE (expr.value) == COMPONENT_REF
> && DECL_C_BIT_FIELD (TREE_OPERAND (expr.value, 1)))
> - error_at (expr_loc, "%<sizeof%> applied to a bit-field");
> - result = c_expr_sizeof_expr (expr_loc, expr);
> + error_at (expr_loc, "%qs applied to a bit-field", op_name);
> + if (rid == RID_LENGTHOF)
> + result = c_expr_lengthof_expr (expr_loc, expr);
> + else
> + result = c_expr_sizeof_expr (expr_loc, expr);
> }
> if (finish == UNKNOWN_LOCATION)
> finish = start;
> diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h
> index 15da875a029..102fcfefea6 100644
> --- a/gcc/c/c-tree.h
> +++ b/gcc/c/c-tree.h
> @@ -736,6 +736,7 @@ extern int c_type_dwarf_attribute (const_tree, int);
> /* in c-typeck.cc */
> extern int in_alignof;
> extern int in_sizeof;
> +extern int in_lengthof;
> extern int in_typeof;
> extern bool c_in_omp_for;
> extern bool c_omp_array_section_p;
> @@ -786,6 +787,9 @@ extern tree build_external_ref (location_t, tree, bool, tree *);
> extern void pop_maybe_used (bool);
> extern struct c_expr c_expr_sizeof_expr (location_t, struct c_expr);
> extern struct c_expr c_expr_sizeof_type (location_t, struct c_type_name *);
> +extern struct c_expr c_expr_lengthof_expr (location_t, struct c_expr);
> +extern struct c_expr c_expr_lengthof_type (location_t loc,
> + struct c_type_name *);
> extern struct c_expr parser_build_unary_op (location_t, enum tree_code,
> struct c_expr);
> extern struct c_expr parser_build_binary_op (location_t,
> diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
> index 7e0f01ed22b..98e8d31cb3b 100644
> --- a/gcc/c/c-typeck.cc
> +++ b/gcc/c/c-typeck.cc
> @@ -71,6 +71,9 @@ int in_alignof;
> /* The level of nesting inside "sizeof". */
> int in_sizeof;
>
> +/* The level of nesting inside "lengthof". */
> +int in_lengthof;
> +
> /* The level of nesting inside "typeof". */
> int in_typeof;
>
> @@ -3255,7 +3258,7 @@ build_external_ref (location_t loc, tree id, bool fun, tree *type)
>
> if (TREE_CODE (ref) == FUNCTION_DECL && !in_alignof)
> {
> - if (!in_sizeof && !in_typeof)
> + if (!in_sizeof && !in_typeof && !in_lengthof)
> C_DECL_USED (ref) = 1;
> else if (DECL_INITIAL (ref) == NULL_TREE
> && DECL_EXTERNAL (ref)
> @@ -3311,7 +3314,7 @@ struct maybe_used_decl
> {
> /* The decl. */
> tree decl;
> - /* The level seen at (in_sizeof + in_typeof). */
> + /* The level seen at (in_sizeof + in_typeof + in_lengthof). */
> int level;
> /* The next one at this level or above, or NULL. */
> struct maybe_used_decl *next;
> @@ -3329,7 +3332,7 @@ record_maybe_used_decl (tree decl)
> {
> struct maybe_used_decl *t = XOBNEW (&parser_obstack, struct maybe_used_decl);
> t->decl = decl;
> - t->level = in_sizeof + in_typeof;
> + t->level = in_sizeof + in_typeof + in_lengthof;
> t->next = maybe_used_decls;
> maybe_used_decls = t;
> }
> @@ -3343,7 +3346,7 @@ void
> pop_maybe_used (bool used)
> {
> struct maybe_used_decl *p = maybe_used_decls;
> - int cur_level = in_sizeof + in_typeof;
> + int cur_level = in_sizeof + in_typeof + in_lengthof;
> while (p && p->level > cur_level)
> {
> if (used)
> @@ -3453,6 +3456,109 @@ 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
> +c_expr_lengthof_expr (location_t loc, struct c_expr expr)
> +{
> + struct c_expr ret;
> + if (expr.value == error_mark_node)
> + {
> + ret.value = error_mark_node;
> + ret.original_code = ERROR_MARK;
> + ret.original_type = NULL;
> + ret.m_decimal = 0;
> + pop_maybe_used (false);
> + }
> + else
> + {
> + bool expr_const_operands = true;
> +
> + tree folded_expr = c_fully_fold (expr.value, require_constant_value,
> + &expr_const_operands);
> + ret.value = c_lengthof_type (loc, TREE_TYPE (folded_expr));
> + c_last_sizeof_arg = expr.value;
> + c_last_sizeof_loc = loc;
This part is something I had no idea what it's for. Please check what I
should do with it.
> + ret.original_code = LENGTHOF_EXPR;
> + ret.original_type = NULL;
> + ret.m_decimal = 0;
> + 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),
> + folded_expr, ret.value);
> + C_MAYBE_CONST_EXPR_NON_CONST (ret.value) = !expr_const_operands;
> + SET_EXPR_LOCATION (ret.value, loc);
> + }
> + pop_maybe_used (is_top_array_vla (TREE_TYPE (folded_expr)));
> + }
> + return ret;
> +}
> +
> +/* Return the result of lengthof applied to T, a structure for the type
> + name passed to _lengthof (rather than the type itself). LOC is the
> + location of the original expression. */
> +
> +struct c_expr
> +c_expr_lengthof_type (location_t loc, struct c_type_name *t)
> +{
> + tree type;
> + struct c_expr ret;
> + tree type_expr = NULL_TREE;
> + bool type_expr_const = true;
> + type = groktypename (t, &type_expr, &type_expr_const);
> + ret.value = c_lengthof_type (loc, type);
> + c_last_sizeof_arg = type;
> + c_last_sizeof_loc = loc;
> + ret.original_code = LENGTHOF_EXPR;
> + ret.original_type = NULL;
> + ret.m_decimal = 0;
> + if (type == error_mark_node)
> + {
> + ret.value = error_mark_node;
> + ret.original_code = ERROR_MARK;
> + }
> + else
> + if ((type_expr || TREE_CODE (ret.value) == INTEGER_CST)
> + && 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
> + the result of lengthof does not get folded to a constant by
> + c_fully_fold, because if the length is evaluated the result is
> + not constant and so constraints on zero or negative size
> + arrays must not be applied when this lengthof call is inside
> + another array declarator. */
> + if (!type_expr)
> + type_expr = integer_zero_node;
> + ret.value = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (ret.value),
> + type_expr, ret.value);
> + C_MAYBE_CONST_EXPR_NON_CONST (ret.value) = !type_expr_const;
> + }
> + pop_maybe_used (type != error_mark_node ? is_top_array_vla (type) : false);
> + return ret;
> +}
> +
> /* Build a function call to function FUNCTION with parameters PARAMS.
> The function call is at LOC.
> PARAMS is a list--a chain of TREE_LIST nodes--in which the
> diff --git a/gcc/cp/operators.def b/gcc/cp/operators.def
> index d8878923602..d640ed8bd91 100644
> --- a/gcc/cp/operators.def
> +++ b/gcc/cp/operators.def
> @@ -91,6 +91,7 @@ DEF_OPERATOR ("co_await", CO_AWAIT_EXPR, "aw", OVL_OP_FLAG_UNARY)
>
> /* These are extensions. */
> DEF_OPERATOR ("alignof", ALIGNOF_EXPR, "az", OVL_OP_FLAG_UNARY)
> +DEF_OPERATOR ("__lengthof__", LENGTHOF_EXPR, "lz", OVL_OP_FLAG_UNARY)
> DEF_OPERATOR ("__imag__", IMAGPART_EXPR, "v18__imag__", OVL_OP_FLAG_UNARY)
> DEF_OPERATOR ("__real__", REALPART_EXPR, "v18__real__", OVL_OP_FLAG_UNARY)
>
> diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
> index 0b572afca72..21608eb43a6 100644
> --- a/gcc/doc/extend.texi
> +++ b/gcc/doc/extend.texi
> @@ -10391,6 +10391,29 @@ 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 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}.
> +The operand must be a complete array type.
> +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);
> +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
> +@end smallexample
> +
> @node Inline
> @section An Inline Function is As Fast As a Macro
> @cindex inline functions
> diff --git a/gcc/target.h b/gcc/target.h
> index c1f99b97b86..79890ae9944 100644
> --- a/gcc/target.h
> +++ b/gcc/target.h
> @@ -245,6 +245,9 @@ enum type_context_kind {
> /* Directly measuring the alignment of T. */
> TCTX_ALIGNOF,
>
> + /* Directly measuring the length of array T. */
> + TCTX_LENGTHOF,
> +
> /* Creating objects of type T with static storage duration. */
> TCTX_STATIC_STORAGE,
>
> diff --git a/gcc/testsuite/gcc.dg/lengthof-compile.c b/gcc/testsuite/gcc.dg/lengthof-compile.c
> new file mode 100644
> index 00000000000..6b44704ca7e
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/lengthof-compile.c
> @@ -0,0 +1,49 @@
> +/* { dg-do compile } */
> +/* { dg-options "-Wno-declaration-after-statement -Wno-pedantic -Wno-vla" } */
> +
> +extern int x[];
> +
> +void
> +incomplete (int p[])
> +{
> + unsigned n;
> +
> + n = __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" } */
> +}
> +
> +void
> +fam (void)
> +{
> + struct {
> + int x;
> + int fam[];
> + } s;
> + unsigned n;
> +
> + n = __lengthof__ (s.fam); /* { dg-error "incomplete" } */
> +}
> +
> +void fix_fix (int i, char (*a)[3][5], int (*x)[__lengthof__ (*a)]);
> +void fix_var (int i, char (*a)[3][i], int (*x)[__lengthof__ (*a)]);
> +void fix_uns (int i, char (*a)[3][*], int (*x)[__lengthof__ (*a)]);
> +
> +void
> +func (void)
> +{
> + int i3[3];
> + int i5[5];
> + char c35[3][5];
> +
> + fix_fix (5, &c35, &i3);
> + fix_fix (5, &c35, &i5); /* { dg-error "incompatible-pointer-types" } */
> +
> + fix_var (5, &c35, &i3);
> + fix_var (5, &c35, &i5); /* { dg-error "incompatible-pointer-types" } */
> +
> + fix_uns (5, &c35, &i3);
> + fix_uns (5, &c35, &i5); /* { dg-error "incompatible-pointer-types" } */
> +}
> diff --git a/gcc/testsuite/gcc.dg/lengthof.c b/gcc/testsuite/gcc.dg/lengthof.c
> new file mode 100644
> index 00000000000..38da5df52a5
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/lengthof.c
> @@ -0,0 +1,127 @@
> +/* { dg-do run } */
> +/* { dg-options "-Wno-declaration-after-statement -Wno-pedantic -Wno-vla" } */
> +
> +#undef NDEBUG
> +#include <assert.h>
> +
> +void
> +array (void)
> +{
> + short a[7];
> +
> + assert (__lengthof__ (a) == 7);
> + assert (__lengthof__ (long [0]) == 0);
> + assert (__lengthof__ (unsigned [99]) == 99);
> +}
> +
> +void
> +vla (void)
> +{
> + unsigned n;
> +
> + n = 99;
> + assert (__lengthof__ (short [n - 10]) == 99 - 10);
> +
> + int v[n / 2];
> + assert (__lengthof__ (v) == 99 / 2);
> +
> + n = 0;
> + int z[n];
> + assert (__lengthof__ (z) == 0);
> +}
> +
> +void
> +member (void)
> +{
> + struct {
> + int a[8];
> + } s;
> +
> + assert (__lengthof__ (s.a) == 8);
> +}
> +
> +void
> +vla_eval (void)
> +{
> + int i;
> +
> + i = 7;
> + assert (__lengthof__ (struct {int x;}[i++]) == 7);
> + assert (i == 7 + 1);
> +
> + int v[i];
> + int (*p)[i];
> + p = &v;
> + assert (__lengthof__ (*p++) == i);
> + assert (p - 1 == &v);
> +}
> +
> +void
> +inner_vla_noeval (void)
> +{
> + int i;
> +
> + i = 3;
> + assert (__lengthof__ (struct {int x[i++];}[3]) == 3);
> + assert (i == 3);
> +}
> +
> +void
> +array_noeval (void)
> +{
> + long a[5];
> + long (*p)[__lengthof__ (a)];
> +
> + p = &a;
> + assert (__lengthof__ (*p++) == 5);
> + assert (p == &a);
> +}
> +
> +void
> +matrix_zero (void)
> +{
> + int i;
> +
> + assert (__lengthof__ (int [0][4]) == 0);
> + i = 3;
> + assert (__lengthof__ (int [0][i]) == 0);
> +}
> +
> +void
> +matrix_fixed (void)
> +{
> + int i;
> +
> + assert (__lengthof__ (int [7][4]) == 7);
> + i = 3;
> + assert (__lengthof__ (int [7][i]) == 7);
> +}
> +
> +void
> +matrix_vla (void)
> +{
> + int i, j;
> +
> + i = 7;
> + assert (__lengthof__ (int [i++][4]) == 7);
> + assert (i == 7 + 1);
> +
> + i = 9;
> + j = 3;
> + assert (__lengthof__ (int [i++][j]) == 9);
> + assert (i == 9 + 1);
> +}
> +
> +int
> +main (void)
> +{
> + array ();
> + vla ();
> + member ();
> + vla_eval ();
> + inner_vla_noeval ();
> + array_noeval ();
> + matrix_zero ();
> + matrix_fixed ();
> + matrix_vla ();
> +}
> --
> 2.45.2
>
--
<https://www.alejandro-colomar.es/>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [PATCH v5 0/3] c: Add __lengthof__ operator
2024-08-06 23:11 ` [PATCH v5 0/3] " Alejandro Colomar
` (2 preceding siblings ...)
2024-08-06 23:12 ` [PATCH v5 3/3] c: Add __lengthof__ operator Alejandro Colomar
@ 2024-08-06 23:25 ` Alejandro Colomar
2024-08-07 8:11 ` david.brown
[not found] ` <20240807081133.395C7C32782@smtp.kernel.org>
2024-08-08 22:41 ` Internal Compiler Error (was: [PATCH v5 0/3] c: Add __lengthof__ operator) Alejandro Colomar
4 siblings, 2 replies; 248+ messages in thread
From: Alejandro Colomar @ 2024-08-06 23:25 UTC (permalink / raw)
To: gcc-patches
Cc: Martin Uecker, Xavier Del Campo Romero, Joseph Myers,
Gabriel Ravier, Jakub Jelinek, Kees Cook, Qing Zhao,
Jens Gustedt, David Brown, Florian Weimer, Andreas Schwab
[-- Attachment #1: Type: text/plain, Size: 21043 bytes --]
<david.brown@hesbynett.no> is bouncing. FYI. I've removed it.
On Wed, Aug 07, 2024 at 01:12:00AM GMT, Alejandro Colomar wrote:
> Hi!
>
> This is ready for review.
>
> v5:
>
> - Add changelog entries.
> - Wording fixes in commit messages.
> - s/sizeof/lengthof/ in comment.
> - CC += David, Florian, Andreas [Qing]
> - Docs: Remove some details about future directions. [Qing]
> - Docs: Add examples. [Qing]
> - Docs: Clarify when __lengthof__ evaluates as a constant expression
> and when it evaluates as a run-time value. [Joseph, Qing]
> - Tests: Use several -Wno-* flags to turn off unwanted warnings.
> [Martin, Joseph]
> - Tests: Merge into the same commit that adds the feature.
> - Tests: Fix style (whitespace).
>
> I won't paste the example program I used for development, since it's the
> same as in v4. Check that cover letter if necessary.
>
> When reviewing, mind that some parts of the code have been blindly
> pasted from sizeof, and might not make much sense; I didn't fully
> understand some parts. However, it seems to behave well, and more or
> less it makes sense. Just be careful about it.
>
> At the bottom of this message is the range-diff against v4.
>
> Have a lovely night!
> Alex
>
>
> BTW, I've tested that there are no regressions:
>
> alx@debian:~/src/gnu/gcc$ find len0 -type f
> len0/host-x86_64-pc-linux-gnu/gcc/testsuite/gcc/gcc.sum
> len0/host-x86_64-pc-linux-gnu/gcc/testsuite/gfortran/gfortran.sum
> len0/host-x86_64-pc-linux-gnu/gcc/testsuite/objc/objc.sum
> len0/host-x86_64-pc-linux-gnu/gcc/testsuite/g++/g++.sum
> len0/x86_64-pc-linux-gnu/libitm/testsuite/libitm.sum
> len0/x86_64-pc-linux-gnu/libgomp/testsuite/libgomp.sum
> len0/x86_64-pc-linux-gnu/libatomic/testsuite/libatomic.sum
> len0/x86_64-pc-linux-gnu/libstdc++-v3/testsuite/libstdc++.sum
> alx@debian:~/src/gnu/gcc$ find len1 -type f
> len1/host-x86_64-pc-linux-gnu/gcc/testsuite/gcc/gcc.sum
> len1/host-x86_64-pc-linux-gnu/gcc/testsuite/gfortran/gfortran.sum
> len1/host-x86_64-pc-linux-gnu/gcc/testsuite/objc/objc.sum
> len1/host-x86_64-pc-linux-gnu/gcc/testsuite/g++/g++.sum
> len1/x86_64-pc-linux-gnu/libitm/testsuite/libitm.sum
> len1/x86_64-pc-linux-gnu/libgomp/testsuite/libgomp.sum
> len1/x86_64-pc-linux-gnu/libatomic/testsuite/libatomic.sum
> len1/x86_64-pc-linux-gnu/libstdc++-v3/testsuite/libstdc++.sum
> alx@debian:~/src/gnu/gcc$ cat <(cd len0; find -type f) \
> | while read f; do
> diff -u "len0/$f" "len1/$f";
> done;
> --- len0/./host-x86_64-pc-linux-gnu/gcc/testsuite/gcc/gcc.sum 2024-08-06
> +22:22:44.514175252 +0200
> +++ len1/./host-x86_64-pc-linux-gnu/gcc/testsuite/gcc/gcc.sum 2024-08-06
> +23:29:53.693730123 +0200
> @@ -1,4 +1,4 @@
> -Test run by alx on Tue Aug 6 19:28:53 2024
> +Test run by alx on Tue Aug 6 22:49:12 2024
> Native configuration is x86_64-pc-linux-gnu
>
> === gcc tests ===
> @@ -86504,6 +86504,15 @@
> PASS: gcc.dg/large-size-array.c (test for errors, line 19)
> PASS: gcc.dg/large-size-array.c (test for excess errors)
> UNSUPPORTED: gcc.dg/lazy-ptr-test.c
> +PASS: gcc.dg/lengthof-compile.c (test for errors, line 11)
> +PASS: gcc.dg/lengthof-compile.c (test for errors, line 15)
> +PASS: gcc.dg/lengthof-compile.c (test for errors, line 27)
> +PASS: gcc.dg/lengthof-compile.c (test for errors, line 42)
> +PASS: gcc.dg/lengthof-compile.c (test for errors, line 45)
> +PASS: gcc.dg/lengthof-compile.c (test for errors, line 48)
> +PASS: gcc.dg/lengthof-compile.c (test for excess errors)
> +PASS: gcc.dg/lengthof.c (test for excess errors)
> +PASS: gcc.dg/lengthof.c execution test
> PASS: gcc.dg/limits-width-1.c (test for excess errors)
> PASS: gcc.dg/limits-width-2.c (test for excess errors)
> PASS: gcc.dg/live-patching-1.c (test for excess errors)
> @@ -204639,7 +204648,7 @@
>
> === gcc Summary ===
>
> -# of expected passes 199780
> +# of expected passes 199789
> # of unexpected failures 31
> # of unexpected successes 2
> # of expected failures 1463
> --- len0/./host-x86_64-pc-linux-gnu/gcc/testsuite/gfortran/gfortran.sum 2024-08-06
> +22:22:44.546175561 +0200
> +++ len1/./host-x86_64-pc-linux-gnu/gcc/testsuite/gfortran/gfortran.sum 2024-08-06
> +23:29:53.877731933 +0200
> @@ -1,4 +1,4 @@
> -Test run by alx on Tue Aug 6 19:28:53 2024
> +Test run by alx on Tue Aug 6 22:49:12 2024
> Native configuration is x86_64-pc-linux-gnu
>
> === gfortran tests ===
> --- len0/./host-x86_64-pc-linux-gnu/gcc/testsuite/objc/objc.sum 2024-08-06
> +22:22:44.462174752 +0200
> +++ len1/./host-x86_64-pc-linux-gnu/gcc/testsuite/objc/objc.sum 2024-08-06
> +23:29:53.845731618 +0200
> @@ -1,4 +1,4 @@
> -Test run by alx on Tue Aug 6 19:28:53 2024
> +Test run by alx on Tue Aug 6 22:49:12 2024
> Native configuration is x86_64-pc-linux-gnu
>
> === objc tests ===
> --- len0/./host-x86_64-pc-linux-gnu/gcc/testsuite/g++/g++.sum 2024-08-06
> +22:22:44.622176292 +0200
> +++ len1/./host-x86_64-pc-linux-gnu/gcc/testsuite/g++/g++.sum 2024-08-06
> +23:29:53.781730989 +0200
> @@ -1,4 +1,4 @@
> -Test run by alx on Tue Aug 6 19:28:53 2024
> +Test run by alx on Tue Aug 6 22:49:12 2024
> Native configuration is x86_64-pc-linux-gnu
>
> === g++ tests ===
> --- len0/./x86_64-pc-linux-gnu/libitm/testsuite/libitm.sum 2024-08-06
> +22:22:46.206191541 +0200
> +++ len1/./x86_64-pc-linux-gnu/libitm/testsuite/libitm.sum 2024-08-06
> +23:29:55.573748613 +0200
> @@ -1,4 +1,4 @@
> -Test run by alx on Tue Aug 6 19:28:53 2024
> +Test run by alx on Tue Aug 6 22:49:12 2024
> Native configuration is x86_64-pc-linux-gnu
>
> === libitm tests ===
> --- len0/./x86_64-pc-linux-gnu/libgomp/testsuite/libgomp.sum 2024-08-06
> +22:22:45.694186612 +0200
> +++ len1/./x86_64-pc-linux-gnu/libgomp/testsuite/libgomp.sum 2024-08-06
> +23:29:54.717740194 +0200
> @@ -1,4 +1,4 @@
> -Test run by alx on Tue Aug 6 19:28:53 2024
> +Test run by alx on Tue Aug 6 22:49:12 2024
> Native configuration is x86_64-pc-linux-gnu
>
> === libgomp tests ===
> --- len0/./x86_64-pc-linux-gnu/libatomic/testsuite/libatomic.sum 2024-08-06
> +22:22:46.110190617 +0200
> +++ len1/./x86_64-pc-linux-gnu/libatomic/testsuite/libatomic.sum 2024-08-06
> +23:29:55.393746843 +0200
> @@ -1,4 +1,4 @@
> -Test run by alx on Tue Aug 6 19:28:53 2024
> +Test run by alx on Tue Aug 6 22:49:12 2024
> Native configuration is x86_64-pc-linux-gnu
>
> === libatomic tests ===
> --- len0/./x86_64-pc-linux-gnu/libstdc++-v3/testsuite/libstdc++.sum 2024-08-06
> +22:22:45.998189539 +0200
> +++ len1/./x86_64-pc-linux-gnu/libstdc++-v3/testsuite/libstdc++.sum 2024-08-06
> +23:29:55.137744325 +0200
> @@ -1,4 +1,4 @@
> -Test run by alx on Tue Aug 6 19:28:54 2024
> +Test run by alx on Tue Aug 6 22:49:13 2024
> Native configuration is x86_64-pc-linux-gnu
>
> === libstdc++ tests ===
>
>
>
>
>
> 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 | 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 | 23 +++++
> 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 | 49 +++++++++
> gcc/testsuite/gcc.dg/lengthof.c | 127 ++++++++++++++++++++++++
> gcc/tree.cc | 17 +++-
> gcc/tree.h | 3 +-
> 27 files changed, 451 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 v4:
> 1: 73010cb4af6 = 1: 73010cb4af6 gcc/: Rename array_type_nelts() => array_type_nelts_minus_one()
> 2: 2bb966a0a89 ! 2: 9b835478721 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__, which will be added in the following commit.
> +
> + gcc/ChangeLog:
> +
> + * tree.h (array_type_nelts_top):
> + * tree.cc (array_type_nelts_top): Define function (moved from
> + gcc/cp/).
> +
> + gcc/cp/ChangeLog:
> +
> + * cp-tree.h (array_type_nelts_top):
> + * tree.cc (array_type_nelts_top): Remove function (move
> + to gcc/).
> +
> + gcc/rust/ChangeLog:
> +
> + * backend/rust-tree.h (array_type_nelts_top):
> + * backend/rust-tree.cc (array_type_nelts_top): Remove function.
>
> Signed-off-by: Alejandro Colomar <alx@kernel.org>
>
> 3: e2dbfc43b14 ! 3: af05d01e68d c: Add __lengthof__() operator (n2529)
> @@ Metadata
> Author: Alejandro Colomar <alx@kernel.org>
>
> ## Commit message ##
> - c: Add __lengthof__() operator (n2529)
> + c: Add __lengthof__ operator
>
> - This operator is similar to sizeof() but can only be applied to an
> - array, and returns its length (number of elements).
> + This operator is similar to sizeof but can only be applied to an array,
> + and returns its length (number of elements).
>
> 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 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.
>
> - Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2529.pdf>
> - Link: <https://inbox.sourceware.org/gcc/M8S4oQy--3-2@tutanota.com/T/>
> - Suggested-by: Xavier Del Campo Romero <xavi.dcr@tutanota.com>
> - Co-developed-by: Martin Uecker <uecker@tugraz.at>
> - Cc: Gabriel Ravier <gabravier@gmail.com>
> Cc: Joseph Myers <josmyers@redhat.com>
> + Cc: Gabriel Ravier <gabravier@gmail.com>
> Cc: Jakub Jelinek <jakub@redhat.com>
> Cc: Kees Cook <keescook@chromium.org>
> Cc: Qing Zhao <qing.zhao@oracle.com>
> Cc: Jens Gustedt <jens.gustedt@inria.fr>
> + Cc: David Brown <david.brown@hesbynett.no>
> + Cc: Florian Weimer <fweimer@redhat.com>
> + Cc: Andreas Schwab <schwab@linux-m68k.org>
> +
> + gcc/ChangeLog:
> +
> + * doc/extend.texi: Document __lengthof__ operator.
> + * target.h (enum type_context_kind): Add __lengthof__ operator.
> +
> + gcc/c-family/ChangeLog:
> +
> + * c-common.h:
> + * c-common.def:
> + * c-common.cc (c_lengthof_type): Add __lengthof__ operator.
> +
> + gcc/c/ChangeLog:
> +
> + * c-tree.h
> + (c_expr_lengthof_expr, c_expr_lengthof_type):
> + * c-decl.cc
> + (start_struct, finish_struct):
> + (start_enum, finish_enum):
> + * c-parser.cc
> + (c_parser_sizeof_expression):
> + (c_parser_lengthof_expression):
> + (c_parser_sizeof_or_lengthof_expression):
> + (c_parser_unary_expression):
> + * c-typeck.cc
> + (build_external_ref):
> + (record_maybe_used_decl, pop_maybe_used):
> + (is_top_array_vla):
> + (c_expr_lengthof_expr, c_expr_lengthof_type):
> + Add __lengthof__operator.
> +
> + gcc/cp/ChangeLog:
> +
> + * operators.def: Add __lengthof__ operator.
> +
> + gcc/testsuite/ChangeLog:
> +
> + * gcc.dg/lengthof-compile.c:
> + * gcc.dg/lengthof.c: Add tests for __lengthof__ operator.
> +
> + Link: https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2529.pdf
> + Link: https://inbox.sourceware.org/gcc/M8S4oQy--3-2@tutanota.com/T/
> + Suggested-by: Xavier Del Campo Romero <xavi.dcr@tutanota.com>
> + Co-developed-by: Martin Uecker <uecker@tugraz.at>
> Signed-off-by: Alejandro Colomar <alx@kernel.org>
>
> ## gcc/c-family/c-common.cc ##
> @@ gcc/c/c-typeck.cc: int in_alignof;
> /* The level of nesting inside "sizeof". */
> int in_sizeof;
>
> -+/* The level of nesting inside "sizeof". */
> ++/* The level of nesting inside "lengthof". */
> +int in_lengthof;
> +
> /* The level of nesting inside "typeof". */
> @@ gcc/doc/extend.texi: If the operand of the @code{__alignof__} expression is a fu
> +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;
> ++if the top-level length designator is an integer constant expression
> ++(in this case, the operator results in a constant expression);
> +and it is evaluated
> -+if the top-level length designator is not an integer constant expression.
> ++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:
> +
> -+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.
> ++@smallexample
> ++__lengthof__ (int [7][n++]); // constexpr
> ++__lengthof__ (int [n++][7]); // run-time value
> ++@end smallexample
> +
> @node Inline
> @section An Inline Function is As Fast As a Macro
> @@ gcc/target.h: enum type_context_kind {
> /* Creating objects of type T with static storage duration. */
> TCTX_STATIC_STORAGE,
>
> +
> + ## gcc/testsuite/gcc.dg/lengthof-compile.c (new) ##
> +@@
> ++/* { dg-do compile } */
> ++/* { dg-options "-Wno-declaration-after-statement -Wno-pedantic -Wno-vla" } */
> ++
> ++extern int x[];
> ++
> ++void
> ++incomplete (int p[])
> ++{
> ++ unsigned n;
> ++
> ++ n = __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" } */
> ++}
> ++
> ++void
> ++fam (void)
> ++{
> ++ struct {
> ++ int x;
> ++ int fam[];
> ++ } s;
> ++ unsigned n;
> ++
> ++ n = __lengthof__ (s.fam); /* { dg-error "incomplete" } */
> ++}
> ++
> ++void fix_fix (int i, char (*a)[3][5], int (*x)[__lengthof__ (*a)]);
> ++void fix_var (int i, char (*a)[3][i], int (*x)[__lengthof__ (*a)]);
> ++void fix_uns (int i, char (*a)[3][*], int (*x)[__lengthof__ (*a)]);
> ++
> ++void
> ++func (void)
> ++{
> ++ int i3[3];
> ++ int i5[5];
> ++ char c35[3][5];
> ++
> ++ fix_fix (5, &c35, &i3);
> ++ fix_fix (5, &c35, &i5); /* { dg-error "incompatible-pointer-types" } */
> ++
> ++ fix_var (5, &c35, &i3);
> ++ fix_var (5, &c35, &i5); /* { dg-error "incompatible-pointer-types" } */
> ++
> ++ fix_uns (5, &c35, &i3);
> ++ fix_uns (5, &c35, &i5); /* { dg-error "incompatible-pointer-types" } */
> ++}
> +
> + ## gcc/testsuite/gcc.dg/lengthof.c (new) ##
> +@@
> ++/* { dg-do run } */
> ++/* { dg-options "-Wno-declaration-after-statement -Wno-pedantic -Wno-vla" } */
> ++
> ++#undef NDEBUG
> ++#include <assert.h>
> ++
> ++void
> ++array (void)
> ++{
> ++ short a[7];
> ++
> ++ assert (__lengthof__ (a) == 7);
> ++ assert (__lengthof__ (long [0]) == 0);
> ++ assert (__lengthof__ (unsigned [99]) == 99);
> ++}
> ++
> ++void
> ++vla (void)
> ++{
> ++ unsigned n;
> ++
> ++ n = 99;
> ++ assert (__lengthof__ (short [n - 10]) == 99 - 10);
> ++
> ++ int v[n / 2];
> ++ assert (__lengthof__ (v) == 99 / 2);
> ++
> ++ n = 0;
> ++ int z[n];
> ++ assert (__lengthof__ (z) == 0);
> ++}
> ++
> ++void
> ++member (void)
> ++{
> ++ struct {
> ++ int a[8];
> ++ } s;
> ++
> ++ assert (__lengthof__ (s.a) == 8);
> ++}
> ++
> ++void
> ++vla_eval (void)
> ++{
> ++ int i;
> ++
> ++ i = 7;
> ++ assert (__lengthof__ (struct {int x;}[i++]) == 7);
> ++ assert (i == 7 + 1);
> ++
> ++ int v[i];
> ++ int (*p)[i];
> ++ p = &v;
> ++ assert (__lengthof__ (*p++) == i);
> ++ assert (p - 1 == &v);
> ++}
> ++
> ++void
> ++inner_vla_noeval (void)
> ++{
> ++ int i;
> ++
> ++ i = 3;
> ++ assert (__lengthof__ (struct {int x[i++];}[3]) == 3);
> ++ assert (i == 3);
> ++}
> ++
> ++void
> ++array_noeval (void)
> ++{
> ++ long a[5];
> ++ long (*p)[__lengthof__ (a)];
> ++
> ++ p = &a;
> ++ assert (__lengthof__ (*p++) == 5);
> ++ assert (p == &a);
> ++}
> ++
> ++void
> ++matrix_zero (void)
> ++{
> ++ int i;
> ++
> ++ assert (__lengthof__ (int [0][4]) == 0);
> ++ i = 3;
> ++ assert (__lengthof__ (int [0][i]) == 0);
> ++}
> ++
> ++void
> ++matrix_fixed (void)
> ++{
> ++ int i;
> ++
> ++ assert (__lengthof__ (int [7][4]) == 7);
> ++ i = 3;
> ++ assert (__lengthof__ (int [7][i]) == 7);
> ++}
> ++
> ++void
> ++matrix_vla (void)
> ++{
> ++ int i, j;
> ++
> ++ i = 7;
> ++ assert (__lengthof__ (int [i++][4]) == 7);
> ++ assert (i == 7 + 1);
> ++
> ++ i = 9;
> ++ j = 3;
> ++ assert (__lengthof__ (int [i++][j]) == 9);
> ++ assert (i == 9 + 1);
> ++}
> ++
> ++int
> ++main (void)
> ++{
> ++ array ();
> ++ vla ();
> ++ member ();
> ++ vla_eval ();
> ++ inner_vla_noeval ();
> ++ array_noeval ();
> ++ matrix_zero ();
> ++ matrix_fixed ();
> ++ matrix_vla ();
> ++}
> 4: 9a691f7f208 < -: ----------- testsuite: Add tests for __lengthof__
> --
> 2.45.2
>
--
<https://www.alejandro-colomar.es/>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [PATCH v5 3/3] c: Add __lengthof__ operator
2024-08-06 23:12 ` [PATCH v5 3/3] c: Add __lengthof__ operator Alejandro Colomar
2024-08-06 23:14 ` Alejandro Colomar
@ 2024-08-07 7:13 ` Martin Uecker
2024-08-07 9:14 ` Alejandro Colomar
2024-08-07 15:05 ` Joseph Myers
2 siblings, 1 reply; 248+ messages in thread
From: Martin Uecker @ 2024-08-07 7:13 UTC (permalink / raw)
To: Alejandro Colomar, gcc-patches; +Cc: Joseph Myers
Am Mittwoch, dem 07.08.2024 um 01:12 +0200 schrieb Alejandro Colomar:
Hi Alex,
a coupled of comments below.
> --- a/gcc/c/c-parser.cc
> +++ b/gcc/c/c-parser.cc
> @@ -74,7 +74,17 @@ along with GCC; see the file COPYING3. If not see
> #include "bitmap.h"
> #include "analyzer/analyzer-language.h"
> #include "toplev.h"
> +\f
> +#define c_parser_sizeof_expression(parser) \
> +( \
> + c_parser_sizeof_or_lengthof_expression (parser, RID_SIZEOF) \
> +)
>
> +#define c_parser_lengthof_expression(parser) \
> +( \
> + c_parser_sizeof_or_lengthof_expression (parser, RID_LENGTHOF) \
> +)
> +\f
I suggest to avoid the macros. I think the original function calls are
clear enough and this is then just another detour for somebody trying
to follow the code. Or is there a reason I am missing?
...
> diff --git a/gcc/testsuite/gcc.dg/lengthof-compile.c b/gcc/testsuite/gcc.dg/lengthof-compile.c
> new file mode 100644
> index 00000000000..6b44704ca7e
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/lengthof-compile.c
> @@ -0,0 +1,49 @@
> +/* { dg-do compile } */
> +/* { dg-options "-Wno-declaration-after-statement -Wno-pedantic -Wno-vla" } */
> +
> +extern int x[];
> +
> +void
> +incomplete (int p[])
> +{
> + unsigned n;
> +
> + n = __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" } */
> +}
> +
> +void
> +fam (void)
> +{
> + struct {
> + int x;
> + int fam[];
> + } s;
> + unsigned n;
> +
> + n = __lengthof__ (s.fam); /* { dg-error "incomplete" } */
> +}
> +
> +void fix_fix (int i, char (*a)[3][5], int (*x)[__lengthof__ (*a)]);
> +void fix_var (int i, char (*a)[3][i], int (*x)[__lengthof__ (*a)]);
> +void fix_uns (int i, char (*a)[3][*], int (*x)[__lengthof__ (*a)]);
It would include a test that shows that when lengthof
is applied to [*] that it remains formally non-constant. For example,
you could test with -Wvla-parameter that the two declarations do not give a
warning:
void foo(char (*a)[*], int x[*]);
void foo(char (*a)[*], int x[__lengthof__(*a)]);
(With int (*x)[*] we would run into the issue that we can not
distinguish zero arrays from unspecified ones, PR 98539)
> +
> +void
> +func (void)
> +{
> + int i3[3];
> + int i5[5];
> + char c35[3][5];
> +
> + fix_fix (5, &c35, &i3);
> + fix_fix (5, &c35, &i5); /* { dg-error "incompatible-pointer-types" } */
> +
> + fix_var (5, &c35, &i3);
> + fix_var (5, &c35, &i5); /* { dg-error "incompatible-pointer-types" } */
> +
> + fix_uns (5, &c35, &i3);
> + fix_uns (5, &c35, &i5); /* { dg-error "incompatible-pointer-types" } */
> +}
> diff --git a/gcc/testsuite/gcc.dg/lengthof.c b/gcc/testsuite/gcc.dg/lengthof.c
> new file mode 100644
> index 00000000000..38da5df52a5
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/lengthof.c
> @@ -0,0 +1,127 @@
> +/* { dg-do run } */
> +/* { dg-options "-Wno-declaration-after-statement -Wno-pedantic -Wno-vla" } */
> +
> +#undef NDEBUG
> +#include <assert.h>
> +
> +void
> +array (void)
> +{
> + short a[7];
> +
> + assert (__lengthof__ (a) == 7);
> + assert (__lengthof__ (long [0]) == 0);
> + assert (__lengthof__ (unsigned [99]) == 99);
> +}
Instead of using assert you can use
if (! ...) __builtin_abort();
to avoid the include in the testsuite.
Otherwise it looks fine from my side.
Joseph needs to approve and may have more comments.
Martin
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [PATCH v5 0/3] c: Add __lengthof__ operator
2024-08-06 23:25 ` [PATCH v5 0/3] " Alejandro Colomar
@ 2024-08-07 8:11 ` david.brown
[not found] ` <20240807081133.395C7C32782@smtp.kernel.org>
1 sibling, 0 replies; 248+ messages in thread
From: david.brown @ 2024-08-07 8:11 UTC (permalink / raw)
To: Alejandro Colomar, gcc-patches
Cc: Martin Uecker, Xavier Del Campo Romero, Joseph Myers,
Gabriel Ravier, Jakub Jelinek, Kees Cook, Qing Zhao,
Jens Gustedt, Florian Weimer, Andreas Schwab
[-- Attachment #1: Type: text/plain, Size: 23941 bytes --]
Hi,The address david.brown@hesbynett.no is not bouncing. Its my email address, and I'm getting the emails in this discussion just fine.However, I don't think I have anything to contribute here, so I don't object to being removed from the discussion. I am not a gcc developer, but as a long term user I occasionally post on the developer mailing list. I don't remember having posted about a potential __lengthof__ operator, but it is certainly possible. On behalf of all gcc users, thank you for your efforts in working to improve gcc, no matter how this proposal turns out.Mvh.,David Browndavid.brown@hesbynett.no
-------- Original message --------From: Alejandro Colomar <alx@kernel.org> Date: 07/08/2024 01:26 (GMT+01:00) To: gcc-patches@gcc.gnu.org Cc: Martin Uecker <uecker@tugraz.at>, Xavier Del Campo Romero <xavi.dcr@tutanota.com>, Joseph Myers <josmyers@redhat.com>, Gabriel Ravier <gabravier@gmail.com>, Jakub Jelinek <jakub@redhat.com>, Kees Cook <keescook@chromium.org>, Qing Zhao <qing.zhao@oracle.com>, Jens Gustedt <jens.gustedt@inria.fr>, David Brown <david.brown@hesbynett.no>, Florian Weimer <fweimer@redhat.com>, Andreas Schwab <schwab@linux-m68k.org> Subject: Re: [PATCH v5 0/3] c: Add __lengthof__ operator <david.brown@hesbynett.no> is bouncing. FYI. I've removed it.On Wed, Aug 07, 2024 at 01:12:00AM GMT, Alejandro Colomar wrote:> Hi!> > This is ready for review.> > v5:> > - Add changelog entries.> - Wording fixes in commit messages.> - s/sizeof/lengthof/ in comment.> - CC += David, Florian, Andreas [Qing]> - Docs: Remove some details about future directions. [Qing]> - Docs: Add examples. [Qing]> - Docs: Clarify when __lengthof__ evaluates as a constant expression> and when it evaluates as a run-time value. [Joseph, Qing]> - Tests: Use several -Wno-* flags to turn off unwanted warnings.> [Martin, Joseph]> - Tests: Merge into the same commit that adds the feature.> - Tests: Fix style (whitespace).> > I won't paste the example program I used for development, since it's the> same as in v4. Check that cover letter if necessary.> > When reviewing, mind that some parts of the code have been blindly> pasted from sizeof, and might not make much sense; I didn't fully> understand some parts. However, it seems to behave well, and more or> less it makes sense. Just be careful about it.> > At the bottom of this message is the range-diff against v4.> > Have a lovely night!> Alex> > > BTW, I've tested that there are no regressions:> > alx@debian:~/src/gnu/gcc$ find len0 -type f> len0/host-x86_64-pc-linux-gnu/gcc/testsuite/gcc/gcc.sum> len0/host-x86_64-pc-linux-gnu/gcc/testsuite/gfortran/gfortran.sum> len0/host-x86_64-pc-linux-gnu/gcc/testsuite/objc/objc.sum> len0/host-x86_64-pc-linux-gnu/gcc/testsuite/g++/g++.sum> len0/x86_64-pc-linux-gnu/libitm/testsuite/libitm.sum> len0/x86_64-pc-linux-gnu/libgomp/testsuite/libgomp.sum> len0/x86_64-pc-linux-gnu/libatomic/testsuite/libatomic.sum> len0/x86_64-pc-linux-gnu/libstdc++-v3/testsuite/libstdc++.sum> alx@debian:~/src/gnu/gcc$ find len1 -type f> len1/host-x86_64-pc-linux-gnu/gcc/testsuite/gcc/gcc.sum> len1/host-x86_64-pc-linux-gnu/gcc/testsuite/gfortran/gfortran.sum> len1/host-x86_64-pc-linux-gnu/gcc/testsuite/objc/objc.sum> len1/host-x86_64-pc-linux-gnu/gcc/testsuite/g++/g++.sum> len1/x86_64-pc-linux-gnu/libitm/testsuite/libitm.sum> len1/x86_64-pc-linux-gnu/libgomp/testsuite/libgomp.sum> len1/x86_64-pc-linux-gnu/libatomic/testsuite/libatomic.sum> len1/x86_64-pc-linux-gnu/libstdc++-v3/testsuite/libstdc++.sum> alx@debian:~/src/gnu/gcc$ cat <(cd len0; find -type f) \> | while read f; do> diff -u "len0/$f" "len1/$f";> done;> --- len0/./host-x86_64-pc-linux-gnu/gcc/testsuite/gcc/gcc.sum 2024-08-06> +22:22:44.514175252 +0200> +++ len1/./host-x86_64-pc-linux-gnu/gcc/testsuite/gcc/gcc.sum 2024-08-06> +23:29:53.693730123 +0200> @@ -1,4 +1,4 @@> -Test run by alx on Tue Aug 6 19:28:53 2024> +Test run by alx on Tue Aug 6 22:49:12 2024> Native configuration is x86_64-pc-linux-gnu> > === gcc tests ===> @@ -86504,6 +86504,15 @@> PASS: gcc.dg/large-size-array.c (test for errors, line 19)> PASS: gcc.dg/large-size-array.c (test for excess errors)> UNSUPPORTED: gcc.dg/lazy-ptr-test.c> +PASS: gcc.dg/lengthof-compile.c (test for errors, line 11)> +PASS: gcc.dg/lengthof-compile.c (test for errors, line 15)> +PASS: gcc.dg/lengthof-compile.c (test for errors, line 27)> +PASS: gcc.dg/lengthof-compile.c (test for errors, line 42)> +PASS: gcc.dg/lengthof-compile.c (test for errors, line 45)> +PASS: gcc.dg/lengthof-compile.c (test for errors, line 48)> +PASS: gcc.dg/lengthof-compile.c (test for excess errors)> +PASS: gcc.dg/lengthof.c (test for excess errors)> +PASS: gcc.dg/lengthof.c execution test> PASS: gcc.dg/limits-width-1.c (test for excess errors)> PASS: gcc.dg/limits-width-2.c (test for excess errors)> PASS: gcc.dg/live-patching-1.c (test for excess errors)> @@ -204639,7 +204648,7 @@> > === gcc Summary ===> > -# of expected passes 199780> +# of expected passes 199789> # of unexpected failures 31> # of unexpected successes 2> # of expected failures 1463> --- len0/./host-x86_64-pc-linux-gnu/gcc/testsuite/gfortran/gfortran.sum 2024-08-06> +22:22:44.546175561 +0200> +++ len1/./host-x86_64-pc-linux-gnu/gcc/testsuite/gfortran/gfortran.sum 2024-08-06> +23:29:53.877731933 +0200> @@ -1,4 +1,4 @@> -Test run by alx on Tue Aug 6 19:28:53 2024> +Test run by alx on Tue Aug 6 22:49:12 2024> Native configuration is x86_64-pc-linux-gnu> > === gfortran tests ===> --- len0/./host-x86_64-pc-linux-gnu/gcc/testsuite/objc/objc.sum 2024-08-06> +22:22:44.462174752 +0200> +++ len1/./host-x86_64-pc-linux-gnu/gcc/testsuite/objc/objc.sum 2024-08-06> +23:29:53.845731618 +0200> @@ -1,4 +1,4 @@> -Test run by alx on Tue Aug 6 19:28:53 2024> +Test run by alx on Tue Aug 6 22:49:12 2024> Native configuration is x86_64-pc-linux-gnu> > === objc tests ===> --- len0/./host-x86_64-pc-linux-gnu/gcc/testsuite/g++/g++.sum 2024-08-06> +22:22:44.622176292 +0200> +++ len1/./host-x86_64-pc-linux-gnu/gcc/testsuite/g++/g++.sum 2024-08-06> +23:29:53.781730989 +0200> @@ -1,4 +1,4 @@> -Test run by alx on Tue Aug 6 19:28:53 2024> +Test run by alx on Tue Aug 6 22:49:12 2024> Native configuration is x86_64-pc-linux-gnu> > === g++ tests ===> --- len0/./x86_64-pc-linux-gnu/libitm/testsuite/libitm.sum 2024-08-06> +22:22:46.206191541 +0200> +++ len1/./x86_64-pc-linux-gnu/libitm/testsuite/libitm.sum 2024-08-06> +23:29:55.573748613 +0200> @@ -1,4 +1,4 @@> -Test run by alx on Tue Aug 6 19:28:53 2024> +Test run by alx on Tue Aug 6 22:49:12 2024> Native configuration is x86_64-pc-linux-gnu> > === libitm tests ===> --- len0/./x86_64-pc-linux-gnu/libgomp/testsuite/libgomp.sum 2024-08-06> +22:22:45.694186612 +0200> +++ len1/./x86_64-pc-linux-gnu/libgomp/testsuite/libgomp.sum 2024-08-06> +23:29:54.717740194 +0200> @@ -1,4 +1,4 @@> -Test run by alx on Tue Aug 6 19:28:53 2024> +Test run by alx on Tue Aug 6 22:49:12 2024> Native configuration is x86_64-pc-linux-gnu> > === libgomp tests ===> --- len0/./x86_64-pc-linux-gnu/libatomic/testsuite/libatomic.sum 2024-08-06> +22:22:46.110190617 +0200> +++ len1/./x86_64-pc-linux-gnu/libatomic/testsuite/libatomic.sum 2024-08-06> +23:29:55.393746843 +0200> @@ -1,4 +1,4 @@> -Test run by alx on Tue Aug 6 19:28:53 2024> +Test run by alx on Tue Aug 6 22:49:12 2024> Native configuration is x86_64-pc-linux-gnu> > === libatomic tests ===> --- len0/./x86_64-pc-linux-gnu/libstdc++-v3/testsuite/libstdc++.sum 2024-08-06> +22:22:45.998189539 +0200> +++ len1/./x86_64-pc-linux-gnu/libstdc++-v3/testsuite/libstdc++.sum 2024-08-06> +23:29:55.137744325 +0200> @@ -1,4 +1,4 @@> -Test run by alx on Tue Aug 6 19:28:54 2024> +Test run by alx on Tue Aug 6 22:49:13 2024> Native configuration is x86_64-pc-linux-gnu> > === libstdc++ tests ===> > > > > > 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 | 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 | 23 +++++> 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 | 49 +++++++++> gcc/testsuite/gcc.dg/lengthof.c | 127 ++++++++++++++++++++++++> gcc/tree.cc | 17 +++-> gcc/tree.h | 3 +-> 27 files changed, 451 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 v4:> 1: 73010cb4af6 = 1: 73010cb4af6 gcc/: Rename array_type_nelts() => array_type_nelts_minus_one()> 2: 2bb966a0a89 ! 2: 9b835478721 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__, which will be added in the following commit.> +> + gcc/ChangeLog:> +> + * tree.h (array_type_nelts_top):> + * tree.cc (array_type_nelts_top): Define function (moved from> + gcc/cp/).> +> + gcc/cp/ChangeLog:> +> + * cp-tree.h (array_type_nelts_top):> + * tree.cc (array_type_nelts_top): Remove function (move> + to gcc/).> +> + gcc/rust/ChangeLog:> +> + * backend/rust-tree.h (array_type_nelts_top):> + * backend/rust-tree.cc (array_type_nelts_top): Remove function.> > Signed-off-by: Alejandro Colomar <alx@kernel.org>> > 3: e2dbfc43b14 ! 3: af05d01e68d c: Add __lengthof__() operator (n2529)> @@ Metadata> Author: Alejandro Colomar <alx@kernel.org>> > ## Commit message ##> - c: Add __lengthof__() operator (n2529)> + c: Add __lengthof__ operator> > - This operator is similar to sizeof() but can only be applied to an> - array, and returns its length (number of elements).> + This operator is similar to sizeof but can only be applied to an array,> + and returns its length (number of elements).> > 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 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.> > - Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2529.pdf>> - Link: <https://inbox.sourceware.org/gcc/M8S4oQy--3-2@tutanota.com/T/>> - Suggested-by: Xavier Del Campo Romero <xavi.dcr@tutanota.com>> - Co-developed-by: Martin Uecker <uecker@tugraz.at>> - Cc: Gabriel Ravier <gabravier@gmail.com>> Cc: Joseph Myers <josmyers@redhat.com>> + Cc: Gabriel Ravier <gabravier@gmail.com>> Cc: Jakub Jelinek <jakub@redhat.com>> Cc: Kees Cook <keescook@chromium.org>> Cc: Qing Zhao <qing.zhao@oracle.com>> Cc: Jens Gustedt <jens.gustedt@inria.fr>> + Cc: David Brown <david.brown@hesbynett.no>> + Cc: Florian Weimer <fweimer@redhat.com>> + Cc: Andreas Schwab <schwab@linux-m68k.org>> +> + gcc/ChangeLog:> +> + * doc/extend.texi: Document __lengthof__ operator.> + * target.h (enum type_context_kind): Add __lengthof__ operator.> +> + gcc/c-family/ChangeLog:> +> + * c-common.h:> + * c-common.def:> + * c-common.cc (c_lengthof_type): Add __lengthof__ operator.> +> + gcc/c/ChangeLog:> +> + * c-tree.h> + (c_expr_lengthof_expr, c_expr_lengthof_type):> + * c-decl.cc> + (start_struct, finish_struct):> + (start_enum, finish_enum):> + * c-parser.cc> + (c_parser_sizeof_expression):> + (c_parser_lengthof_expression):> + (c_parser_sizeof_or_lengthof_expression):> + (c_parser_unary_expression):> + * c-typeck.cc> + (build_external_ref):> + (record_maybe_used_decl, pop_maybe_used):> + (is_top_array_vla):> + (c_expr_lengthof_expr, c_expr_lengthof_type):> + Add __lengthof__operator.> +> + gcc/cp/ChangeLog:> +> + * operators.def: Add __lengthof__ operator.> +> + gcc/testsuite/ChangeLog:> +> + * gcc.dg/lengthof-compile.c:> + * gcc.dg/lengthof.c: Add tests for __lengthof__ operator.> +> + Link: https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2529.pdf> + Link: https://inbox.sourceware.org/gcc/M8S4oQy--3-2@tutanota.com/T/> + Suggested-by: Xavier Del Campo Romero <xavi.dcr@tutanota.com>> + Co-developed-by: Martin Uecker <uecker@tugraz.at>> Signed-off-by: Alejandro Colomar <alx@kernel.org>> > ## gcc/c-family/c-common.cc ##> @@ gcc/c/c-typeck.cc: int in_alignof;> /* The level of nesting inside "sizeof". */> int in_sizeof;> > -+/* The level of nesting inside "sizeof". */> ++/* The level of nesting inside "lengthof". */> +int in_lengthof;> +> /* The level of nesting inside "typeof". */> @@ gcc/doc/extend.texi: If the operand of the @code{__alignof__} expression is a fu> +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;> ++if the top-level length designator is an integer constant expression> ++(in this case, the operator results in a constant expression);> +and it is evaluated> -+if the top-level length designator is not an integer constant expression.> ++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:> +> -+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.> ++@smallexample> ++__lengthof__ (int [7][n++]); // constexpr> ++__lengthof__ (int [n++][7]); // run-time value> ++@end smallexample> +> @node Inline> @section An Inline Function is As Fast As a Macro> @@ gcc/target.h: enum type_context_kind {> /* Creating objects of type T with static storage duration. */> TCTX_STATIC_STORAGE,> > +> + ## gcc/testsuite/gcc.dg/lengthof-compile.c (new) ##> +@@> ++/* { dg-do compile } */> ++/* { dg-options "-Wno-declaration-after-statement -Wno-pedantic -Wno-vla" } */> ++> ++extern int x[];> ++> ++void> ++incomplete (int p[])> ++{> ++ unsigned n;> ++> ++ n = __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" } */> ++}> ++> ++void> ++fam (void)> ++{> ++ struct {> ++ int x;> ++ int fam[];> ++ } s;> ++ unsigned n;> ++> ++ n = __lengthof__ (s.fam); /* { dg-error "incomplete" } */> ++}> ++> ++void fix_fix (int i, char (*a)[3][5], int (*x)[__lengthof__ (*a)]);> ++void fix_var (int i, char (*a)[3][i], int (*x)[__lengthof__ (*a)]);> ++void fix_uns (int i, char (*a)[3][*], int (*x)[__lengthof__ (*a)]);> ++> ++void> ++func (void)> ++{> ++ int i3[3];> ++ int i5[5];> ++ char c35[3][5];> ++> ++ fix_fix (5, &c35, &i3);> ++ fix_fix (5, &c35, &i5); /* { dg-error "incompatible-pointer-types" } */> ++> ++ fix_var (5, &c35, &i3);> ++ fix_var (5, &c35, &i5); /* { dg-error "incompatible-pointer-types" } */> ++> ++ fix_uns (5, &c35, &i3);> ++ fix_uns (5, &c35, &i5); /* { dg-error "incompatible-pointer-types" } */> ++}> +> + ## gcc/testsuite/gcc.dg/lengthof.c (new) ##> +@@> ++/* { dg-do run } */> ++/* { dg-options "-Wno-declaration-after-statement -Wno-pedantic -Wno-vla" } */> ++> ++#undef NDEBUG> ++#include <assert.h>> ++> ++void> ++array (void)> ++{> ++ short a[7];> ++> ++ assert (__lengthof__ (a) == 7);> ++ assert (__lengthof__ (long [0]) == 0);> ++ assert (__lengthof__ (unsigned [99]) == 99);> ++}> ++> ++void> ++vla (void)> ++{> ++ unsigned n;> ++> ++ n = 99;> ++ assert (__lengthof__ (short [n - 10]) == 99 - 10);> ++> ++ int v[n / 2];> ++ assert (__lengthof__ (v) == 99 / 2);> ++> ++ n = 0;> ++ int z[n];> ++ assert (__lengthof__ (z) == 0);> ++}> ++> ++void> ++member (void)> ++{> ++ struct {> ++ int a[8];> ++ } s;> ++> ++ assert (__lengthof__ (s.a) == 8);> ++}> ++> ++void> ++vla_eval (void)> ++{> ++ int i;> ++> ++ i = 7;> ++ assert (__lengthof__ (struct {int x;}[i++]) == 7);> ++ assert (i == 7 + 1);> ++> ++ int v[i];> ++ int (*p)[i];> ++ p = &v;> ++ assert (__lengthof__ (*p++) == i);> ++ assert (p - 1 == &v);> ++}> ++> ++void> ++inner_vla_noeval (void)> ++{> ++ int i;> ++> ++ i = 3;> ++ assert (__lengthof__ (struct {int x[i++];}[3]) == 3);> ++ assert (i == 3);> ++}> ++> ++void> ++array_noeval (void)> ++{> ++ long a[5];> ++ long (*p)[__lengthof__ (a)];> ++> ++ p = &a;> ++ assert (__lengthof__ (*p++) == 5);> ++ assert (p == &a);> ++}> ++> ++void> ++matrix_zero (void)> ++{> ++ int i;> ++> ++ assert (__lengthof__ (int [0][4]) == 0);> ++ i = 3;> ++ assert (__lengthof__ (int [0][i]) == 0);> ++}> ++> ++void> ++matrix_fixed (void)> ++{> ++ int i;> ++> ++ assert (__lengthof__ (int [7][4]) == 7);> ++ i = 3;> ++ assert (__lengthof__ (int [7][i]) == 7);> ++}> ++> ++void> ++matrix_vla (void)> ++{> ++ int i, j;> ++> ++ i = 7;> ++ assert (__lengthof__ (int [i++][4]) == 7);> ++ assert (i == 7 + 1);> ++> ++ i = 9;> ++ j = 3;> ++ assert (__lengthof__ (int [i++][j]) == 9);> ++ assert (i == 9 + 1);> ++}> ++> ++int> ++main (void)> ++{> ++ array ();> ++ vla ();> ++ member ();> ++ vla_eval ();> ++ inner_vla_noeval ();> ++ array_noeval ();> ++ matrix_zero ();> ++ matrix_fixed ();> ++ matrix_vla ();> ++}> 4: 9a691f7f208 < -: ----------- testsuite: Add tests for __lengthof__> -- > 2.45.2> -- <https://www.alejandro-colomar.es/>
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [PATCH v5 0/3] c: Add __lengthof__ operator
[not found] ` <20240807081133.395C7C32782@smtp.kernel.org>
@ 2024-08-07 8:30 ` Alejandro Colomar
0 siblings, 0 replies; 248+ messages in thread
From: Alejandro Colomar @ 2024-08-07 8:30 UTC (permalink / raw)
To: david.brown
Cc: gcc-patches, Martin Uecker, Xavier Del Campo Romero,
Joseph Myers, Gabriel Ravier, Jakub Jelinek, Kees Cook,
Qing Zhao, Jens Gustedt, Florian Weimer, Andreas Schwab
[-- Attachment #1: Type: text/plain, Size: 1972 bytes --]
Hi David,
On Wed, Aug 07, 2024 at 10:11:12AM GMT, david.brown wrote:
> Hi,The address david.brown@hesbynett.no is not bouncing. Its my email
> address, and I'm getting the emails in this discussion just fine.
Ahh, sorry, I didn't read the bounce notification properly; the address
is indeed reachable, but it rejected some message as spam (and notified
me, which is the first time I see that happen:).
(At the bottom I pasted part of the report I received.)
Thanks for replying!
> However, I don't think I have anything to contribute here, so I don't
> object to being removed from the discussion. I am not a gcc developer,
> but as a long term user I occasionally post on the developer mailing
> list. I don't remember having posted about a potential __lengthof__
> operator, but it is certainly possible.
You did post 4 years ago:
<https://inbox.sourceware.org/gcc/23d3556f-6829-789d-49ba-0551dfa4cfd5@hesbynett.no/>
<https://inbox.sourceware.org/gcc/6f8be1ed-4d76-dbf3-f19a-e9105f7450d4@hesbynett.no/>
I will keep you on CC, unless you expressely want to be remvoved. ;)
> On behalf of all gcc users, thank you for your efforts in working to
> improve gcc, no matter how this proposal turns out.
Thanks!
> Mvh.,David Browndavid.brown@hesbynett.no
Have a lovely day!
Alex
---
This is the mail system at host dfw.source.kernel.org.
I'm sorry to have to inform you that your message could not
be delivered to one or more recipients. It's attached below.
For further assistance, please send mail to postmaster.
If you do so, please include this problem report. You can
delete your own text from the attached returned message.
The mail system
<david.brown@hesbynett.no>: host spam01.hesbynett.no[81.29.32.152] said: 550
5.7.1 Rejected by spam filter (4cb5907b-5449-11ef-98be-506b8dfa0e58) (in
reply to end of DATA command)
--
<https://www.alejandro-colomar.es/>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [PATCH v5 3/3] c: Add __lengthof__ operator
2024-08-07 7:13 ` Martin Uecker
@ 2024-08-07 9:14 ` Alejandro Colomar
2024-08-07 10:07 ` Martin Uecker
0 siblings, 1 reply; 248+ messages in thread
From: Alejandro Colomar @ 2024-08-07 9:14 UTC (permalink / raw)
To: Martin Uecker; +Cc: gcc-patches, Joseph Myers
[-- Attachment #1: Type: text/plain, Size: 3344 bytes --]
Hi Martin,
On Wed, Aug 07, 2024 at 09:13:07AM GMT, Martin Uecker wrote:
> Am Mittwoch, dem 07.08.2024 um 01:12 +0200 schrieb Alejandro Colomar:
> > +#define c_parser_lengthof_expression(parser) \
> > +( \
> > + c_parser_sizeof_or_lengthof_expression (parser, RID_LENGTHOF) \
> > +)
> > +\f
>
> I suggest to avoid the macros. I think the original function calls are
> clear enough and this is then just another detour for somebody trying
> to follow the code. Or is there a reason I am missing?
I imitated the following ones that already exist:
c-family/c-common.h:923:
#define c_sizeof(LOC, T) c_sizeof_or_alignof_type (LOC, T, true, false, 1)
cp/cp-tree.h:8318:
#define cxx_sizeof(T) cxx_sizeof_or_alignof_type (input_location, T, SIZEOF_EXPR, false, true)
c-family/c-common.h:924:
#define c_alignof(LOC, T) c_sizeof_or_alignof_type (LOC, T, false, false, 1)
But I'm fine using it raw.
> > +void fix_fix (int i, char (*a)[3][5], int (*x)[__lengthof__ (*a)]);
> > +void fix_var (int i, char (*a)[3][i], int (*x)[__lengthof__ (*a)]);
> > +void fix_uns (int i, char (*a)[3][*], int (*x)[__lengthof__ (*a)]);
>
>
> It would include a test that shows that when lengthof
> is applied to [*] that it remains formally non-constant. For example,
> you could test with -Wvla-parameter that the two declarations do not give a
> warning:
>
> void foo(char (*a)[*], int x[*]);
> void foo(char (*a)[*], int x[__lengthof__(*a)]);
But [*] is a VLA. Do we want to return a constexpr for it?
> (With int (*x)[*] we would run into the issue that we can not
> distinguish zero arrays from unspecified ones, PR 98539)
As Martin Sebor said, I need to choose between supporting well [0] or
supporting well [*], but not both.
I would personally prefer supporting [0], and consider that not
supporting [*] is a bug in the implementation of [*] (and thus not my
problem).
However, since GCC doesn't support 0-length arrays, I'm not sure that
would be correct.
What do you think?
Does anyone oppose treating [0] as a constexpr 0 length? That means not
supporting well [*], but please fix it separately, which Martin Uecker
is working on. :)
> > diff --git a/gcc/testsuite/gcc.dg/lengthof.c b/gcc/testsuite/gcc.dg/lengthof.c
> > new file mode 100644
> > index 00000000000..38da5df52a5
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.dg/lengthof.c
> > @@ -0,0 +1,127 @@
> > +/* { dg-do run } */
> > +/* { dg-options "-Wno-declaration-after-statement -Wno-pedantic -Wno-vla" } */
> > +
> > +#undef NDEBUG
> > +#include <assert.h>
> > +
> > +void
> > +array (void)
> > +{
> > + short a[7];
> > +
> > + assert (__lengthof__ (a) == 7);
> > + assert (__lengthof__ (long [0]) == 0);
> > + assert (__lengthof__ (unsigned [99]) == 99);
> > +}
>
> Instead of using assert you can use
>
> if (! ...) __builtin_abort();
>
> to avoid the include in the testsuite.
Is it frowned upon to include something? I prefer assert(3).
> Otherwise it looks fine from my side.
>
> Joseph needs to approve and may have more comments.
Thanks!
>
> Martin
Have a lovely day!
Alex
--
<https://www.alejandro-colomar.es/>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [PATCH v5 3/3] c: Add __lengthof__ operator
2024-08-07 9:14 ` Alejandro Colomar
@ 2024-08-07 10:07 ` Martin Uecker
2024-08-07 22:09 ` Alejandro Colomar
0 siblings, 1 reply; 248+ messages in thread
From: Martin Uecker @ 2024-08-07 10:07 UTC (permalink / raw)
To: Alejandro Colomar; +Cc: gcc-patches, Joseph Myers
Am Mittwoch, dem 07.08.2024 um 11:14 +0200 schrieb Alejandro Colomar:
> Hi Martin,
>
> > > +void fix_fix (int i, char (*a)[3][5], int (*x)[__lengthof__ (*a)]);
> > > +void fix_var (int i, char (*a)[3][i], int (*x)[__lengthof__ (*a)]);
> > > +void fix_uns (int i, char (*a)[3][*], int (*x)[__lengthof__ (*a)]);
> >
> >
> > It would include a test that shows that when lengthof
> > is applied to [*] that it remains formally non-constant. For example,
> > you could test with -Wvla-parameter that the two declarations do not give a
> > warning:
> >
> > void foo(char (*a)[*], int x[*]);
> > void foo(char (*a)[*], int x[__lengthof__(*a)]);
>
> But [*] is a VLA. Do we want to return a constexpr for it?
No, my point is only that we could have a test for not
returning a constant.
If __lengthof__ would incorrectly return an integer constant
expression then you would get a warning with -Wvla-parameter. So
adding these two declarations to the tests and activating
the warning would ensure that the int[__lengthof__(*a)]
is a VLA: https://godbolt.org/z/7P7qW15ah
>
> > (With int (*x)[*] we would run into the issue that we can not
> > distinguish zero arrays from unspecified ones, PR 98539)
>
> As Martin Sebor said, I need to choose between supporting well [0] or
> supporting well [*], but not both.
If you have only one array index this works. (and should
already work correctly with your patch)
>
> I would personally prefer supporting [0], and consider that not
> supporting [*] is a bug in the implementation of [*] (and thus not my
> problem).
>
> However, since GCC doesn't support 0-length arrays, I'm not sure that
> would be correct.
>
> What do you think?
I think the logic in your patch is OK as is. It does not exactly
what you want, as it now treats some [0] as [*] but I would not
make the logic more complex here when we will fix it properly
anyway.
>
> Does anyone oppose treating [0] as a constexpr 0 length? That means not
> supporting well [*], but please fix it separately, which Martin Uecker
> is working on. :)
>
> > > diff --git a/gcc/testsuite/gcc.dg/lengthof.c b/gcc/testsuite/gcc.dg/lengthof.c
> > > new file mode 100644
> > > index 00000000000..38da5df52a5
> > > --- /dev/null
> > > +++ b/gcc/testsuite/gcc.dg/lengthof.c
> > > @@ -0,0 +1,127 @@
> > > +/* { dg-do run } */
> > > +/* { dg-options "-Wno-declaration-after-statement -Wno-pedantic -Wno-vla" } */
> > > +
> > > +#undef NDEBUG
> > > +#include <assert.h>
> > > +
> > > +void
> > > +array (void)
> > > +{
> > > + short a[7];
> > > +
> > > + assert (__lengthof__ (a) == 7);
> > > + assert (__lengthof__ (long [0]) == 0);
> > > + assert (__lengthof__ (unsigned [99]) == 99);
> > > +}
> >
> > Instead of using assert you can use
> >
> > if (! ...) __builtin_abort();
> >
> > to avoid the include in the testsuite.
>
> Is it frowned upon to include something? I prefer assert(3).
It makes the tests run faster. At least people told me before
to avoid includes in tests for this reason. But from my side
assert is ok too.
Martin
>
> > Otherwise it looks fine from my side.
> >
> > Joseph needs to approve and may have more comments.
>
> Thanks!
>
> >
> > Martin
>
> Have a lovely day!
> Alex
>
--
Univ.-Prof. Dr. rer. nat. Martin Uecker
Graz University of Technology
Institute of Biomedical Imaging
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [PATCH v5 3/3] c: Add __lengthof__ operator
2024-08-06 23:12 ` [PATCH v5 3/3] c: Add __lengthof__ operator Alejandro Colomar
2024-08-06 23:14 ` Alejandro Colomar
2024-08-07 7:13 ` Martin Uecker
@ 2024-08-07 15:05 ` Joseph Myers
2024-08-07 15:30 ` Jens Gustedt
2 siblings, 1 reply; 248+ messages in thread
From: Joseph Myers @ 2024-08-07 15:05 UTC (permalink / raw)
To: Alejandro Colomar
Cc: gcc-patches, Martin Uecker, Xavier Del Campo Romero,
Gabriel Ravier, Jakub Jelinek, Kees Cook, Qing Zhao,
Jens Gustedt, David Brown, Florian Weimer, Andreas Schwab
On Wed, 7 Aug 2024, Alejandro Colomar wrote:
> +@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}.
> +The operand must be a complete array type.
I think you mean the operand must be *an expression whose type is a
complete array type* or *a type name for a complete array type*. The
wording you have suggests only type names, you need to be clear about both
kinds of operands being possible (and include examples for them).
> +@smallexample
> +__lengthof__ (int [7][n++]); // constexpr
> +__lengthof__ (int [n++][7]); // run-time value
> +@end smallexample
I don't think using "constexpr" to mean "constant expression" is a good
idea, they're different things.
> +void
> +incomplete (int p[])
> +{
> + unsigned n;
> +
> + n = __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" } */
This seems to be the only test you have for a non-array operand. I'd
expect such tests (both for type name operands and for expression
operands) covering cases that we *don't* want to support in future, not
just this one that we would like to be supportable in future.
I don't see any tests for the constraints on external definitions from
6.9.1 that we discussed - that referenced to undefined internal linkage
identifiers are OK inside __lengthof__ returning a constant (both
constant-length arrays of non-VLA and constant-length arrays of VLA) but
not in the cases where __lengthof__ is evaluated.
--
Joseph S. Myers
josmyers@redhat.com
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [PATCH v5 3/3] c: Add __lengthof__ operator
2024-08-07 15:05 ` Joseph Myers
@ 2024-08-07 15:30 ` Jens Gustedt
2024-08-07 22:44 ` Alejandro Colomar
0 siblings, 1 reply; 248+ messages in thread
From: Jens Gustedt @ 2024-08-07 15:30 UTC (permalink / raw)
To: Joseph Myers, Alejandro Colomar
Cc: gcc-patches, Martin Uecker, Xavier Del Campo Romero,
Gabriel Ravier, Jakub Jelinek, Kees Cook, Qing Zhao, David Brown,
Florian Weimer, Andreas Schwab
Hi
Am 7. August 2024 17:05:48 MESZ schrieb Joseph Myers <josmyers@redhat.com>:
> On Wed, 7 Aug 2024, Alejandro Colomar wrote:
>
> > +@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}.
> > +The operand must be a complete array type.
>
> I think you mean the operand must be *an expression whose type is a
> complete array type* or *a type name for a complete array type*. The
> wording you have suggests only type names, you need to be clear about both
> kinds of operands being possible (and include examples for them).
>
> > +@smallexample
> > +__lengthof__ (int [7][n++]); // constexpr
> > +__lengthof__ (int [n++][7]); // run-time value
> > +@end smallexample
>
> I don't think using "constexpr" to mean "constant expression" is a good
> idea, they're different things.
It should actually state "integer constant expression", I think. the nuance is probably important
> > +void
> > +incomplete (int p[])
> > +{
> > + unsigned n;
> > +
> > + n = __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" } */
>
> This seems to be the only test you have for a non-array operand. I'd
> expect such tests (both for type name operands and for expression
> operands) covering cases that we *don't* want to support in future, not
> just this one that we would like to be supportable in future.
>
> I don't see any tests for the constraints on external definitions from
> 6.9.1 that we discussed - that referenced to undefined internal linkage
> identifiers are OK inside __lengthof__ returning a constant (both
> constant-length arrays of non-VLA and constant-length arrays of VLA) but
> not in the cases where __lengthof__ is evaluated.
>
--
Jens Gustedt - INRIA & ICube, Strasbourg, France
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [PATCH v5 3/3] c: Add __lengthof__ operator
2024-08-07 10:07 ` Martin Uecker
@ 2024-08-07 22:09 ` Alejandro Colomar
2024-08-08 7:39 ` Martin Uecker
0 siblings, 1 reply; 248+ messages in thread
From: Alejandro Colomar @ 2024-08-07 22:09 UTC (permalink / raw)
To: Martin Uecker; +Cc: gcc-patches, Joseph Myers
[-- Attachment #1: Type: text/plain, Size: 6937 bytes --]
Hi Martin,
On Wed, Aug 07, 2024 at 12:07:00PM GMT, Martin Uecker wrote:
> > > void foo(char (*a)[*], int x[*]);
> > > void foo(char (*a)[*], int x[__lengthof__(*a)]);
> >
> > But [*] is a VLA. Do we want to return a constexpr for it?
>
> No, my point is only that we could have a test for not
> returning a constant.
Ok.
>
> If __lengthof__ would incorrectly return an integer constant
> expression then you would get a warning with -Wvla-parameter. So
> adding these two declarations to the tests and activating
> the warning would ensure that the int[__lengthof__(*a)]
> is a VLA: https://godbolt.org/z/7P7qW15ah
>
> >
> > > (With int (*x)[*] we would run into the issue that we can not
> > > distinguish zero arrays from unspecified ones, PR 98539)
> >
> > As Martin Sebor said, I need to choose between supporting well [0] or
> > supporting well [*], but not both.
>
> If you have only one array index this works. (and should
> already work correctly with your patch)
I've been thinking today that I'll add full support for [0], and let [*]
broken.
I'll also add tests for it.
>
> >
> > I would personally prefer supporting [0], and consider that not
> > supporting [*] is a bug in the implementation of [*] (and thus not my
> > problem).
> >
> > However, since GCC doesn't support 0-length arrays, I'm not sure that
> > would be correct.
> >
> > What do you think?
>
> I think the logic in your patch is OK as is. It does not exactly
> what you want, as it now treats some [0] as [*] but I would not
> make the logic more complex here when we will fix it properly
> anyway.
I'm detecting some issues with my patches.
$ cat zero.c
static int A[__lengthof__(int [0])];
static int B[__lengthof__(A)];
static int C[0];
static int D[__lengthof__(C)];
void fa(char (*a)[3][*], int (*x)[__lengthof__(*a)]); // x: array
void fb(char (*a)[*][3], int (*x)[__lengthof__(*a)]); // x: vla
void fc(char (*a)[3], int (*x)[__lengthof__(*a)]); // x: array
void fd(char (*a)[0], int (*x)[__lengthof__(*a)]); // x: ?
void fe(char (*a)[*], int (*x)[__lengthof__(*a)]); // x: vla
void ff(char (*a)[*], int (*x)[*]); // x: array
static int W[1];
static int X[__lengthof__(W)];
static int Y[0];
static int Z[__lengthof__(Y)];
$ /opt/local/gnu/gcc/lengthof/bin/gcc zero.c
zero.c:18:12: error: variably modified ‘Z’ at file scope
18 | static int Z[__lengthof__(Y)];
| ^
See that D, which is identical to Z, does not cause an error.
There's one case of [0] resulting in a constant expression, and another
in a VLA. Can you please help investigate why it's happening?
I've added the following change on top of v5 to see some debugging info:
diff --git i/gcc/c/c-typeck.cc w/gcc/c/c-typeck.cc
index 98e8d31cb3b..9e05ee01a4a 100644
--- i/gcc/c/c-typeck.cc
+++ w/gcc/c/c-typeck.cc
@@ -3462,6 +3462,8 @@ is_top_array_vla (tree type)
bool zero, var;
tree d;
+fprintf(stderr, "ALX: %s(): %d\n", __func__, __LINE__);
+
if (TREE_CODE (type) != ARRAY_TYPE)
return false;
if (!COMPLETE_TYPE_P (type))
@@ -3469,10 +3471,14 @@ is_top_array_vla (tree type)
d = TYPE_DOMAIN (type);
zero = !TYPE_MAX_VALUE (d);
+fprintf(stderr, "ALX: zero: %d\n", !!zero);
var = (!zero
&& (TREE_CODE (TYPE_MIN_VALUE (d)) != INTEGER_CST
|| TREE_CODE (TYPE_MAX_VALUE (d)) != INTEGER_CST));
+fprintf(stderr, "ALX: var: %d\n", !!var);
var = var || (zero && C_TYPE_VARIABLE_SIZE (type));
+fprintf(stderr, "ALX: var: %d\n", !!var);
return var;
}
@@ -3481,6 +3487,7 @@ is_top_array_vla (tree type)
struct c_expr
c_expr_lengthof_expr (location_t loc, struct c_expr expr)
{
+fprintf(stderr, "ALX: %s(): %d\n", __func__, __LINE__);
struct c_expr ret;
if (expr.value == error_mark_node)
{
@@ -3522,6 +3529,7 @@ c_expr_lengthof_expr (location_t loc, struct c_expr expr)
struct c_expr
c_expr_lengthof_type (location_t loc, struct c_type_name *t)
{
+fprintf(stderr, "ALX: %s(): %d\n", __func__, __LINE__);
tree type;
struct c_expr ret;
tree type_expr = NULL_TREE;
which prints:
$ /opt/local/gnu/gcc/lengthof/bin/gcc zero.c
ALX: c_expr_lengthof_type(): 3531
ALX: is_top_array_vla(): 3465
ALX: zero: 1
ALX: var: 0
ALX: var: 0
ALX: is_top_array_vla(): 3465
ALX: zero: 1
ALX: var: 0
ALX: var: 0
ALX: c_expr_lengthof_expr(): 3489
ALX: is_top_array_vla(): 3465
ALX: zero: 1
ALX: var: 0
ALX: var: 0
ALX: is_top_array_vla(): 3465
ALX: zero: 1
ALX: var: 0
ALX: var: 0
ALX: c_expr_lengthof_expr(): 3489
ALX: is_top_array_vla(): 3465
ALX: zero: 1
ALX: var: 0
ALX: var: 0
ALX: is_top_array_vla(): 3465
ALX: zero: 1
ALX: var: 0
ALX: var: 0
ALX: c_expr_lengthof_expr(): 3489
ALX: is_top_array_vla(): 3465
ALX: zero: 0
ALX: var: 0
ALX: var: 0
ALX: is_top_array_vla(): 3465
ALX: zero: 0
ALX: var: 0
ALX: var: 0
ALX: c_expr_lengthof_expr(): 3489
ALX: is_top_array_vla(): 3465
ALX: zero: 1
ALX: var: 0
ALX: var: 1
ALX: is_top_array_vla(): 3465
ALX: zero: 1
ALX: var: 0
ALX: var: 1
ALX: c_expr_lengthof_expr(): 3489
ALX: is_top_array_vla(): 3465
ALX: zero: 0
ALX: var: 0
ALX: var: 0
ALX: is_top_array_vla(): 3465
ALX: zero: 0
ALX: var: 0
ALX: var: 0
ALX: c_expr_lengthof_expr(): 3489
ALX: is_top_array_vla(): 3465
ALX: zero: 1
ALX: var: 0
ALX: var: 1
ALX: is_top_array_vla(): 3465
ALX: zero: 1
ALX: var: 0
ALX: var: 1
ALX: c_expr_lengthof_expr(): 3489
ALX: is_top_array_vla(): 3465
ALX: zero: 1
ALX: var: 0
ALX: var: 1
ALX: is_top_array_vla(): 3465
ALX: zero: 1
ALX: var: 0
ALX: var: 1
ALX: c_expr_lengthof_expr(): 3489
ALX: is_top_array_vla(): 3465
ALX: zero: 0
ALX: var: 0
ALX: var: 0
ALX: is_top_array_vla(): 3465
ALX: zero: 0
ALX: var: 0
ALX: var: 0
ALX: c_expr_lengthof_expr(): 3489
ALX: is_top_array_vla(): 3465
ALX: zero: 1
ALX: var: 0
ALX: var: 1
ALX: is_top_array_vla(): 3465
ALX: zero: 1
ALX: var: 0
ALX: var: 1
zero.c:18:12: error: variably modified ‘Z’ at file scope
18 | static int Z[__lengthof__(Y)];
| ^
If I make [0] always result in a constant expression (and thus break
some [*] cases), by doing
- var = var || (zero && C_TYPE_VARIABLE_SIZE (type));
Then the problem disappears. But I'm worried that it might be hiding
the problem instead of removing it, since I don't really understand why
it's happening. Do you know why?
Anyway, I'll remove that line to support [0]. But it would be
interesting to learn why this problem triggers.
Have a lovely night!
Alex
--
<https://www.alejandro-colomar.es/>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [PATCH v5 3/3] c: Add __lengthof__ operator
2024-08-07 15:30 ` Jens Gustedt
@ 2024-08-07 22:44 ` Alejandro Colomar
2024-08-08 5:35 ` Jₑₙₛ Gustedt
0 siblings, 1 reply; 248+ messages in thread
From: Alejandro Colomar @ 2024-08-07 22:44 UTC (permalink / raw)
To: Jens Gustedt
Cc: Joseph Myers, gcc-patches, Martin Uecker,
Xavier Del Campo Romero, Gabriel Ravier, Jakub Jelinek,
Kees Cook, Qing Zhao, David Brown, Florian Weimer,
Andreas Schwab
[-- Attachment #1: Type: text/plain, Size: 2943 bytes --]
Hi Jens, Joseph,
On Wed, Aug 07, 2024 at 05:30:13PM GMT, Jens Gustedt wrote:
> Hi
>
> Am 7. August 2024 17:05:48 MESZ schrieb Joseph Myers <josmyers@redhat.com>:
> > On Wed, 7 Aug 2024, Alejandro Colomar wrote:
> >
> > > +@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}.
> > > +The operand must be a complete array type.
> >
> > I think you mean the operand must be *an expression whose type is a
> > complete array type* or *a type name for a complete array type*. The
> > wording you have suggests only type names, you need to be clear about both
> > kinds of operands being possible (and include examples for them).
I've written the following for v6:
-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
+
> >
> > > +@smallexample
> > > +__lengthof__ (int [7][n++]); // constexpr
> > > +__lengthof__ (int [n++][7]); // run-time value
> > > +@end smallexample
> >
> > I don't think using "constexpr" to mean "constant expression" is a good
> > idea, they're different things.
>
> It should actually state "integer constant expression", I think. the nuance is probably important
Agree.
>
>
> > > +void
> > > +incomplete (int p[])
> > > +{
> > > + unsigned n;
> > > +
> > > + n = __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" } */
> >
> > This seems to be the only test you have for a non-array operand. I'd
> > expect such tests (both for type name operands and for expression
> > operands) covering cases that we *don't* want to support in future, not
> > just this one that we would like to be supportable in future.
> >
> > I don't see any tests for the constraints on external definitions from
> > 6.9.1 that we discussed - that referenced to undefined internal linkage
> > identifiers are OK inside __lengthof__ returning a constant (both
> > constant-length arrays of non-VLA and constant-length arrays of VLA) but
> > not in the cases where __lengthof__ is evaluated.
> >
I think I've added them for v6. (Please let me know if anything is
still untested there.) I'll publish v6 after I test for regressions.
Have a lovely night!
Alex
--
<https://www.alejandro-colomar.es/>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [PATCH v5 3/3] c: Add __lengthof__ operator
2024-08-07 22:44 ` Alejandro Colomar
@ 2024-08-08 5:35 ` Jₑₙₛ Gustedt
2024-08-08 8:26 ` Alejandro Colomar
0 siblings, 1 reply; 248+ messages in thread
From: Jₑₙₛ Gustedt @ 2024-08-08 5:35 UTC (permalink / raw)
To: Alejandro Colomar
Cc: Joseph Myers, gcc-patches, Martin Uecker,
Xavier Del Campo Romero, Gabriel Ravier, Jakub Jelinek,
Kees Cook, Qing Zhao, David Brown, Florian Weimer,
Andreas Schwab
[-- Attachment #1: Type: text/plain, Size: 799 bytes --]
Hello Alejandro,
On Thu, 8 Aug 2024 00:44:02 +0200, Alejandro Colomar wrote:
> +Its syntax is similar to @code{sizeof}.
For my curiosity, do you also make the same distinction that with
expressions you may omit the parenthesis?
I wouldn't be sure that we should continue that distinction from
`sizeof`. Also that prefix variant would be difficult to wrap in a
`lengthof` macro (without underscores) as we would probably like to
have it in the end.
Thanks
Jₑₙₛ
--
:: ICube :::::::::::::::::::::::::::::: deputy director ::
:: Université de Strasbourg :::::::::::::::::::::: ICPS ::
:: INRIA antenne de Strasbourg :::::::::::::::::: Camus ::
:: :::::::::::::::::::::::::::::::::::: ☎ +33 368854536 ::
:: https://icube-icps.unistra.fr/index.php/Jens_Gustedt ::
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 195 bytes --]
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [PATCH v5 3/3] c: Add __lengthof__ operator
2024-08-07 22:09 ` Alejandro Colomar
@ 2024-08-08 7:39 ` Martin Uecker
2024-08-08 8:42 ` Alejandro Colomar
0 siblings, 1 reply; 248+ messages in thread
From: Martin Uecker @ 2024-08-08 7:39 UTC (permalink / raw)
To: Alejandro Colomar; +Cc: gcc-patches, Joseph Myers
Am Donnerstag, dem 08.08.2024 um 00:09 +0200 schrieb Alejandro Colomar:
> Hi Martin,
> >
...
> > >
> > > I would personally prefer supporting [0], and consider that not
> > > supporting [*] is a bug in the implementation of [*] (and thus not my
> > > problem).
> > >
> > > However, since GCC doesn't support 0-length arrays, I'm not sure that
> > > would be correct.
> > >
> > > What do you think?
> >
> > I think the logic in your patch is OK as is. It does not exactly
> > what you want, as it now treats some [0] as [*] but I would not
> > make the logic more complex here when we will fix it properly
> > anyway.
>
> I'm detecting some issues with my patches.
>
> $ cat zero.c
> static int A[__lengthof__(int [0])];
> static int B[__lengthof__(A)];
>
> static int C[0];
> static int D[__lengthof__(C)];
>
> void fa(char (*a)[3][*], int (*x)[__lengthof__(*a)]); // x: array
> void fb(char (*a)[*][3], int (*x)[__lengthof__(*a)]); // x: vla
> void fc(char (*a)[3], int (*x)[__lengthof__(*a)]); // x: array
> void fd(char (*a)[0], int (*x)[__lengthof__(*a)]); // x: ?
> void fe(char (*a)[*], int (*x)[__lengthof__(*a)]); // x: vla
> void ff(char (*a)[*], int (*x)[*]); // x: array
>
>
> static int W[1];
> static int X[__lengthof__(W)];
> static int Y[0];
> static int Z[__lengthof__(Y)];
>
> $ /opt/local/gnu/gcc/lengthof/bin/gcc zero.c
> zero.c:18:12: error: variably modified ‘Z’ at file scope
> 18 | static int Z[__lengthof__(Y)];
> | ^
>
>
> See that D, which is identical to Z, does not cause an error.
> There's one case of [0] resulting in a constant expression, and another
> in a VLA. Can you please help investigate why it's happening?
This seems to be another bug where we incorrectly set
C_TYPE_VARIABLE_SIZE and this also affects sizeof:
https://godbolt.org/z/a8Ej6c5jr
Strangely it seems related to the function declaration
with the unspecified size before. I will look into this,
I am just working on some checking functions that make sure
that those bits are consistent all the time because I also
missed some cases where I need to set C_TYPE_VARIABLY_MODIFIED
I filed a new bug:
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=116284
...
> | ^
>
> If I make [0] always result in a constant expression (and thus break
> some [*] cases), by doing
>
> - var = var || (zero && C_TYPE_VARIABLE_SIZE (type));
>
> Then the problem disappears. But I'm worried that it might be hiding
> the problem instead of removing it, since I don't really understand why
> it's happening. Do you know why?
>
> Anyway, I'll remove that line to support [0]. But it would be
> interesting to learn why this problem triggers.
You need the line to support variable size arrays. Please just uncomment
your test with a reference to the bug for now and I will try fix this ASAP.
Martin
> Alex
>
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [PATCH v5 3/3] c: Add __lengthof__ operator
2024-08-08 5:35 ` Jₑₙₛ Gustedt
@ 2024-08-08 8:26 ` Alejandro Colomar
2024-08-08 9:13 ` Jens Gustedt
0 siblings, 1 reply; 248+ messages in thread
From: Alejandro Colomar @ 2024-08-08 8:26 UTC (permalink / raw)
To: Jₑₙₛ Gustedt
Cc: Joseph Myers, gcc-patches, Martin Uecker,
Xavier Del Campo Romero, Gabriel Ravier, Jakub Jelinek,
Kees Cook, Qing Zhao, David Brown, Florian Weimer,
Andreas Schwab
[-- Attachment #1: Type: text/plain, Size: 2354 bytes --]
Hello Jens,
On Thu, Aug 08, 2024 at 07:35:12AM GMT, Jₑₙₛ Gustedt wrote:
> Hello Alejandro,
>
> On Thu, 8 Aug 2024 00:44:02 +0200, Alejandro Colomar wrote:
>
> > +Its syntax is similar to @code{sizeof}.
>
> For my curiosity, do you also make the same distinction that with
> expressions you may omit the parenthesis?
I thought of it. TBH, I haven't tested that thoroughly.
In principle, I have implemented it in the same way as sizeof, yes.
Personally, I would have never allowed sizeof without parentheses, but I
understand there are people who think the parentheses hurt readability,
so I kept it in the same way.
I'm not sure why the parentheses are necessary with type names in
sizeof, but to maintain expectations, I think it would be better to do
the same here.
>
> I wouldn't be sure that we should continue that distinction from
> `sizeof`.
But then, what do we do? Allow lengthof with type names without parens?
Or require parens? I'm not comfortable with that choice.
> Also that prefix variant would be difficult to wrap in a
> `lengthof` macro (without underscores) as we would probably like to
> have it in the end.
Do you mean that I should add _Lengthof? We're adding __lengthof__ to
be a GNU extension with relative freedom from ISO. If I sent a patch
adding _Lengthof, we'd have to send a proposal to ISO at the same time,
and we'd be waiting for ISO to discuss it before I can merge it. And we
couldn't bring prior art to ISO.
With this approach instead, the plan is:
- Merge __lengthof__ in GCC before ISO hears of it (well, there are
already several WG14 members in this discussion, so you have actually
heard of it, but we're free to do more or less what we want).
- Propose _Lengthof to ISO C, with prior art in GCC as __lengthof__,
proposing the same semantics. Also propose a lengthof macro defined
in <stdlength.h>
- When ISO C accepts _Lengthof and lengthof, map _Lengthof in GCC to
the same internals as __lengthof__, so they are the same thing.
Still, I'm interested in having some feedback from WG14, to prevent
implementing something that will have modifications when merged to
ISO C, so please CC anyone interested from WG14, if you know of any.
Have a lovely day!
Alex
--
<https://www.alejandro-colomar.es/>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [PATCH v5 3/3] c: Add __lengthof__ operator
2024-08-08 7:39 ` Martin Uecker
@ 2024-08-08 8:42 ` Alejandro Colomar
2024-08-08 9:23 ` Martin Uecker
0 siblings, 1 reply; 248+ messages in thread
From: Alejandro Colomar @ 2024-08-08 8:42 UTC (permalink / raw)
To: Martin Uecker; +Cc: gcc-patches, Joseph Myers
[-- Attachment #1: Type: text/plain, Size: 2349 bytes --]
Hi Martin,
On Thu, Aug 08, 2024 at 09:39:59AM GMT, Martin Uecker wrote:
> > $ /opt/local/gnu/gcc/lengthof/bin/gcc zero.c
> > zero.c:18:12: error: variably modified ‘Z’ at file scope
> > 18 | static int Z[__lengthof__(Y)];
> > | ^
> >
> >
> > See that D, which is identical to Z, does not cause an error.
> > There's one case of [0] resulting in a constant expression, and another
> > in a VLA. Can you please help investigate why it's happening?
>
> This seems to be another bug where we incorrectly set
> C_TYPE_VARIABLE_SIZE and this also affects sizeof:
>
> https://godbolt.org/z/a8Ej6c5jr
>
> Strangely it seems related to the function declaration
> with the unspecified size before. I will look into this,
> I am just working on some checking functions that make sure
> that those bits are consistent all the time because I also
> missed some cases where I need to set C_TYPE_VARIABLY_MODIFIED
>
> I filed a new bug:
> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=116284
Huh, that's obscure! Thanks! :-)
>
> ...
>
> > | ^
> >
> > If I make [0] always result in a constant expression (and thus break
> > some [*] cases), by doing
> >
> > - var = var || (zero && C_TYPE_VARIABLE_SIZE (type));
> >
> > Then the problem disappears. But I'm worried that it might be hiding
> > the problem instead of removing it, since I don't really understand why
> > it's happening. Do you know why?
> >
> > Anyway, I'll remove that line to support [0]. But it would be
> > interesting to learn why this problem triggers.
>
> You need the line to support variable size arrays.
Not really. 'zero' is only true for [0] and for [*], but nor for
[zero], right?
All vla tests seem to pass if I remove that line. The only issue will
be that
void f(char (*a)[*], int (*x)[__lengthof__(*a)]);
will result in 'int (*x)[0]' until you change the implementation of [*],
but I think we can live with that small detail.
> Please just uncomment
> your test with a reference to the bug for now and I will try fix this ASAP.
I'll send v6 in a moment; feel free to insist in this if you disagree
after seeing it, but I think it works well without the line.
>
> Martin
Cheers,
Alex
--
<https://www.alejandro-colomar.es/>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [PATCH v5 3/3] c: Add __lengthof__ operator
2024-08-08 8:26 ` Alejandro Colomar
@ 2024-08-08 9:13 ` Jens Gustedt
2024-08-08 9:25 ` Alejandro Colomar
2024-08-08 17:21 ` [PATCH v5 3/3] c: Add __lengthof__ operator David Brown
0 siblings, 2 replies; 248+ messages in thread
From: Jens Gustedt @ 2024-08-08 9:13 UTC (permalink / raw)
To: Alejandro Colomar
Cc: Joseph Myers, gcc-patches, Martin Uecker,
Xavier Del Campo Romero, Gabriel Ravier, Jakub Jelinek,
Kees Cook, Qing Zhao, David Brown, Florian Weimer,
Andreas Schwab
Hi
Am 8. August 2024 10:26:14 MESZ schrieb Alejandro Colomar <alx@kernel.org>:
> Hello Jens,
>
> On Thu, Aug 08, 2024 at 07:35:12AM GMT, Jₑₙₛ Gustedt wrote:
> > Hello Alejandro,
> >
> > On Thu, 8 Aug 2024 00:44:02 +0200, Alejandro Colomar wrote:
> >
> > > +Its syntax is similar to @code{sizeof}.
> >
> > For my curiosity, do you also make the same distinction that with
> > expressions you may omit the parenthesis?
>
> I thought of it. TBH, I haven't tested that thoroughly.
>
> In principle, I have implemented it in the same way as sizeof, yes.
>
> Personally, I would have never allowed sizeof without parentheses, but I
> understand there are people who think the parentheses hurt readability,
> so I kept it in the same way.
>
> I'm not sure why the parentheses are necessary with type names in
> sizeof,
probably because of operator precedence. there would be no rule that tells us where sizeof ends and we'd switch back from parsing a type to parsing an expression
> but to maintain expectations, I think it would be better to do
> the same here.
Just to compare, the recent additions in C23 typeof etc. only have the parenthesized versions. So there would be precedent. And it really eases transition
> >
> > I wouldn't be sure that we should continue that distinction from
> > `sizeof`.
>
> But then, what do we do? Allow lengthof with type names without parens?
> Or require parens? I'm not comfortable with that choice.
>
> > Also that prefix variant would be difficult to wrap in a
> > `lengthof` macro (without underscores) as we would probably like to
> > have it in the end.
>
> Do you mean that I should add _Lengthof? We're adding __lengthof__ to
> be a GNU extension with relative freedom from ISO. If I sent a patch
> adding _Lengthof, we'd have to send a proposal to ISO at the same time,
> and we'd be waiting for ISO to discuss it before I can merge it. And we
> couldn't bring prior art to ISO.
>
> With this approach instead, the plan is:
>
> - Merge __lengthof__ in GCC before ISO hears of it (well, there are
> already several WG14 members in this discussion, so you have actually
> heard of it, but we're free to do more or less what we want).
>
> - Propose _Lengthof to ISO C, with prior art in GCC as __lengthof__,
> proposing the same semantics. Also propose a lengthof macro defined
> in <stdlength.h>
I don't really see why we should take a detour via _Lengthof, I would hope we could directly propose lengthof as the standardization
> - When ISO C accepts _Lengthof and lengthof, map _Lengthof in GCC to
> the same internals as __lengthof__, so they are the same thing.
>
> Still, I'm interested in having some feedback from WG14, to prevent
> implementing something that will have modifications when merged to
> ISO C, so please CC anyone interested from WG14, if you know of any.
I think that more important would be to have clang on board with this.
In any case, thanks for doing this!
Jens
--
Jens Gustedt - INRIA & ICube, Strasbourg, France
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [PATCH v5 3/3] c: Add __lengthof__ operator
2024-08-08 8:42 ` Alejandro Colomar
@ 2024-08-08 9:23 ` Martin Uecker
2024-08-08 9:36 ` Alejandro Colomar
0 siblings, 1 reply; 248+ messages in thread
From: Martin Uecker @ 2024-08-08 9:23 UTC (permalink / raw)
To: Alejandro Colomar; +Cc: gcc-patches, Joseph Myers
Am Donnerstag, dem 08.08.2024 um 10:42 +0200 schrieb Alejandro Colomar:
> >
> > ...
> >
> > > | ^
> > >
> > > If I make [0] always result in a constant expression (and thus break
> > > some [*] cases), by doing
> > >
> > > - var = var || (zero && C_TYPE_VARIABLE_SIZE (type));
> > >
> > > Then the problem disappears. But I'm worried that it might be hiding
> > > the problem instead of removing it, since I don't really understand why
> > > it's happening. Do you know why?
> > >
> > > Anyway, I'll remove that line to support [0]. But it would be
> > > interesting to learn why this problem triggers.
> >
> > You need the line to support variable size arrays.
>
> Not really. 'zero' is only true for [0] and for [*], but nor for
> [zero], right?
>
> All vla tests seem to pass if I remove that line. The only issue will
> be that
>
> void f(char (*a)[*], int (*x)[__lengthof__(*a)]);
>
> will result in 'int (*x)[0]' until you change the implementation of [*],
> but I think we can live with that small detail.
I plan to change the representation of [0], so it would be nice if the
[*] cases are correct as much as possible so that they not get forgotten
later.
Martin
>
> > Please just uncomment
> > your test with a reference to the bug for now and I will try fix this ASAP.
>
> I'll send v6 in a moment; feel free to insist in this if you disagree
> after seeing it, but I think it works well without the line.
>
> >
> > Martin
>
> Cheers,
> Alex
>
--
Univ.-Prof. Dr. rer. nat. Martin Uecker
Graz University of Technology
Institute of Biomedical Imaging
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [PATCH v5 3/3] c: Add __lengthof__ operator
2024-08-08 9:13 ` Jens Gustedt
@ 2024-08-08 9:25 ` Alejandro Colomar
2024-08-08 11:28 ` Joseph Myers
2024-08-08 17:21 ` [PATCH v5 3/3] c: Add __lengthof__ operator David Brown
1 sibling, 1 reply; 248+ messages in thread
From: Alejandro Colomar @ 2024-08-08 9:25 UTC (permalink / raw)
To: Jens Gustedt
Cc: Joseph Myers, gcc-patches, Martin Uecker,
Xavier Del Campo Romero, Gabriel Ravier, Jakub Jelinek,
Kees Cook, Qing Zhao, David Brown, Florian Weimer,
Andreas Schwab
[-- Attachment #1: Type: text/plain, Size: 2732 bytes --]
Hi Jens,
On Thu, Aug 08, 2024 at 11:13:02AM GMT, Jens Gustedt wrote:
> > but to maintain expectations, I think it would be better to do
> > the same here.
>
> Just to compare, the recent additions in C23 typeof etc. only have the
> parenthesized versions. So there would be precedent. And it really
> eases transition
Hmmm, interesting.
The good part of reusing sizeof syntax is that I can reuse internal code
for sizeof. But I'll check if I can change it easily to only support
parens.
> > > I wouldn't be sure that we should continue that distinction from
> > > `sizeof`.
> >
> > But then, what do we do? Allow lengthof with type names without parens?
> > Or require parens? I'm not comfortable with that choice.
> >
> > > Also that prefix variant would be difficult to wrap in a
> > > `lengthof` macro (without underscores) as we would probably like to
> > > have it in the end.
> >
> > Do you mean that I should add _Lengthof? We're adding __lengthof__ to
> > be a GNU extension with relative freedom from ISO. If I sent a patch
> > adding _Lengthof, we'd have to send a proposal to ISO at the same time,
> > and we'd be waiting for ISO to discuss it before I can merge it. And we
> > couldn't bring prior art to ISO.
> >
> > With this approach instead, the plan is:
> >
> > - Merge __lengthof__ in GCC before ISO hears of it (well, there are
> > already several WG14 members in this discussion, so you have actually
> > heard of it, but we're free to do more or less what we want).
> >
> > - Propose _Lengthof to ISO C, with prior art in GCC as __lengthof__,
> > proposing the same semantics. Also propose a lengthof macro defined
> > in <stdlength.h>
>
> I don't really see why we should take a detour via _Lengthof, I would
> hope we could directly propose lengthof as the standardization
Hmmm, maybe programs already use lengthof for some other purpose.
Hopefully not, but I don't know. In any case, I'm fine with both
approaches.
> > - When ISO C accepts _Lengthof and lengthof, map _Lengthof in GCC to
> > the same internals as __lengthof__, so they are the same thing.
> >
> > Still, I'm interested in having some feedback from WG14, to prevent
> > implementing something that will have modifications when merged to
> > ISO C, so please CC anyone interested from WG14, if you know of any.
>
> I think that more important would be to have clang on board with this.
Does anyone have any Clang maintainer in mind that would be interested
in being CCed? If so, please let me know (and/or add it yourselves).
>
> In any case, thanks for doing this!
:-)
Cheers,
Alex
--
<https://www.alejandro-colomar.es/>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [PATCH v5 3/3] c: Add __lengthof__ operator
2024-08-08 9:23 ` Martin Uecker
@ 2024-08-08 9:36 ` Alejandro Colomar
0 siblings, 0 replies; 248+ messages in thread
From: Alejandro Colomar @ 2024-08-08 9:36 UTC (permalink / raw)
To: Martin Uecker; +Cc: gcc-patches, Joseph Myers
[-- Attachment #1: Type: text/plain, Size: 727 bytes --]
On Thu, Aug 08, 2024 at 11:23:51AM GMT, Martin Uecker wrote:
> > Not really. 'zero' is only true for [0] and for [*], but nor for
> > [zero], right?
> >
> > All vla tests seem to pass if I remove that line. The only issue will
> > be that
> >
> > void f(char (*a)[*], int (*x)[__lengthof__(*a)]);
> >
> > will result in 'int (*x)[0]' until you change the implementation of [*],
> > but I think we can live with that small detail.
>
>
> I plan to change the representation of [0], so it would be nice if the
> [*] cases are correct as much as possible so that they not get forgotten
> later.
Ahhh, thanks! Will do, then.
>
> Martin
Cheers,
Alex
--
<https://www.alejandro-colomar.es/>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [PATCH v5 3/3] c: Add __lengthof__ operator
2024-08-08 9:25 ` Alejandro Colomar
@ 2024-08-08 11:28 ` Joseph Myers
2024-08-08 14:56 ` Jens Gustedt
0 siblings, 1 reply; 248+ messages in thread
From: Joseph Myers @ 2024-08-08 11:28 UTC (permalink / raw)
To: Alejandro Colomar
Cc: Jens Gustedt, gcc-patches, Martin Uecker,
Xavier Del Campo Romero, Gabriel Ravier, Jakub Jelinek,
Kees Cook, Qing Zhao, David Brown, Florian Weimer,
Andreas Schwab
On Thu, 8 Aug 2024, Alejandro Colomar wrote:
> Hi Jens,
>
> On Thu, Aug 08, 2024 at 11:13:02AM GMT, Jens Gustedt wrote:
> > > but to maintain expectations, I think it would be better to do
> > > the same here.
> >
> > Just to compare, the recent additions in C23 typeof etc. only have the
> > parenthesized versions. So there would be precedent. And it really
> > eases transition
>
> Hmmm, interesting.
>
> The good part of reusing sizeof syntax is that I can reuse internal code
> for sizeof. But I'll check if I can change it easily to only support
> parens.
Since typeof produces a type, it's used in different syntactic contexts
from sizeof, so has different ambiguity issues, and requiring parentheses
with typeof is not relevant to sizeof/lengthof. I think lengthof should
follow sizeof. Make sure there's a testcase for lengthof applied to a
compound literal (the case that illustrates how, on parsing sizeof
(type-name), the compiler needs to see what comes after (type-name) to
determine whether it's actually sizeof applied to an expression (if '{'
follows) or to a type (otherwise)). (If you're following the sizeof
implementation closely enough, this should just work.)
--
Joseph S. Myers
josmyers@redhat.com
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [PATCH v5 3/3] c: Add __lengthof__ operator
2024-08-08 11:28 ` Joseph Myers
@ 2024-08-08 14:56 ` Jens Gustedt
2024-08-08 15:42 ` Martin Uecker
0 siblings, 1 reply; 248+ messages in thread
From: Jens Gustedt @ 2024-08-08 14:56 UTC (permalink / raw)
To: Joseph Myers, Alejandro Colomar
Cc: gcc-patches, Martin Uecker, Xavier Del Campo Romero,
Gabriel Ravier, Jakub Jelinek, Kees Cook, Qing Zhao, David Brown,
Florian Weimer, Andreas Schwab
[-- Attachment #1: Type: text/plain, Size: 2191 bytes --]
Am 8. August 2024 13:28:57 MESZ schrieb Joseph Myers <josmyers@redhat.com>:
> On Thu, 8 Aug 2024, Alejandro Colomar wrote:
>
> > Hi Jens,
> >
> > On Thu, Aug 08, 2024 at 11:13:02AM GMT, Jens Gustedt wrote:
> > > > but to maintain expectations, I think it would be better to do
> > > > the same here.
> > >
> > > Just to compare, the recent additions in C23 typeof etc. only have the
> > > parenthesized versions. So there would be precedent. And it really
> > > eases transition
> >
> > Hmmm, interesting.
> >
> > The good part of reusing sizeof syntax is that I can reuse internal code
> > for sizeof. But I'll check if I can change it easily to only support
> > parens.
>
> Since typeof produces a type, it's used in different syntactic contexts
> from sizeof, so has different ambiguity issues, and requiring parentheses
> with typeof is not relevant to sizeof/lengthof. I think lengthof should
> follow sizeof. Make sure there's a testcase for lengthof applied to a
> compound literal (the case that illustrates how, on parsing sizeof
> (type-name), the compiler needs to see what comes after (type-name) to
> determine whether it's actually sizeof applied to an expression (if '{'
> follows) or to a type (otherwise)). (If you're following the sizeof
> implementation closely enough, this should just work.)
>
> --
> Joseph S. Myers
> josmyers@redhat.com
>
Hi,
I am not convinced that we should introduce the same syntax weirdness
for this feature. sizeof seems to be the only place in the core language
where a keyword is used as an operator in expressions, and
that does not resemble function-call notation. In particular your
example with compound literals shows that we could avoid syntax look-ahead
by not doing this. (People argued violently against look-ahead when we discussed possible inclusion of lambdas into C23)
We don't have to repeat all historic accidents when inventing a new feature.
Sure that gcc may invent anything to their liking, but when and if we pass this
for standardisation we will give such considerations a careful look.
Jens
--
Jens Gustedt - INRIA & ICube, Strasbourg, France
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [PATCH v5 3/3] c: Add __lengthof__ operator
2024-08-08 14:56 ` Jens Gustedt
@ 2024-08-08 15:42 ` Martin Uecker
2024-08-08 15:56 ` Jens Gustedt
0 siblings, 1 reply; 248+ messages in thread
From: Martin Uecker @ 2024-08-08 15:42 UTC (permalink / raw)
To: Jens Gustedt, Joseph Myers, Alejandro Colomar; +Cc: gcc-patches
Am Donnerstag, dem 08.08.2024 um 16:56 +0200 schrieb Jens Gustedt:
> Am 8. August 2024 13:28:57 MESZ schrieb Joseph Myers <josmyers@redhat.com>:
> > On Thu, 8 Aug 2024, Alejandro Colomar wrote:
> >
> > > Hi Jens,
> > >
> > > On Thu, Aug 08, 2024 at 11:13:02AM GMT, Jens Gustedt wrote:
> > > > > but to maintain expectations, I think it would be better to do
> > > > > the same here.
> > > > >
> > > >
> > > > Just to compare, the recent additions in C23 typeof etc. only have the
> > > > parenthesized versions. So there would be precedent. And it really
> > > > eases transition
> > > >
> > > Hmmm, interesting.
> > >
> > > The good part of reusing sizeof syntax is that I can reuse internal code
> > > for sizeof. But I'll check if I can change it easily to only support
> > > parens.
> > >
> >
> > Since typeof produces a type, it's used in different syntactic contexts
> > from sizeof, so has different ambiguity issues, and requiring parentheses
> > with typeof is not relevant to sizeof/lengthof. I think lengthof should
> > follow sizeof. Make sure there's a testcase for lengthof applied to a
> > compound literal (the case that illustrates how, on parsing sizeof
> > (type-name), the compiler needs to see what comes after (type-name) to
> > determine whether it's actually sizeof applied to an expression (if '{'
> > follows) or to a type (otherwise)). (If you're following the sizeof
> > implementation closely enough, this should just work.)
> Hi,
> I am not convinced that we should introduce the same syntax weirdness
> for this feature. sizeof seems to be the only place in the core language
> where a keyword is used as an operator in expressions, and
> that does not resemble function-call notation. In particular your
> example with compound literals shows that we could avoid syntax look-ahead
> by not doing this.
It is the other way around: With the "(" there is the ambiguity
whether this starts a compound literal or a type name enclosed
in parentheses. But this is not problematic for parsing.
Martin
> (People argued violently against look-ahead when we discussed
> possible inclusion of lambdas into C23)
> We don't have to repeat all historic accidents when inventing a new feature.
> Sure that gcc may invent anything to their liking, but when and if we pass this
> for standardisation we will give such considerations a careful look.
> Jens
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [PATCH v5 3/3] c: Add __lengthof__ operator
2024-08-08 15:42 ` Martin Uecker
@ 2024-08-08 15:56 ` Jens Gustedt
2024-08-08 16:08 ` Joseph Myers
0 siblings, 1 reply; 248+ messages in thread
From: Jens Gustedt @ 2024-08-08 15:56 UTC (permalink / raw)
To: Martin Uecker, Joseph Myers, Alejandro Colomar; +Cc: gcc-patches
Am 8. August 2024 17:42:54 MESZ schrieb Martin Uecker <uecker@tugraz.at>:
> Am Donnerstag, dem 08.08.2024 um 16:56 +0200 schrieb Jens Gustedt:
> > Am 8. August 2024 13:28:57 MESZ schrieb Joseph Myers <josmyers@redhat.com>:
> > > On Thu, 8 Aug 2024, Alejandro Colomar wrote:
> > >
> > > > Hi Jens,
> > > >
> > > > On Thu, Aug 08, 2024 at 11:13:02AM GMT, Jens Gustedt wrote:
> > > > > > but to maintain expectations, I think it would be better to do
> > > > > > the same here.
> > > > > >
> > > > >
> > > > > Just to compare, the recent additions in C23 typeof etc. only have the
> > > > > parenthesized versions. So there would be precedent. And it really
> > > > > eases transition
> > > > >
> > > > Hmmm, interesting.
> > > >
> > > > The good part of reusing sizeof syntax is that I can reuse internal code
> > > > for sizeof. But I'll check if I can change it easily to only support
> > > > parens.
> > > >
> > >
> > > Since typeof produces a type, it's used in different syntactic contexts
> > > from sizeof, so has different ambiguity issues, and requiring parentheses
> > > with typeof is not relevant to sizeof/lengthof. I think lengthof should
> > > follow sizeof. Make sure there's a testcase for lengthof applied to a
> > > compound literal (the case that illustrates how, on parsing sizeof
> > > (type-name), the compiler needs to see what comes after (type-name) to
> > > determine whether it's actually sizeof applied to an expression (if '{'
> > > follows) or to a type (otherwise)). (If you're following the sizeof
> > > implementation closely enough, this should just work.)
>
> > Hi,
> > I am not convinced that we should introduce the same syntax weirdness
> > for this feature. sizeof seems to be the only place in the core language
> > where a keyword is used as an operator in expressions, and
> > that does not resemble function-call notation. In particular your
> > example with compound literals shows that we could avoid syntax look-ahead
> > by not doing this.
>
> It is the other way around: With the "(" there is the ambiguity
> whether this starts a compound literal or a type name enclosed
> in parentheses. But this is not problematic for parsing.
No, the ambiguity is there because the first ( after the keyword could start either a type in parenthesis or an expression, and among these a compound literal. If that first parenthesis would be part of the construct (as for the typeof or offsetof constructs) there would be no ambiguity a the only look ahead would be balanced parenthesis parsing.
And just because there is "no problem"
because we learned to deal with this weirdness, it still doesn't mean we have to write an inconsistency forward for which we don't even remember why we have it.
>
> Martin
>
>
> > (People argued violently against look-ahead when we discussed
> > possible inclusion of lambdas into C23)
>
> > We don't have to repeat all historic accidents when inventing a new feature.
> > Sure that gcc may invent anything to their liking, but when and if we pass this
> > for standardisation we will give such considerations a careful look.
>
> > Jens
>
--
Jens Gustedt - INRIA & ICube, Strasbourg, France
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [PATCH v5 3/3] c: Add __lengthof__ operator
2024-08-08 15:56 ` Jens Gustedt
@ 2024-08-08 16:08 ` Joseph Myers
2024-08-08 16:23 ` Jens Gustedt
0 siblings, 1 reply; 248+ messages in thread
From: Joseph Myers @ 2024-08-08 16:08 UTC (permalink / raw)
To: Jens Gustedt; +Cc: Martin Uecker, Alejandro Colomar, gcc-patches
On Thu, 8 Aug 2024, Jens Gustedt wrote:
> No, the ambiguity is there because the first ( after the keyword could
> start either a type in parenthesis or an expression, and among these a
> compound literal. If that first parenthesis would be part of the
> construct (as for the typeof or offsetof constructs) there would be no
> ambiguity a the only look ahead would be balanced parenthesis parsing.
I don't consider this ambiguity / unbounded lookahead in any problematic
sense. There are the following cases for sizeof:
* Not followed by '(': sizeof unary-expression.
* Followed by '(' then a token that does not start a type-name: sizeof
unary-expression.
* Followed by '(' then a token that does start a type-name: sizeof
(type-name) later-tokens, where if later-tokens start with '{' then it's
sizeof unary-expression and otherwise it's sizeof (type-name).
The last case is not problematic because the parsing of the type-name
doesn't depend at all on what comes after it; it's parsed exactly the same
whether it's part of sizeof (type-name) or a compound literal.
Fundamentally this is exactly the same as if a cast-expression starts with
(type-name): until the end of the type name, you don't know whether it's a
cast, or whether the cast-expression is actually a unary-expression which
is a postfix-expression which is a compound-literal. In both cases, the
parsing of a compound-literal is entered only after the initial
(type-name) has been seen, because until after the (type-name) it's not
known which construct is being parsed.
--
Joseph S. Myers
josmyers@redhat.com
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [PATCH v5 3/3] c: Add __lengthof__ operator
2024-08-08 16:08 ` Joseph Myers
@ 2024-08-08 16:23 ` Jens Gustedt
2024-08-08 16:30 ` Martin Uecker
0 siblings, 1 reply; 248+ messages in thread
From: Jens Gustedt @ 2024-08-08 16:23 UTC (permalink / raw)
To: Joseph Myers; +Cc: Martin Uecker, Alejandro Colomar, gcc-patches
[-- Attachment #1: Type: text/plain, Size: 626 bytes --]
As said, even if we don't consider this problematic because we are used to the mildly complex case distinction that you just exposed over several paragraphs, it doesn't mean that we should do it, nor does it mean that it would be beneficial for our users or for other implementations that would like to follow.
And also as said, all other features in the standard, being types, typeof, or expressions, e.g offsetof, unreachable or other gnu extensions, don't have nor need this kind of syntax.
We should be designing features for the future, not the past
Jens
--
Jens Gustedt - INRIA & ICube, Strasbourg, France
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [PATCH v5 3/3] c: Add __lengthof__ operator
2024-08-08 16:23 ` Jens Gustedt
@ 2024-08-08 16:30 ` Martin Uecker
2024-08-08 17:01 ` Alejandro Colomar
0 siblings, 1 reply; 248+ messages in thread
From: Martin Uecker @ 2024-08-08 16:30 UTC (permalink / raw)
To: Jens Gustedt, Joseph Myers; +Cc: Alejandro Colomar, gcc-patches
Am Donnerstag, dem 08.08.2024 um 18:23 +0200 schrieb Jens Gustedt:
> As said, even if we don't consider this problematic because we are used to the mildly complex case distinction that you just exposed over several paragraphs, it doesn't mean that we should
> do it, nor does it mean that it would be beneficial for our users or for other implementations that would like to follow.
>
> And also as said, all other features in the standard, being types, typeof, or expressions, e.g offsetof, unreachable or other gnu extensions, don't have nor need this kind of syntax.
>
> We should be designing features for the future, not the past
While not problematic for parsing, I see now how the grammar becomes
better if we eliminated this quirk. Thanks!
But we should then deprecate this for sizeof too.
Martin
>
> Jens
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [PATCH v5 3/3] c: Add __lengthof__ operator
2024-08-08 16:30 ` Martin Uecker
@ 2024-08-08 17:01 ` Alejandro Colomar
2024-08-08 17:31 ` Joseph Myers
0 siblings, 1 reply; 248+ messages in thread
From: Alejandro Colomar @ 2024-08-08 17:01 UTC (permalink / raw)
To: Martin Uecker; +Cc: Jens Gustedt, Joseph Myers, gcc-patches
[-- Attachment #1: Type: text/plain, Size: 1796 bytes --]
Hi Martin, Jens, Joseph,
On Thu, Aug 08, 2024 at 06:30:42PM GMT, Martin Uecker wrote:
> Am Donnerstag, dem 08.08.2024 um 18:23 +0200 schrieb Jens Gustedt:
> > As said, even if we don't consider this problematic because we are used to the mildly complex case distinction that you just exposed over several paragraphs, it doesn't mean that we should
> > do it, nor does it mean that it would be beneficial for our users or for other implementations that would like to follow.
> >
> > And also as said, all other features in the standard, being types, typeof, or expressions, e.g offsetof, unreachable or other gnu extensions, don't have nor need this kind of syntax.
> >
> > We should be designing features for the future, not the past
>
>
> While not problematic for parsing, I see now how the grammar becomes
> better if we eliminated this quirk. Thanks!
>
> But we should then deprecate this for sizeof too.
How about having __lengthof__ behave like sizeof, but deprecate it in
sizeof too?
ISO C could accept only lengthof() with parens, and we could have it
without them as a deprecated-on-arrival GNU extension.
And then remove it from both at some point in the future.
We could start by adding a -Wall warning for sizeof without parens, and
promote it to an error a few versions later.
Have a lovely day!
Alex
P.S.: I'm doing a whole-tree update to use __lengthof__ instead of
open-coded sizeof divisons or macros based on it, and I've found several
bugs already. I'll use this change to test the new operator in the
entire code base, which should result in no regressions at all. That
would be an interesting test suite. :)
However, I advance that it will be painful to review that patch.
--
<https://www.alejandro-colomar.es/>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [PATCH v5 3/3] c: Add __lengthof__ operator
2024-08-08 9:13 ` Jens Gustedt
2024-08-08 9:25 ` Alejandro Colomar
@ 2024-08-08 17:21 ` David Brown
2024-08-08 18:19 ` Jens Gustedt
1 sibling, 1 reply; 248+ messages in thread
From: David Brown @ 2024-08-08 17:21 UTC (permalink / raw)
To: Jens Gustedt, Alejandro Colomar
Cc: Joseph Myers, gcc-patches, Martin Uecker,
Xavier Del Campo Romero, Gabriel Ravier, Jakub Jelinek,
Kees Cook, Qing Zhao, Florian Weimer, Andreas Schwab
On 08/08/2024 11:13, Jens Gustedt wrote:
> Hi
>
> Am 8. August 2024 10:26:14 MESZ schrieb Alejandro Colomar <alx@kernel.org>:
>> Hello Jens,
>>
>> On Thu, Aug 08, 2024 at 07:35:12AM GMT, Jₑₙₛ Gustedt wrote:
>>> Hello Alejandro,
>>>
>>> On Thu, 8 Aug 2024 00:44:02 +0200, Alejandro Colomar wrote:
>>>
>>>> +Its syntax is similar to @code{sizeof}.
>>>
>>> For my curiosity, do you also make the same distinction that with
>>> expressions you may omit the parenthesis?
>>
>> I thought of it. TBH, I haven't tested that thoroughly.
>>
>> In principle, I have implemented it in the same way as sizeof, yes.
>>
>> Personally, I would have never allowed sizeof without parentheses, but I
>> understand there are people who think the parentheses hurt readability,
>> so I kept it in the same way.
>>
>> I'm not sure why the parentheses are necessary with type names in
>> sizeof,
>
> probably because of operator precedence. there would be no rule that tells us where sizeof ends and we'd switch back from parsing a type to parsing an expression
>
I personally have always found it looks odd that the sizeof operator
does not always need parentheses - I suppose that is because it is a
word, rather than punctuation. To me, it looks more like a function or
function-like macro. And I'd view lengthof in the same light. However,
that's just personal opinion, not a rational argument!
>
>> but to maintain expectations, I think it would be better to do
>> the same here.
>
> Just to compare, the recent additions in C23 typeof etc. only have the parenthesized versions. So there would be precedent. And it really eases transition
>
_Alignof (now "alignof") from C11 always needs parentheses too - but it
always applies to a type, not an expression. (I think it should also be
possible to use it with expressions for consistency, but that's another
matter.)
As I see it, there is a good reason to say that a "lengthof" feature
should always have parentheses. With "typeof" (either as the gcc
extension or the C23 feature), you can come a long way to the
functionality of the proposed "lengthof" (or "__lengthof__") using a
macro. This will mean that if someone writes code using the new feature
in gcc, and another person wants to compile the code with older gcc or a
different compiler, they can use a macro (even "#define lengthof(arr)
(sizeof(arr)/sizeof((arr)[0])", which is less safe but works everywhere)
instead. But that is only true of the person writing the original
"lengthof" code has included the parentheses.
>
>>>
>>> I wouldn't be sure that we should continue that distinction from
>>> `sizeof`.
>>
>> But then, what do we do? Allow lengthof with type names without parens?
>> Or require parens? I'm not comfortable with that choice.
>>
>>> Also that prefix variant would be difficult to wrap in a
>>> `lengthof` macro (without underscores) as we would probably like to
>>> have it in the end.
>>
>> Do you mean that I should add _Lengthof? We're adding __lengthof__ to
>> be a GNU extension with relative freedom from ISO. If I sent a patch
>> adding _Lengthof, we'd have to send a proposal to ISO at the same time,
>> and we'd be waiting for ISO to discuss it before I can merge it. And we
>> couldn't bring prior art to ISO.
>>
>> With this approach instead, the plan is:
>>
>> - Merge __lengthof__ in GCC before ISO hears of it (well, there are
>> already several WG14 members in this discussion, so you have actually
>> heard of it, but we're free to do more or less what we want).
>>
>> - Propose _Lengthof to ISO C, with prior art in GCC as __lengthof__,
>> proposing the same semantics. Also propose a lengthof macro defined
>> in <stdlength.h>
>
> I don't really see why we should take a detour via _Lengthof, I would hope we could directly propose lengthof as the standardization
>
It is traditional for C. It has taken until C23 to get alignof, bool,
etc., as full keywords. I would expect that we would have _Lengthof for
a transitional period while "lengthof" is in "<stdlength.h>" and other
uses of it are deprecated. Changes in C happen slowly if backwards
compatibility is threatened (too slowly for some people, too fast for
others).
>> - When ISO C accepts _Lengthof and lengthof, map _Lengthof in GCC to
>> the same internals as __lengthof__, so they are the same thing.
>>
>> Still, I'm interested in having some feedback from WG14, to prevent
>> implementing something that will have modifications when merged to
>> ISO C, so please CC anyone interested from WG14, if you know of any.
>
> I think that more important would be to have clang on board with this.
>
> In any case, thanks for doing this!
>
> Jens
>
>
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [PATCH v5 3/3] c: Add __lengthof__ operator
2024-08-08 17:01 ` Alejandro Colomar
@ 2024-08-08 17:31 ` Joseph Myers
2024-08-08 18:04 ` Alejandro Colomar
2024-08-08 20:01 ` Alejandro Colomar
0 siblings, 2 replies; 248+ messages in thread
From: Joseph Myers @ 2024-08-08 17:31 UTC (permalink / raw)
To: Alejandro Colomar; +Cc: Martin Uecker, Jens Gustedt, gcc-patches
On Thu, 8 Aug 2024, Alejandro Colomar wrote:
> How about having __lengthof__ behave like sizeof, but deprecate it in
> sizeof too?
Deprecation would be a matter for WG14.
> We could start by adding a -Wall warning for sizeof without parens, and
> promote it to an error a few versions later.
This is very far outside the scope of -Wall. There is nothing confusing
for the programmer about sizeof without parentheses and no likelihood that
the programmer meant something other than the semantics of the code.
GCC should not be opinionated about promoting personal ideas of what is or
is not good style or what might or might not be a future language feature;
it should support a wide range of different programming styles. The
threshold for warning about something in -Wall (or -Wextra) should be much
higher than "the language design would be simpler without this feature".
> P.S.: I'm doing a whole-tree update to use __lengthof__ instead of
> open-coded sizeof divisons or macros based on it, and I've found several
> bugs already. I'll use this change to test the new operator in the
> entire code base, which should result in no regressions at all. That
> would be an interesting test suite. :)
I think the code base (code on the host is generally in C++) should be
readable to people who know C++ (C++11 is the documented requirement for
building GCC - we're very conservative about adopting new language
versions, to facilitate bootstrapping on a wide range of systems) as it
is, not a playground for trying out new language features. We have enough
GCC-specific versions of standard features as it is (e.g. the GCC-specific
vectors designed to interoperate with GCC's garbage collection), using a
new feature that doesn't add expressivity and isn't in any standard C++
version doesn't seem like a good idea to me.
Actual bugs should of course be fixed. But certainly standard features
are preferable to something specific to GCC, and existing macros in GCC
such as ARRAY_SIZE that people are at least familiar with are preferable
to introducing a new language feature.
*If* the feature were adopted into C++26, we could then consider if
existing macros should be renamed to look more like the future language
feature.
Target code is at least always compiled with the same version of GCC, but
it still shouldn't be a playground for new language features; that doesn't
help readability, backporting patches to versions without the features,
etc.
--
Joseph S. Myers
josmyers@redhat.com
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [PATCH v5 3/3] c: Add __lengthof__ operator
2024-08-08 17:31 ` Joseph Myers
@ 2024-08-08 18:04 ` Alejandro Colomar
2024-08-08 18:16 ` Martin Uecker
2024-08-08 20:01 ` Alejandro Colomar
1 sibling, 1 reply; 248+ messages in thread
From: Alejandro Colomar @ 2024-08-08 18:04 UTC (permalink / raw)
To: Joseph Myers; +Cc: Martin Uecker, Jens Gustedt, gcc-patches
[-- Attachment #1: Type: text/plain, Size: 2637 bytes --]
Hi Joseph,
On Thu, Aug 08, 2024 at 05:31:05PM GMT, Joseph Myers wrote:
> On Thu, 8 Aug 2024, Alejandro Colomar wrote:
>
> > How about having __lengthof__ behave like sizeof, but deprecate it in
> > sizeof too?
>
> Deprecation would be a matter for WG14.
Yep; I wouldn't add it to -Wall unless WG14 decides to deprecate it
first. But if it does, that could be the path. For lengthof, I think
keeping it like sizeof would be the simplest, as an implementer. And
users will probably not care too much. And if WG14 decides to deprecate
it from sizeof, they can also deprecate it from lengthof at the same
time.
> I think the code base (code on the host is generally in C++) should be
> readable to people who know C++ (C++11 is the documented requirement for
> building GCC - we're very conservative about adopting new language
> versions, to facilitate bootstrapping on a wide range of systems) as it
> is, not a playground for trying out new language features. We have enough
> GCC-specific versions of standard features as it is (e.g. the GCC-specific
> vectors designed to interoperate with GCC's garbage collection), using a
> new feature that doesn't add expressivity and isn't in any standard C++
> version doesn't seem like a good idea to me.
>
> Actual bugs should of course be fixed. But certainly standard features
> are preferable to something specific to GCC, and existing macros in GCC
> such as ARRAY_SIZE that people are at least familiar with are preferable
> to introducing a new language feature.
ARRAY_SIZE() is very rarely used. From what I've seen, most of the
existing code uses the raw sizeof division, and there's a non-negligible
amount of typos in those.
I suggest that someone at least converts most or all calls to
ARRAY_SIZE(), so that it can later easily be changed to lengthof().
I can provide my patch as a draft, so that it's just adding some include
and s/__lengthof__/ARRAY_SIZE/, plus some whitespace and parens fixes.
>
> *If* the feature were adopted into C++26, we could then consider if
> existing macros should be renamed to look more like the future language
> feature.
>
> Target code is at least always compiled with the same version of GCC, but
> it still shouldn't be a playground for new language features; that doesn't
> help readability, backporting patches to versions without the features,
> etc.
It will serve me as a huge test suite anyway; so it's worth it even if
just for myself. And it will uncover bugs. :)
Thanks!
Have a lovely day!
Alex
--
<https://www.alejandro-colomar.es/>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [PATCH v5 3/3] c: Add __lengthof__ operator
2024-08-08 18:04 ` Alejandro Colomar
@ 2024-08-08 18:16 ` Martin Uecker
2024-08-08 18:30 ` Alejandro Colomar
0 siblings, 1 reply; 248+ messages in thread
From: Martin Uecker @ 2024-08-08 18:16 UTC (permalink / raw)
To: Alejandro Colomar, Joseph Myers; +Cc: Jens Gustedt, gcc-patches
Am Donnerstag, dem 08.08.2024 um 20:04 +0200 schrieb Alejandro Colomar:
>
...
> >
> > *If* the feature were adopted into C++26, we could then consider if
> > existing macros should be renamed to look more like the future language
> > feature.
> >
> > Target code is at least always compiled with the same version of GCC, but
> > it still shouldn't be a playground for new language features; that doesn't
> > help readability, backporting patches to versions without the features,
> > etc.
>
> It will serve me as a huge test suite anyway; so it's worth it even if
> just for myself. And it will uncover bugs. :)
Did you implement a C++ version? Or are you talking about the C parts
of the code. It is a bit sad that we do not get the testing of the
C FE anymore which a self-hosting would have.
Martin
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [PATCH v5 3/3] c: Add __lengthof__ operator
2024-08-08 17:21 ` [PATCH v5 3/3] c: Add __lengthof__ operator David Brown
@ 2024-08-08 18:19 ` Jens Gustedt
0 siblings, 0 replies; 248+ messages in thread
From: Jens Gustedt @ 2024-08-08 18:19 UTC (permalink / raw)
To: David Brown, Alejandro Colomar
Cc: Joseph Myers, gcc-patches, Martin Uecker,
Xavier Del Campo Romero, Gabriel Ravier, Jakub Jelinek,
Kees Cook, Qing Zhao, Florian Weimer, Andreas Schwab
Am 8. August 2024 19:21:23 MESZ schrieb David Brown <david.brown@hesbynett.no>:
>
>
> On 08/08/2024 11:13, Jens Gustedt wrote:
> > Hi
> >
> > Am 8. August 2024 10:26:14 MESZ schrieb Alejandro Colomar <alx@kernel.org>:
> >> Hello Jens,
> >>
> >> On Thu, Aug 08, 2024 at 07:35:12AM GMT, Jₑₙₛ Gustedt wrote:
> >>> Hello Alejandro,
> >>>
> >>> On Thu, 8 Aug 2024 00:44:02 +0200, Alejandro Colomar wrote:
> >>>
> >>>> +Its syntax is similar to @code{sizeof}.
> >>>
> >>> For my curiosity, do you also make the same distinction that with
> >>> expressions you may omit the parenthesis?
> >>
> >> I thought of it. TBH, I haven't tested that thoroughly.
> >>
> >> In principle, I have implemented it in the same way as sizeof, yes.
> >>
> >> Personally, I would have never allowed sizeof without parentheses, but I
> >> understand there are people who think the parentheses hurt readability,
> >> so I kept it in the same way.
> >>
> >> I'm not sure why the parentheses are necessary with type names in
> >> sizeof,
> >
> > probably because of operator precedence. there would be no rule that tells us where sizeof ends and we'd switch back from parsing a type to parsing an expression
> >
>
> I personally have always found it looks odd that the sizeof operator does not always need parentheses - I suppose that is because it is a word, rather than punctuation. To me, it looks more like a function or function-like macro. And I'd view lengthof in the same light. However, that's just personal opinion, not a rational argument!
>
> >
> >> but to maintain expectations, I think it would be better to do
> >> the same here.
> >
> > Just to compare, the recent additions in C23 typeof etc. only have the parenthesized versions. So there would be precedent. And it really eases transition
> >
>
> _Alignof (now "alignof") from C11 always needs parentheses too - but it always applies to a type, not an expression. (I think it should also be possible to use it with expressions for consistency, but that's another matter.)
>
> As I see it, there is a good reason to say that a "lengthof" feature should always have parentheses. With "typeof" (either as the gcc extension or the C23 feature), you can come a long way to the functionality of the proposed "lengthof" (or "__lengthof__") using a macro. This will mean that if someone writes code using the new feature in gcc, and another person wants to compile the code with older gcc or a different compiler, they can use a macro (even "#define lengthof(arr) (sizeof(arr)/sizeof((arr)[0])", which is less safe but works everywhere)
> instead. But that is only true of the person writing the original "lengthof" code has included the parentheses.
>
> >
> >>>
> >>> I wouldn't be sure that we should continue that distinction from
> >>> `sizeof`.
> >>
> >> But then, what do we do? Allow lengthof with type names without parens?
> >> Or require parens? I'm not comfortable with that choice.
> >>
> >>> Also that prefix variant would be difficult to wrap in a
> >>> `lengthof` macro (without underscores) as we would probably like to
> >>> have it in the end.
> >>
> >> Do you mean that I should add _Lengthof? We're adding __lengthof__ to
> >> be a GNU extension with relative freedom from ISO. If I sent a patch
> >> adding _Lengthof, we'd have to send a proposal to ISO at the same time,
> >> and we'd be waiting for ISO to discuss it before I can merge it. And we
> >> couldn't bring prior art to ISO.
> >>
> >> With this approach instead, the plan is:
> >>
> >> - Merge __lengthof__ in GCC before ISO hears of it (well, there are
> >> already several WG14 members in this discussion, so you have actually
> >> heard of it, but we're free to do more or less what we want).
> >>
> >> - Propose _Lengthof to ISO C, with prior art in GCC as __lengthof__,
> >> proposing the same semantics. Also propose a lengthof macro defined
> >> in <stdlength.h>
> >
> > I don't really see why we should take a detour via _Lengthof, I would hope we could directly propose lengthof as the standardization
> >
>
> It is traditional for C. It has taken until C23 to get alignof, bool, etc., as full keywords. I would expect that we would have _Lengthof for a transitional period while "lengthof" is in "<stdlength.h>" and other uses of it are deprecated. Changes in C happen slowly if backwards compatibility is threatened (too slowly for some people, too fast for others).
The reason is not to use user space identifiers. There __lengthof__ is already as good as the other weirdo, no reason to add that.
>
> >> - When ISO C accepts _Lengthof and lengthof, map _Lengthof in GCC to
> >> the same internals as __lengthof__, so they are the same thing.
> >>
> >> Still, I'm interested in having some feedback from WG14, to prevent
> >> implementing something that will have modifications when merged to
> >> ISO C, so please CC anyone interested from WG14, if you know of any.
> >
> > I think that more important would be to have clang on board with this.
> >
> > In any case, thanks for doing this!
> >
> > Jens
> >
> >
--
Jens Gustedt - INRIA & ICube, Strasbourg, France
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [PATCH v5 3/3] c: Add __lengthof__ operator
2024-08-08 18:16 ` Martin Uecker
@ 2024-08-08 18:30 ` Alejandro Colomar
0 siblings, 0 replies; 248+ messages in thread
From: Alejandro Colomar @ 2024-08-08 18:30 UTC (permalink / raw)
To: Martin Uecker; +Cc: Joseph Myers, Jens Gustedt, gcc-patches
[-- Attachment #1: Type: text/plain, Size: 779 bytes --]
Hi Martin,
On Thu, Aug 08, 2024 at 08:16:50PM GMT, Martin Uecker wrote:
> > It will serve me as a huge test suite anyway; so it's worth it even if
> > just for myself. And it will uncover bugs. :)
>
> Did you implement a C++ version? Or are you talking about the C parts
> of the code.
I'll start with C, but was considering trying to implement a C++
version. But I think it's not worth it for me. I don't like the
language at all, anyway. :)
> It is a bit sad that we do not get the testing of the
> C FE anymore which a self-hosting would have.
Yup. I wish GCC had not moved to C++. Maybe improving the C language
helps that goal (move back to C) in the very long term. :)
> Martin
Cheers,
Alex
--
<https://www.alejandro-colomar.es/>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [PATCH v5 3/3] c: Add __lengthof__ operator
2024-08-08 17:31 ` Joseph Myers
2024-08-08 18:04 ` Alejandro Colomar
@ 2024-08-08 20:01 ` Alejandro Colomar
2024-08-08 20:36 ` Joseph Myers
` (3 more replies)
1 sibling, 4 replies; 248+ messages in thread
From: Alejandro Colomar @ 2024-08-08 20:01 UTC (permalink / raw)
To: Joseph Myers; +Cc: Martin Uecker, Jens Gustedt, gcc-patches
[-- Attachment #1: Type: text/plain, Size: 1297 bytes --]
Hi Joseph,
On Thu, Aug 08, 2024 at 05:31:05PM GMT, Joseph Myers wrote:
> Actual bugs should of course be fixed.
Here are the suspects:
./gcc/testsuite/gcc.target/powerpc/sse3-addsubps.c:80:
for (i = 0; i < sizeof (vals) / sizeof (vals); i += 8)
./gcc/c-family/c-pragma.cc:1811:
= sizeof (omp_pragmas_simd) / sizeof (*omp_pragmas);
The second sizeof expression seems to have a bogus operand, and the
correct one is probably the common one in sizeof divisions.
There are some others which are weird, but the result is correct. For
example:
./libstdc++-v3/testsuite/21_strings/basic_string/cons/char/constexpr.cc:62:
const auto len = (sizeof(cs) - 1)/sizeof(C);
./libstdc++-v3/testsuite/21_strings/basic_string/cons/wchar_t/constexpr.cc:62:
const auto len = (sizeof(cs) - 1)/sizeof(C);
Which would read better as sizeof/sizeof - 1.
There are others which also could be improved in readability terms, but
I don't think it's worth bikeshedding that at the moment. If you do a
global switch to ARRAY_SIZE(), I can help with those. I'll keep the
commit in the backyard in case we need it for something.
It's:
662 files changed, 1426 insertions(+), 1545 deletions(-)
Have a lovely night!
Alex
--
<https://www.alejandro-colomar.es/>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [PATCH v5 3/3] c: Add __lengthof__ operator
2024-08-08 20:01 ` Alejandro Colomar
@ 2024-08-08 20:36 ` Joseph Myers
2024-08-08 20:56 ` Alejandro Colomar
2024-08-08 22:43 ` Jakub Jelinek
` (2 subsequent siblings)
3 siblings, 1 reply; 248+ messages in thread
From: Joseph Myers @ 2024-08-08 20:36 UTC (permalink / raw)
To: Alejandro Colomar; +Cc: Martin Uecker, Jens Gustedt, gcc-patches
On Thu, 8 Aug 2024, Alejandro Colomar wrote:
> Here are the suspects:
>
> ./gcc/testsuite/gcc.target/powerpc/sse3-addsubps.c:80:
> for (i = 0; i < sizeof (vals) / sizeof (vals); i += 8)
The key question for testcases is *does the test actually test what was
intended*? We never want to change testcases simply for cleanness or
consistency; being inconsistent is actively good in the testsuite, which
should cover as wide a variety of weird code as possible.
--
Joseph S. Myers
josmyers@redhat.com
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [PATCH v5 3/3] c: Add __lengthof__ operator
2024-08-08 20:36 ` Joseph Myers
@ 2024-08-08 20:56 ` Alejandro Colomar
0 siblings, 0 replies; 248+ messages in thread
From: Alejandro Colomar @ 2024-08-08 20:56 UTC (permalink / raw)
To: Joseph Myers; +Cc: Martin Uecker, Jens Gustedt, gcc-patches
[-- Attachment #1: Type: text/plain, Size: 851 bytes --]
On Thu, Aug 08, 2024 at 08:36:36PM GMT, Joseph Myers wrote:
> On Thu, 8 Aug 2024, Alejandro Colomar wrote:
>
> > Here are the suspects:
> >
> > ./gcc/testsuite/gcc.target/powerpc/sse3-addsubps.c:80:
> > for (i = 0; i < sizeof (vals) / sizeof (vals); i += 8)
>
> The key question for testcases is *does the test actually test what was
> intended*? We never want to change testcases simply for cleanness or
> consistency; being inconsistent is actively good in the testsuite, which
> should cover as wide a variety of weird code as possible.
I suspect it doesn't test what was intended. sizeof(vals)/sizeof(vals)
is 1, which doesn't look like intended at all. Also, there were related
tests that had the proper division.
>
> --
> Joseph S. Myers
> josmyers@redhat.com
>
--
<https://www.alejandro-colomar.es/>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 248+ messages in thread
* Internal Compiler Error (was: [PATCH v5 0/3] c: Add __lengthof__ operator)
2024-08-06 23:11 ` [PATCH v5 0/3] " Alejandro Colomar
` (3 preceding siblings ...)
2024-08-06 23:25 ` [PATCH v5 0/3] " Alejandro Colomar
@ 2024-08-08 22:41 ` Alejandro Colomar
4 siblings, 0 replies; 248+ messages in thread
From: Alejandro Colomar @ 2024-08-08 22:41 UTC (permalink / raw)
To: gcc-patches; +Cc: Martin Uecker, Joseph Myers, Jakub Jelinek
[-- Attachment #1: Type: text/plain, Size: 13025 bytes --]
Hi!
While running `make check -j24`, I've seen an internal compiler error.
I've tried to reproduce it, but it only triggered once that time.
This is the only log I've been able to collect. I hope it helps.
lto1: internal compiler error: in lto_read_decls, at lto/lto-common.cc:1970
0x23234de internal_error(char const*, ...)
../.././gcc/diagnostic-global-context.cc:491
0x923807 fancy_abort(char const*, int, char const*)
../.././gcc/diagnostic.cc:1772
0x71d494 lto_read_decls
../.././gcc/lto/lto-common.cc:1970
0x97b959 lto_file_finalize
../.././gcc/lto/lto-common.cc:2299
0x97b959 lto_create_files_from_ids
../.././gcc/lto/lto-common.cc:2309
0x97b959 lto_file_read
../.././gcc/lto/lto-common.cc:2364
0x97b959 read_cgraph_and_symbols(unsigned int, char const**)
../.././gcc/lto/lto-common.cc:2812
0x95c012 lto_main()
../.././gcc/lto/lto.cc:658
Please submit a full bug report, with preprocessed source (by using -freport-bug).
Please include the complete backtrace with any bug report.
See <https://gcc.gnu.org/bugs/> for instructions.
lto-wrapper: fatal error: /home/alx/src/gnu/gcc/len/host-x86_64-pc-linux-gnu/gcc/xgcc returned 1 exit status
compilation terminated.
/usr/bin/ld: error: lto-wrapper failed
collect2: error: ld returned 1 exit status
To clarify, this was run after running a slightly-modified version of
this patch set, and nothing else. In theory, I think, I haven't touched
anything that should cause an lto ICE. I've rebased on top of git HEAD
earlier today, and have applied the changes shown below.
I assume I'm causing it somehow, with my patches, but maybe it's not.
Is git HEAD known to be in a bad state at the moment regarding lto?
The range-diff below is what will be v6, which I was planning to send
today, but haven't because of this ICE.
Cheers,
Alex
$ git range-diff 73010cb4af6^..af05d01e68d gnu/master..HEAD
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: e8867c0fef4 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 <josmyers@redhat.com>
Cc: Gabriel Ravier <gabravier@gmail.com>
@@ 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(), f2();
++int a[10][10];
++int n;
++
++void
++syms(void)
++{
++ int b[n][n];
++
++ __lengthof__ (a[f1()]);
++ __lengthof__ (b[f2()]); /* { dg-warning "never defined" } */
++}
++
++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-warning "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-warning "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 ();
+}
--
<https://www.alejandro-colomar.es/>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [PATCH v5 3/3] c: Add __lengthof__ operator
2024-08-08 20:01 ` Alejandro Colomar
2024-08-08 20:36 ` Joseph Myers
@ 2024-08-08 22:43 ` Jakub Jelinek
2024-08-08 22:48 ` Jakub Jelinek
2024-08-10 8:57 ` [committed] testsuite: Fix up sse3-addsubps.c Jakub Jelinek
3 siblings, 0 replies; 248+ messages in thread
From: Jakub Jelinek @ 2024-08-08 22:43 UTC (permalink / raw)
To: Alejandro Colomar; +Cc: Joseph Myers, Martin Uecker, Jens Gustedt, gcc-patches
On Thu, Aug 08, 2024 at 10:01:14PM +0200, Alejandro Colomar wrote:
> Hi Joseph,
>
> On Thu, Aug 08, 2024 at 05:31:05PM GMT, Joseph Myers wrote:
> > Actual bugs should of course be fixed.
>
> Here are the suspects:
>
> ./gcc/testsuite/gcc.target/powerpc/sse3-addsubps.c:80:
> for (i = 0; i < sizeof (vals) / sizeof (vals); i += 8)
>
> ./gcc/c-family/c-pragma.cc:1811:
> = sizeof (omp_pragmas_simd) / sizeof (*omp_pragmas);
>
> The second sizeof expression seems to have a bogus operand, and the
> correct one is probably the common one in sizeof divisions.
While the c-pragma one looks suspect and should be using ARRAY_SIZE (I'll
post a patch), it actually works correctly.
Both omp_pragmas and omp_pragmas_simd are arrays of the same structure, so
whether it divides by sizeof (*omp_pragmas) or sizeof (*omp_pragmas_simd)
or sizeof (omp_pragmas_simd[0]) doesn't matter.
Jakub
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [PATCH v5 3/3] c: Add __lengthof__ operator
2024-08-08 20:01 ` Alejandro Colomar
2024-08-08 20:36 ` Joseph Myers
2024-08-08 22:43 ` Jakub Jelinek
@ 2024-08-08 22:48 ` Jakub Jelinek
2024-08-10 8:57 ` [committed] testsuite: Fix up sse3-addsubps.c Jakub Jelinek
3 siblings, 0 replies; 248+ messages in thread
From: Jakub Jelinek @ 2024-08-08 22:48 UTC (permalink / raw)
To: Alejandro Colomar; +Cc: Joseph Myers, Martin Uecker, Jens Gustedt, gcc-patches
On Thu, Aug 08, 2024 at 10:01:14PM +0200, Alejandro Colomar wrote:
> ./libstdc++-v3/testsuite/21_strings/basic_string/cons/char/constexpr.cc:62:
> const auto len = (sizeof(cs) - 1)/sizeof(C);
> ./libstdc++-v3/testsuite/21_strings/basic_string/cons/wchar_t/constexpr.cc:62:
> const auto len = (sizeof(cs) - 1)/sizeof(C);
>
> Which would read better as sizeof/sizeof - 1.
>
> There are others which also could be improved in readability terms, but
> I don't think it's worth bikeshedding that at the moment. If you do a
> global switch to ARRAY_SIZE(), I can help with those. I'll keep the
> commit in the backyard in case we need it for something.
E.g. in testcases, we definitely don't want to use ARRAY_SIZE, at least most
of them should be self-contained if possible, include as few headers as
posible etc.
Jakub
^ permalink raw reply [flat|nested] 248+ messages in thread
* [PATCH v6 0/3] c: Add __lengthof__ operator
2024-07-28 14:15 ` [RFC v1 0/2] c: Add _Lengthof operator Alejandro Colomar
` (7 preceding siblings ...)
2024-08-06 23:11 ` [PATCH v5 0/3] " Alejandro Colomar
@ 2024-08-09 13:58 ` Alejandro Colomar
2024-08-09 13:59 ` [PATCH v6 1/3] gcc/: Rename array_type_nelts() => array_type_nelts_minus_one() Alejandro Colomar
` (13 subsequent siblings)
22 siblings, 0 replies; 248+ messages in thread
From: Alejandro Colomar @ 2024-08-09 13:58 UTC (permalink / raw)
To: gcc-patches
Cc: Alejandro Colomar, Martin Uecker, Xavier Del Campo Romero,
Joseph Myers, Gabriel Ravier, Jakub Jelinek, Kees Cook,
Qing Zhao, Jens Gustedt, David Brown, Florian Weimer,
Andreas Schwab, Timm Baeder
[-- Attachment #1: Type: text/plain, Size: 14707 bytes --]
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 <josmyers@redhat.com>
Cc: Gabriel Ravier <gabravier@gmail.com>
@@ Commit message
Cc: David Brown <david.brown@hesbynett.no>
Cc: Florian Weimer <fweimer@redhat.com>
Cc: Andreas Schwab <schwab@linux-m68k.org>
+ Cc: Timm Baeder <tbaeder@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
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 248+ messages in thread
* [PATCH v6 1/3] gcc/: Rename array_type_nelts() => array_type_nelts_minus_one()
2024-07-28 14:15 ` [RFC v1 0/2] c: Add _Lengthof operator Alejandro Colomar
` (8 preceding siblings ...)
2024-08-09 13:58 ` [PATCH v6 0/3] c: Add __lengthof__ operator Alejandro Colomar
@ 2024-08-09 13:59 ` Alejandro Colomar
2024-08-09 13:59 ` [PATCH v6 2/3] Merge definitions of array_type_nelts_top() Alejandro Colomar
` (12 subsequent siblings)
22 siblings, 0 replies; 248+ messages in thread
From: Alejandro Colomar @ 2024-08-09 13:59 UTC (permalink / raw)
To: gcc-patches
Cc: Alejandro Colomar, Martin Uecker, Xavier Del Campo Romero,
Joseph Myers, Gabriel Ravier, Jakub Jelinek, Kees Cook,
Qing Zhao, Jens Gustedt, David Brown, Florian Weimer,
Andreas Schwab, Timm Baeder, Richard Biener
[-- Attachment #1: Type: text/plain, Size: 12983 bytes --]
The old name was misleading.
While at it, also rename some temporary variables that are used with
this function, for consistency.
Link: https://inbox.sourceware.org/gcc-patches/9fffd80-dca-2c7e-14b-6c9b509a7215@redhat.com/T/#m2f661c67c8f7b2c405c8c7fc3152dd85dc729120
Cc: Gabriel Ravier <gabravier@gmail.com>
Cc: Martin Uecker <uecker@tugraz.at>
Cc: Joseph Myers <josmyers@redhat.com>
Cc: Xavier Del Campo Romero <xavi.dcr@tutanota.com>
Cc: Jakub Jelinek <jakub@redhat.com>
gcc/ChangeLog:
* tree.cc (array_type_nelts): Rename function ...
(array_type_nelts_minus_one): ... to this name. The old name
was misleading.
* tree.h (array_type_nelts): Rename function ...
(array_type_nelts_minus_one): ... to this name. The old name
was misleading.
* expr.cc (count_type_elements):
Rename array_type_nelts() => array_type_nelts_minus_one()
* config/aarch64/aarch64.cc
(pure_scalable_type_info::analyze_array): Likewise.
* config/i386/i386.cc (ix86_canonical_va_list_type): Likewise.
gcc/c/ChangeLog:
* c-decl.cc (one_element_array_type_p, get_parm_array_spec):
Rename array_type_nelts() => array_type_nelts_minus_one()
* c-fold.cc (c_fold_array_ref): Likewise.
gcc/cp/ChangeLog:
* decl.cc (reshape_init_array):
Rename array_type_nelts() => array_type_nelts_minus_one()
* init.cc (build_zero_init_1): Likewise.
(build_value_init_noctor): Likewise.
(build_vec_init): Likewise.
(build_delete): Likewise.
* lambda.cc (add_capture): Likewise.
* tree.cc (array_type_nelts_top): Likewise.
gcc/fortran/ChangeLog:
* trans-array.cc (structure_alloc_comps):
Rename array_type_nelts() => array_type_nelts_minus_one()
* trans-openmp.cc (gfc_walk_alloc_comps): Likewise.
(gfc_omp_clause_linear_ctor): Likewise.
gcc/rust/ChangeLog:
* backend/rust-tree.cc (array_type_nelts_top):
Rename array_type_nelts() => array_type_nelts_minus_one()
Suggested-by: Richard Biener <richard.guenther@gmail.com>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
---
gcc/c/c-decl.cc | 10 +++++-----
gcc/c/c-fold.cc | 7 ++++---
gcc/config/aarch64/aarch64.cc | 2 +-
gcc/config/i386/i386.cc | 2 +-
gcc/cp/decl.cc | 2 +-
gcc/cp/init.cc | 8 ++++----
gcc/cp/lambda.cc | 3 ++-
gcc/cp/tree.cc | 2 +-
gcc/expr.cc | 8 ++++----
gcc/fortran/trans-array.cc | 2 +-
gcc/fortran/trans-openmp.cc | 4 ++--
gcc/rust/backend/rust-tree.cc | 2 +-
gcc/tree.cc | 4 ++--
gcc/tree.h | 2 +-
14 files changed, 30 insertions(+), 28 deletions(-)
diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 8cef8f2c289..e7c2783e724 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -5309,7 +5309,7 @@ one_element_array_type_p (const_tree type)
{
if (TREE_CODE (type) != ARRAY_TYPE)
return false;
- return integer_zerop (array_type_nelts (type));
+ return integer_zerop (array_type_nelts_minus_one (type));
}
/* Determine whether TYPE is a zero-length array type "[0]". */
@@ -6257,15 +6257,15 @@ get_parm_array_spec (const struct c_parm *parm, tree attrs)
for (tree type = parm->specs->type; TREE_CODE (type) == ARRAY_TYPE;
type = TREE_TYPE (type))
{
- tree nelts = array_type_nelts (type);
- if (error_operand_p (nelts))
+ tree nelts_minus_one = array_type_nelts_minus_one (type);
+ if (error_operand_p (nelts_minus_one))
return attrs;
- if (TREE_CODE (nelts) != INTEGER_CST)
+ if (TREE_CODE (nelts_minus_one) != INTEGER_CST)
{
/* Each variable VLA bound is represented by the dollar
sign. */
spec += "$";
- tpbnds = tree_cons (NULL_TREE, nelts, tpbnds);
+ tpbnds = tree_cons (NULL_TREE, nelts_minus_one, tpbnds);
}
}
tpbnds = nreverse (tpbnds);
diff --git a/gcc/c/c-fold.cc b/gcc/c/c-fold.cc
index 57b67c74bd8..9ea174f79c4 100644
--- a/gcc/c/c-fold.cc
+++ b/gcc/c/c-fold.cc
@@ -73,11 +73,12 @@ c_fold_array_ref (tree type, tree ary, tree index)
unsigned elem_nchars = (TYPE_PRECISION (elem_type)
/ TYPE_PRECISION (char_type_node));
unsigned len = (unsigned) TREE_STRING_LENGTH (ary) / elem_nchars;
- tree nelts = array_type_nelts (TREE_TYPE (ary));
+ tree nelts_minus_one = array_type_nelts_minus_one (TREE_TYPE (ary));
bool dummy1 = true, dummy2 = true;
- nelts = c_fully_fold_internal (nelts, true, &dummy1, &dummy2, false, false);
+ nelts_minus_one = c_fully_fold_internal (nelts_minus_one, true, &dummy1,
+ &dummy2, false, false);
unsigned HOST_WIDE_INT i = tree_to_uhwi (index);
- if (!tree_int_cst_le (index, nelts)
+ if (!tree_int_cst_le (index, nelts_minus_one)
|| i >= len
|| i + elem_nchars > len)
return NULL_TREE;
diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
index 2ac5a22c848..a757796afcf 100644
--- a/gcc/config/aarch64/aarch64.cc
+++ b/gcc/config/aarch64/aarch64.cc
@@ -1083,7 +1083,7 @@ pure_scalable_type_info::analyze_array (const_tree type)
/* An array of unknown, flexible or variable length will be passed and
returned by reference whatever we do. */
- tree nelts_minus_one = array_type_nelts (type);
+ tree nelts_minus_one = array_type_nelts_minus_one (type);
if (!tree_fits_uhwi_p (nelts_minus_one))
return DOESNT_MATTER;
diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc
index 02e28290441..bc62de9a5f4 100644
--- a/gcc/config/i386/i386.cc
+++ b/gcc/config/i386/i386.cc
@@ -24518,7 +24518,7 @@ ix86_canonical_va_list_type (tree type)
return ms_va_list_type_node;
if ((TREE_CODE (type) == ARRAY_TYPE
- && integer_zerop (array_type_nelts (type)))
+ && integer_zerop (array_type_nelts_minus_one (type)))
|| POINTER_TYPE_P (type))
{
tree elem_type = TREE_TYPE (type);
diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index a468bfdb7b6..53d7ed7e327 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -6907,7 +6907,7 @@ reshape_init_array (tree type, reshape_iter *d, tree first_initializer_p,
gcc_assert (TREE_CODE (type) == ARRAY_TYPE);
if (TYPE_DOMAIN (type))
- max_index = array_type_nelts (type);
+ max_index = array_type_nelts_minus_one (type);
return reshape_init_array_1 (TREE_TYPE (type), max_index, d,
first_initializer_p, complain);
diff --git a/gcc/cp/init.cc b/gcc/cp/init.cc
index 20373d26988..493e64691cd 100644
--- a/gcc/cp/init.cc
+++ b/gcc/cp/init.cc
@@ -263,7 +263,7 @@ build_zero_init_1 (tree type, tree nelts, bool static_storage_p,
else if (TYPE_DOMAIN (type) == NULL_TREE)
return NULL_TREE;
else
- max_index = array_type_nelts (type);
+ max_index = array_type_nelts_minus_one (type);
/* If we have an error_mark here, we should just return error mark
as we don't know the size of the array yet. */
@@ -474,7 +474,7 @@ build_value_init_noctor (tree type, tsubst_flags_t complain)
vec<constructor_elt, va_gc> *v = NULL;
/* Iterate over the array elements, building initializations. */
- tree max_index = array_type_nelts (type);
+ tree max_index = array_type_nelts_minus_one (type);
/* If we have an error_mark here, we should just return error mark
as we don't know the size of the array yet. */
@@ -4519,7 +4519,7 @@ build_vec_init (tree base, tree maxindex, tree init,
: location_of (base));
if (TREE_CODE (atype) == ARRAY_TYPE && TYPE_DOMAIN (atype))
- maxindex = array_type_nelts (atype);
+ maxindex = array_type_nelts_minus_one (atype);
if (maxindex == NULL_TREE || maxindex == error_mark_node)
return error_mark_node;
@@ -5178,7 +5178,7 @@ build_delete (location_t loc, tree otype, tree addr,
error_at (loc, "unknown array size in delete");
return error_mark_node;
}
- return build_vec_delete (loc, addr, array_type_nelts (type),
+ return build_vec_delete (loc, addr, array_type_nelts_minus_one (type),
auto_delete, use_global_delete, complain);
}
diff --git a/gcc/cp/lambda.cc b/gcc/cp/lambda.cc
index 0770417810e..065113bc122 100644
--- a/gcc/cp/lambda.cc
+++ b/gcc/cp/lambda.cc
@@ -556,7 +556,8 @@ add_capture (tree lambda, tree id, tree orig_init, bool by_reference_p,
integer_zero_node, tf_warning_or_error);
initializer = build_constructor_va (init_list_type_node, 2,
NULL_TREE, build_address (elt),
- NULL_TREE, array_type_nelts (type));
+ NULL_TREE,
+ array_type_nelts_minus_one (type));
type = vla_capture_type (type);
}
else if (!dependent_type_p (type)
diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
index 31ecbb1ac79..040136c70ab 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -3088,7 +3088,7 @@ array_type_nelts_top (tree type)
{
return fold_build2_loc (input_location,
PLUS_EXPR, sizetype,
- array_type_nelts (type),
+ array_type_nelts_minus_one (type),
size_one_node);
}
diff --git a/gcc/expr.cc b/gcc/expr.cc
index 2089c2b86a9..cd0fcf15d6d 100644
--- a/gcc/expr.cc
+++ b/gcc/expr.cc
@@ -6991,14 +6991,14 @@ count_type_elements (const_tree type, bool for_ctor_p)
{
case ARRAY_TYPE:
{
- tree nelts;
+ tree nelts_minus_one;
- nelts = array_type_nelts (type);
- if (nelts && tree_fits_uhwi_p (nelts))
+ nelts_minus_one = array_type_nelts_minus_one (type);
+ if (nelts_minus_one && tree_fits_uhwi_p (nelts_minus_one))
{
unsigned HOST_WIDE_INT n;
- n = tree_to_uhwi (nelts) + 1;
+ n = tree_to_uhwi (nelts_minus_one) + 1;
if (n == 0 || for_ctor_p)
return n;
else
diff --git a/gcc/fortran/trans-array.cc b/gcc/fortran/trans-array.cc
index 9fb0b2b398d..e25f365362f 100644
--- a/gcc/fortran/trans-array.cc
+++ b/gcc/fortran/trans-array.cc
@@ -9711,7 +9711,7 @@ structure_alloc_comps (gfc_symbol * der_type, tree decl, tree dest,
else
{
/* Otherwise use the TYPE_DOMAIN information. */
- tmp = array_type_nelts (decl_type);
+ tmp = array_type_nelts_minus_one (decl_type);
tmp = fold_convert (gfc_array_index_type, tmp);
}
diff --git a/gcc/fortran/trans-openmp.cc b/gcc/fortran/trans-openmp.cc
index df1bf144e23..14cd2f9fad7 100644
--- a/gcc/fortran/trans-openmp.cc
+++ b/gcc/fortran/trans-openmp.cc
@@ -582,7 +582,7 @@ gfc_walk_alloc_comps (tree decl, tree dest, tree var,
tem = size_binop (MINUS_EXPR, tem, size_one_node);
}
else
- tem = array_type_nelts (type);
+ tem = array_type_nelts_minus_one (type);
tem = fold_convert (gfc_array_index_type, tem);
}
@@ -1309,7 +1309,7 @@ gfc_omp_clause_linear_ctor (tree clause, tree dest, tree src, tree add)
nelems = size_binop (MINUS_EXPR, nelems, size_one_node);
}
else
- nelems = array_type_nelts (type);
+ nelems = array_type_nelts_minus_one (type);
nelems = fold_convert (gfc_array_index_type, nelems);
gfc_omp_linear_clause_add_loop (&block, dest, src, add, nelems);
diff --git a/gcc/rust/backend/rust-tree.cc b/gcc/rust/backend/rust-tree.cc
index cdb79095da8..8d32e5203ae 100644
--- a/gcc/rust/backend/rust-tree.cc
+++ b/gcc/rust/backend/rust-tree.cc
@@ -869,7 +869,7 @@ tree
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
diff --git a/gcc/tree.cc b/gcc/tree.cc
index 17a5cea7c25..ed0a766016a 100644
--- a/gcc/tree.cc
+++ b/gcc/tree.cc
@@ -3698,7 +3698,7 @@ int_byte_position (const_tree field)
ARRAY_TYPE) minus one. This counts only elements of the top array. */
tree
-array_type_nelts (const_tree type)
+array_type_nelts_minus_one (const_tree type)
{
tree index_type, min, max;
@@ -14790,7 +14790,7 @@ is_empty_type (const_tree type)
return true;
}
else if (TREE_CODE (type) == ARRAY_TYPE)
- return (integer_minus_onep (array_type_nelts (type))
+ return (integer_minus_onep (array_type_nelts_minus_one (type))
|| TYPE_DOMAIN (type) == NULL_TREE
|| is_empty_type (TREE_TYPE (type)));
return false;
diff --git a/gcc/tree.h b/gcc/tree.h
index 5dcbb2fb5dd..69d40bb4f04 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -4921,7 +4921,7 @@ extern tree build_method_type_directly (tree, tree, tree);
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 value_member (tree, tree);
extern tree purpose_member (const_tree, tree);
--
2.45.2
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 248+ messages in thread
* [PATCH v6 2/3] Merge definitions of array_type_nelts_top()
2024-07-28 14:15 ` [RFC v1 0/2] c: Add _Lengthof operator Alejandro Colomar
` (9 preceding siblings ...)
2024-08-09 13:59 ` [PATCH v6 1/3] gcc/: Rename array_type_nelts() => array_type_nelts_minus_one() Alejandro Colomar
@ 2024-08-09 13:59 ` Alejandro Colomar
2024-08-09 13:59 ` [PATCH v6 3/3] c: Add __lengthof__ operator Alejandro Colomar
` (11 subsequent siblings)
22 siblings, 0 replies; 248+ messages in thread
From: Alejandro Colomar @ 2024-08-09 13:59 UTC (permalink / raw)
To: gcc-patches
Cc: Alejandro Colomar, Martin Uecker, Xavier Del Campo Romero,
Joseph Myers, Gabriel Ravier, Jakub Jelinek, Kees Cook,
Qing Zhao, Jens Gustedt, David Brown, Florian Weimer,
Andreas Schwab, Timm Baeder
[-- Attachment #1: Type: text/plain, Size: 4875 bytes --]
There were two identical definitions, and none of them are available
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__, which will be added in the following commit.
gcc/ChangeLog:
* tree.h (array_type_nelts_top):
* tree.cc (array_type_nelts_top): Define function (moved from
gcc/cp/).
gcc/cp/ChangeLog:
* cp-tree.h (array_type_nelts_top):
* tree.cc (array_type_nelts_top): Remove function (move
to gcc/).
gcc/rust/ChangeLog:
* backend/rust-tree.h (array_type_nelts_top):
* backend/rust-tree.cc (array_type_nelts_top): Remove function.
Signed-off-by: Alejandro Colomar <alx@kernel.org>
---
gcc/cp/cp-tree.h | 1 -
gcc/cp/tree.cc | 13 -------------
gcc/rust/backend/rust-tree.cc | 13 -------------
gcc/rust/backend/rust-tree.h | 2 --
gcc/tree.cc | 13 +++++++++++++
gcc/tree.h | 1 +
6 files changed, 14 insertions(+), 29 deletions(-)
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index b1693051231..76d7bc34577 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -8100,7 +8100,6 @@ extern tree build_exception_variant (tree, tree);
extern void fixup_deferred_exception_variants (tree, tree);
extern tree bind_template_template_parm (tree, tree);
extern tree array_type_nelts_total (tree);
-extern tree array_type_nelts_top (tree);
extern bool array_of_unknown_bound_p (const_tree);
extern tree break_out_target_exprs (tree, bool = false);
extern tree build_ctor_subob_ref (tree, tree, tree);
diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
index 040136c70ab..7d179491476 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -3079,19 +3079,6 @@ cxx_print_statistics (void)
depth_reached);
}
-/* Return, as an INTEGER_CST node, the number of elements for TYPE
- (which is an ARRAY_TYPE). This counts only elements of the top
- array. */
-
-tree
-array_type_nelts_top (tree type)
-{
- return fold_build2_loc (input_location,
- PLUS_EXPR, sizetype,
- array_type_nelts_minus_one (type),
- size_one_node);
-}
-
/* Return, as an INTEGER_CST node, the number of elements for TYPE
(which is an ARRAY_TYPE). This one is a recursive count of all
ARRAY_TYPEs that are clumped together. */
diff --git a/gcc/rust/backend/rust-tree.cc b/gcc/rust/backend/rust-tree.cc
index 8d32e5203ae..3dc6b076711 100644
--- a/gcc/rust/backend/rust-tree.cc
+++ b/gcc/rust/backend/rust-tree.cc
@@ -859,19 +859,6 @@ is_empty_class (tree type)
return CLASSTYPE_EMPTY_P (type);
}
-// forked from gcc/cp/tree.cc array_type_nelts_top
-
-/* Return, as an INTEGER_CST node, the number of elements for TYPE
- (which is an ARRAY_TYPE). This counts only elements of the top
- array. */
-
-tree
-array_type_nelts_top (tree type)
-{
- return fold_build2_loc (input_location, PLUS_EXPR, sizetype,
- array_type_nelts_minus_one (type), size_one_node);
-}
-
// forked from gcc/cp/tree.cc builtin_valid_in_constant_expr_p
/* Test whether DECL is a builtin that may appear in a
diff --git a/gcc/rust/backend/rust-tree.h b/gcc/rust/backend/rust-tree.h
index 26c8b653ac6..e597c3ab81d 100644
--- a/gcc/rust/backend/rust-tree.h
+++ b/gcc/rust/backend/rust-tree.h
@@ -2993,8 +2993,6 @@ extern location_t rs_expr_location (const_tree);
extern int
is_empty_class (tree type);
-extern tree array_type_nelts_top (tree);
-
extern bool
is_really_empty_class (tree, bool);
diff --git a/gcc/tree.cc b/gcc/tree.cc
index ed0a766016a..cedf95cc222 100644
--- a/gcc/tree.cc
+++ b/gcc/tree.cc
@@ -3729,6 +3729,19 @@ array_type_nelts_minus_one (const_tree type)
? max
: fold_build2 (MINUS_EXPR, TREE_TYPE (max), max, min));
}
+
+/* Return, as an INTEGER_CST node, the number of elements for TYPE
+ (which is an ARRAY_TYPE). This counts only elements of the top
+ array. */
+
+tree
+array_type_nelts_top (tree type)
+{
+ return fold_build2_loc (input_location,
+ PLUS_EXPR, sizetype,
+ array_type_nelts_minus_one (type),
+ size_one_node);
+}
\f
/* If arg is static -- a reference to an object in static storage -- then
return the object. This is not the same as the C meaning of `static'.
diff --git a/gcc/tree.h b/gcc/tree.h
index 69d40bb4f04..9061dafd027 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -4922,6 +4922,7 @@ 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_minus_one (const_tree);
+extern tree array_type_nelts_top (tree);
extern tree value_member (tree, tree);
extern tree purpose_member (const_tree, tree);
--
2.45.2
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 248+ messages in thread
* [PATCH v6 3/3] c: Add __lengthof__ operator
2024-07-28 14:15 ` [RFC v1 0/2] c: Add _Lengthof operator Alejandro Colomar
` (10 preceding siblings ...)
2024-08-09 13:59 ` [PATCH v6 2/3] Merge definitions of array_type_nelts_top() Alejandro Colomar
@ 2024-08-09 13:59 ` Alejandro Colomar
2024-08-09 15:51 ` Alejandro Colomar
2024-08-10 20:54 ` [PATCH v7 0/3] " Alejandro Colomar
` (10 subsequent siblings)
22 siblings, 1 reply; 248+ messages in thread
From: Alejandro Colomar @ 2024-08-09 13:59 UTC (permalink / raw)
To: gcc-patches
Cc: Alejandro Colomar, Martin Uecker, Xavier Del Campo Romero,
Joseph Myers, Gabriel Ravier, Jakub Jelinek, Kees Cook,
Qing Zhao, Jens Gustedt, David Brown, Florian Weimer,
Andreas Schwab, Timm Baeder
[-- Attachment #1: Type: text/plain, Size: 29832 bytes --]
This operator is similar to sizeof but can only be applied to an array,
and returns its length (number of elements).
FUTURE DIRECTIONS:
- 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 <josmyers@redhat.com>
Cc: Gabriel Ravier <gabravier@gmail.com>
Cc: Jakub Jelinek <jakub@redhat.com>
Cc: Kees Cook <keescook@chromium.org>
Cc: Qing Zhao <qing.zhao@oracle.com>
Cc: Jens Gustedt <jens.gustedt@inria.fr>
Cc: David Brown <david.brown@hesbynett.no>
Cc: Florian Weimer <fweimer@redhat.com>
Cc: Andreas Schwab <schwab@linux-m68k.org>
Cc: Timm Baeder <tbaeder@redhat.com>
gcc/ChangeLog:
* doc/extend.texi: Document __lengthof__ operator.
* target.h (enum type_context_kind): Add __lengthof__ operator.
gcc/c-family/ChangeLog:
* c-common.h:
* c-common.def:
* c-common.cc (c_lengthof_type): Add __lengthof__ operator.
gcc/c/ChangeLog:
* c-tree.h
(c_expr_lengthof_expr, c_expr_lengthof_type):
* c-decl.cc
(start_struct, finish_struct):
(start_enum, finish_enum):
* c-parser.cc
(c_parser_sizeof_expression):
(c_parser_lengthof_expression):
(c_parser_sizeof_or_lengthof_expression):
(c_parser_unary_expression):
* c-typeck.cc
(build_external_ref):
(record_maybe_used_decl, pop_maybe_used):
(is_top_array_vla):
(c_expr_lengthof_expr, c_expr_lengthof_type):
Add __lengthof__operator.
gcc/cp/ChangeLog:
* operators.def: Add __lengthof__ operator.
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
Link: https://inbox.sourceware.org/gcc/M8S4oQy--3-2@tutanota.com/T/
Suggested-by: Xavier Del Campo Romero <xavi.dcr@tutanota.com>
Co-developed-by: Martin Uecker <uecker@tugraz.at>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
---
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 | 20 +++-
gcc/c/c-parser.cc | 61 +++++++---
gcc/c/c-tree.h | 4 +
gcc/c/c-typeck.cc | 118 ++++++++++++++++++-
gcc/cp/operators.def | 1 +
gcc/doc/extend.texi | 31 +++++
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 ++++++++++++++++++++++++
13 files changed, 556 insertions(+), 24 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
diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
index e7e371fd26f..9f5feb83345 100644
--- a/gcc/c-family/c-common.cc
+++ b/gcc/c-family/c-common.cc
@@ -465,6 +465,7 @@ const struct c_common_resword c_common_reswords[] =
{ "__inline", RID_INLINE, 0 },
{ "__inline__", RID_INLINE, 0 },
{ "__label__", RID_LABEL, 0 },
+ { "__lengthof__", RID_LENGTHOF, 0 },
{ "__null", RID_NULL, 0 },
{ "__real", RID_REALPART, 0 },
{ "__real__", RID_REALPART, 0 },
@@ -4070,6 +4071,31 @@ c_alignof_expr (location_t loc, tree expr)
return fold_convert_loc (loc, size_type_node, t);
}
+
+/* Implement the lengthof keyword: Return the length of an array,
+ that is, the number of elements in the array. */
+
+tree
+c_lengthof_type (location_t loc, tree type)
+{
+ 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,
+ "invalid application of %<lengthof%> to incomplete type %qT",
+ type);
+ return error_mark_node;
+ }
+
+ return array_type_nelts_top (type);
+}
\f
/* Handle C and C++ default attributes. */
diff --git a/gcc/c-family/c-common.def b/gcc/c-family/c-common.def
index 5de96e5d4a8..6d162f67104 100644
--- a/gcc/c-family/c-common.def
+++ b/gcc/c-family/c-common.def
@@ -50,6 +50,9 @@ DEFTREECODE (EXCESS_PRECISION_EXPR, "excess_precision_expr", tcc_expression, 1)
number. */
DEFTREECODE (USERDEF_LITERAL, "userdef_literal", tcc_exceptional, 3)
+/* Represents a 'lengthof' expression. */
+DEFTREECODE (LENGTHOF_EXPR, "lengthof_expr", tcc_expression, 1)
+
/* Represents a 'sizeof' expression during C++ template expansion,
or for the purpose of -Wsizeof-pointer-memaccess warning. */
DEFTREECODE (SIZEOF_EXPR, "sizeof_expr", tcc_expression, 1)
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index 2510ee4dbc9..d2e7d7e8c40 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -105,6 +105,7 @@ enum rid
/* C extensions */
RID_ASM, RID_TYPEOF, RID_TYPEOF_UNQUAL, RID_ALIGNOF, RID_ATTRIBUTE,
+ RID_LENGTHOF,
RID_VA_ARG,
RID_EXTENSION, RID_IMAGPART, RID_REALPART, RID_LABEL, RID_CHOOSE_EXPR,
RID_TYPES_COMPATIBLE_P, RID_BUILTIN_COMPLEX, RID_BUILTIN_SHUFFLE,
@@ -885,6 +886,7 @@ extern tree c_common_truthvalue_conversion (location_t, tree);
extern void c_apply_type_quals_to_decl (int, tree);
extern tree c_sizeof_or_alignof_type (location_t, tree, bool, bool, int);
extern tree c_alignof_expr (location_t, tree);
+extern tree c_lengthof_type (location_t, tree);
/* Print an error message for invalid operands to arith operation CODE.
NOP_EXPR is used as a special case (see truthvalue_conversion). */
extern void binary_op_error (rich_location *, enum tree_code, tree, tree);
diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index e7c2783e724..6bacf8c8c23 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -8943,12 +8943,16 @@ start_struct (location_t loc, enum tree_code code, tree name,
within a statement expr used within sizeof, et. al. This is not
terribly serious as C++ doesn't permit statement exprs within
sizeof anyhow. */
- if (warn_cxx_compat && (in_sizeof || in_typeof || in_alignof))
+ if (warn_cxx_compat && (in_sizeof || in_typeof || in_alignof || in_lengthof))
warning_at (loc, OPT_Wc___compat,
"defining type in %qs expression is invalid in C++",
(in_sizeof
? "sizeof"
- : (in_typeof ? "typeof" : "alignof")));
+ : (in_typeof
+ ? "typeof"
+ : (in_alignof
+ ? "alignof"
+ : "lengthof"))));
if (in_underspecified_init)
error_at (loc, "%qT defined in underspecified object initializer", ref);
@@ -9908,7 +9912,7 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes,
struct_types. */
if (warn_cxx_compat
&& struct_parse_info != NULL
- && !in_sizeof && !in_typeof && !in_alignof)
+ && !in_sizeof && !in_typeof && !in_alignof && !in_lengthof)
struct_parse_info->struct_types.safe_push (t);
}
@@ -10082,12 +10086,16 @@ start_enum (location_t loc, struct c_enum_contents *the_enum, tree name,
/* FIXME: This will issue a warning for a use of a type defined
within sizeof in a statement expr. This is not terribly serious
as C++ doesn't permit statement exprs within sizeof anyhow. */
- if (warn_cxx_compat && (in_sizeof || in_typeof || in_alignof))
+ if (warn_cxx_compat && (in_sizeof || in_typeof || in_alignof || in_lengthof))
warning_at (loc, OPT_Wc___compat,
"defining type in %qs expression is invalid in C++",
(in_sizeof
? "sizeof"
- : (in_typeof ? "typeof" : "alignof")));
+ : (in_typeof
+ ? "typeof"
+ : (in_alignof
+ ? "alignof"
+ : "lengthof"))));
if (in_underspecified_init)
error_at (loc, "%qT defined in underspecified object initializer",
@@ -10281,7 +10289,7 @@ finish_enum (tree enumtype, tree values, tree attributes)
struct_types. */
if (warn_cxx_compat
&& struct_parse_info != NULL
- && !in_sizeof && !in_typeof && !in_alignof)
+ && !in_sizeof && !in_typeof && !in_alignof && !in_lengthof)
struct_parse_info->struct_types.safe_push (enumtype);
/* Check for consistency with previous definition */
diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
index 9b9284b1ba4..b30194d9218 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -74,7 +74,17 @@ along with GCC; see the file COPYING3. If not see
#include "bitmap.h"
#include "analyzer/analyzer-language.h"
#include "toplev.h"
+\f
+#define c_parser_sizeof_expression(parser) \
+( \
+ c_parser_sizeof_or_lengthof_expression (parser, RID_SIZEOF) \
+)
+#define c_parser_lengthof_expression(parser) \
+( \
+ c_parser_sizeof_or_lengthof_expression (parser, RID_LENGTHOF) \
+)
+\f
/* We need to walk over decls with incomplete struct/union/enum types
after parsing the whole translation unit.
In finish_decl(), if the decl is static, has incomplete
@@ -1694,7 +1704,7 @@ static struct c_expr c_parser_binary_expression (c_parser *, struct c_expr *,
tree);
static struct c_expr c_parser_cast_expression (c_parser *, struct c_expr *);
static struct c_expr c_parser_unary_expression (c_parser *);
-static struct c_expr c_parser_sizeof_expression (c_parser *);
+static struct c_expr c_parser_sizeof_or_lengthof_expression (c_parser *, enum rid);
static struct c_expr c_parser_alignof_expression (c_parser *);
static struct c_expr c_parser_postfix_expression (c_parser *);
static struct c_expr c_parser_postfix_expression_after_paren_type (c_parser *,
@@ -9909,6 +9919,8 @@ c_parser_unary_expression (c_parser *parser)
case CPP_KEYWORD:
switch (c_parser_peek_token (parser)->keyword)
{
+ case RID_LENGTHOF:
+ return c_parser_lengthof_expression (parser);
case RID_SIZEOF:
return c_parser_sizeof_expression (parser);
case RID_ALIGNOF:
@@ -9948,12 +9960,13 @@ c_parser_unary_expression (c_parser *parser)
/* Parse a sizeof expression. */
static struct c_expr
-c_parser_sizeof_expression (c_parser *parser)
+c_parser_sizeof_or_lengthof_expression (c_parser *parser, enum rid rid)
{
+ const char *op_name = (rid == RID_LENGTHOF) ? "lengthof" : "sizeof";
struct c_expr expr;
struct c_expr result;
location_t expr_loc;
- gcc_assert (c_parser_next_token_is_keyword (parser, RID_SIZEOF));
+ gcc_assert (c_parser_next_token_is_keyword (parser, rid));
location_t start;
location_t finish = UNKNOWN_LOCATION;
@@ -9962,7 +9975,10 @@ c_parser_sizeof_expression (c_parser *parser)
c_parser_consume_token (parser);
c_inhibit_evaluation_warnings++;
- in_sizeof++;
+ if (rid == RID_LENGTHOF)
+ in_lengthof++;
+ else
+ in_sizeof++;
if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)
&& c_token_starts_compound_literal (c_parser_peek_2nd_token (parser)))
{
@@ -9981,7 +9997,10 @@ c_parser_sizeof_expression (c_parser *parser)
{
struct c_expr ret;
c_inhibit_evaluation_warnings--;
- in_sizeof--;
+ if (rid == RID_LENGTHOF)
+ in_lengthof--;
+ else
+ in_sizeof--;
ret.set_error ();
ret.original_code = ERROR_MARK;
ret.original_type = NULL;
@@ -9993,31 +10012,45 @@ c_parser_sizeof_expression (c_parser *parser)
type_name,
expr_loc);
finish = expr.get_finish ();
- goto sizeof_expr;
+ goto Xof_expr;
}
/* sizeof ( type-name ). */
if (scspecs)
- error_at (expr_loc, "storage class specifier in %<sizeof%>");
+ error_at (expr_loc, "storage class specifier in %qs", op_name);
if (type_name->specs->alignas_p)
error_at (type_name->specs->locations[cdw_alignas],
- "alignment specified for type name in %<sizeof%>");
+ "alignment specified for type name in %qs", op_name);
c_inhibit_evaluation_warnings--;
- in_sizeof--;
- result = c_expr_sizeof_type (expr_loc, type_name);
+ if (rid == RID_LENGTHOF)
+ {
+ in_lengthof--;
+ result = c_expr_lengthof_type (expr_loc, type_name);
+ }
+ else
+ {
+ in_sizeof--;
+ result = c_expr_sizeof_type (expr_loc, type_name);
+ }
}
else
{
expr_loc = c_parser_peek_token (parser)->location;
expr = c_parser_unary_expression (parser);
finish = expr.get_finish ();
- sizeof_expr:
+ Xof_expr:
c_inhibit_evaluation_warnings--;
- in_sizeof--;
+ if (rid == RID_LENGTHOF)
+ in_lengthof--;
+ else
+ in_sizeof--;
mark_exp_read (expr.value);
if (TREE_CODE (expr.value) == COMPONENT_REF
&& DECL_C_BIT_FIELD (TREE_OPERAND (expr.value, 1)))
- error_at (expr_loc, "%<sizeof%> applied to a bit-field");
- result = c_expr_sizeof_expr (expr_loc, expr);
+ error_at (expr_loc, "%qs applied to a bit-field", op_name);
+ if (rid == RID_LENGTHOF)
+ result = c_expr_lengthof_expr (expr_loc, expr);
+ else
+ result = c_expr_sizeof_expr (expr_loc, expr);
}
if (finish == UNKNOWN_LOCATION)
finish = start;
diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h
index 3dc6338bf06..81cfe002961 100644
--- a/gcc/c/c-tree.h
+++ b/gcc/c/c-tree.h
@@ -736,6 +736,7 @@ extern int c_type_dwarf_attribute (const_tree, int);
/* in c-typeck.cc */
extern int in_alignof;
extern int in_sizeof;
+extern int in_lengthof;
extern int in_typeof;
extern bool c_in_omp_for;
extern bool c_omp_array_section_p;
@@ -786,6 +787,9 @@ extern tree build_external_ref (location_t, tree, bool, tree *);
extern void pop_maybe_used (bool);
extern struct c_expr c_expr_sizeof_expr (location_t, struct c_expr);
extern struct c_expr c_expr_sizeof_type (location_t, struct c_type_name *);
+extern struct c_expr c_expr_lengthof_expr (location_t, struct c_expr);
+extern struct c_expr c_expr_lengthof_type (location_t loc,
+ struct c_type_name *);
extern struct c_expr parser_build_unary_op (location_t, enum tree_code,
struct c_expr);
extern struct c_expr parser_build_binary_op (location_t,
diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index 094e41fa202..9a8bbd707e8 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -71,6 +71,9 @@ int in_alignof;
/* The level of nesting inside "sizeof". */
int in_sizeof;
+/* The level of nesting inside "lengthof". */
+int in_lengthof;
+
/* The level of nesting inside "typeof". */
int in_typeof;
@@ -3255,7 +3258,7 @@ build_external_ref (location_t loc, tree id, bool fun, tree *type)
if (TREE_CODE (ref) == FUNCTION_DECL && !in_alignof)
{
- if (!in_sizeof && !in_typeof)
+ if (!in_sizeof && !in_typeof && !in_lengthof)
C_DECL_USED (ref) = 1;
else if (DECL_INITIAL (ref) == NULL_TREE
&& DECL_EXTERNAL (ref)
@@ -3311,7 +3314,7 @@ struct maybe_used_decl
{
/* The decl. */
tree decl;
- /* The level seen at (in_sizeof + in_typeof). */
+ /* The level seen at (in_sizeof + in_typeof + in_lengthof). */
int level;
/* The next one at this level or above, or NULL. */
struct maybe_used_decl *next;
@@ -3329,7 +3332,7 @@ record_maybe_used_decl (tree decl)
{
struct maybe_used_decl *t = XOBNEW (&parser_obstack, struct maybe_used_decl);
t->decl = decl;
- t->level = in_sizeof + in_typeof;
+ t->level = in_sizeof + in_typeof + in_lengthof;
t->next = maybe_used_decls;
maybe_used_decls = t;
}
@@ -3343,7 +3346,7 @@ void
pop_maybe_used (bool used)
{
struct maybe_used_decl *p = maybe_used_decls;
- int cur_level = in_sizeof + in_typeof;
+ int cur_level = in_sizeof + in_typeof + in_lengthof;
while (p && p->level > cur_level)
{
if (used)
@@ -3453,6 +3456,113 @@ c_expr_sizeof_type (location_t loc, struct c_type_name *t)
return ret;
}
+static bool
+is_top_array_vla (tree type)
+{
+ bool zero, star, 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);
+ 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;
+}
+
+/* Return the result of lengthof applied to EXPR. */
+
+struct c_expr
+c_expr_lengthof_expr (location_t loc, struct c_expr expr)
+{
+ struct c_expr ret;
+ if (expr.value == error_mark_node)
+ {
+ ret.value = error_mark_node;
+ ret.original_code = ERROR_MARK;
+ ret.original_type = NULL;
+ ret.m_decimal = 0;
+ pop_maybe_used (false);
+ }
+ else
+ {
+ bool expr_const_operands = true;
+
+ tree folded_expr = c_fully_fold (expr.value, require_constant_value,
+ &expr_const_operands);
+ ret.value = c_lengthof_type (loc, TREE_TYPE (folded_expr));
+ c_last_sizeof_arg = expr.value;
+ c_last_sizeof_loc = loc;
+ ret.original_code = LENGTHOF_EXPR;
+ ret.original_type = NULL;
+ ret.m_decimal = 0;
+ 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),
+ folded_expr, ret.value);
+ C_MAYBE_CONST_EXPR_NON_CONST (ret.value) = !expr_const_operands;
+ SET_EXPR_LOCATION (ret.value, loc);
+ }
+ pop_maybe_used (is_top_array_vla (TREE_TYPE (folded_expr)));
+ }
+ return ret;
+}
+
+/* Return the result of lengthof applied to T, a structure for the type
+ name passed to _lengthof (rather than the type itself). LOC is the
+ location of the original expression. */
+
+struct c_expr
+c_expr_lengthof_type (location_t loc, struct c_type_name *t)
+{
+ tree type;
+ struct c_expr ret;
+ tree type_expr = NULL_TREE;
+ bool type_expr_const = true;
+ type = groktypename (t, &type_expr, &type_expr_const);
+ ret.value = c_lengthof_type (loc, type);
+ c_last_sizeof_arg = type;
+ c_last_sizeof_loc = loc;
+ ret.original_code = LENGTHOF_EXPR;
+ ret.original_type = NULL;
+ ret.m_decimal = 0;
+ if (type == error_mark_node)
+ {
+ ret.value = error_mark_node;
+ ret.original_code = ERROR_MARK;
+ }
+ else
+ if ((type_expr || TREE_CODE (ret.value) == INTEGER_CST)
+ && 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
+ the result of lengthof does not get folded to a constant by
+ c_fully_fold, because if the length is evaluated the result is
+ not constant and so constraints on zero or negative size
+ arrays must not be applied when this lengthof call is inside
+ another array declarator. */
+ if (!type_expr)
+ type_expr = integer_zero_node;
+ ret.value = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (ret.value),
+ type_expr, ret.value);
+ C_MAYBE_CONST_EXPR_NON_CONST (ret.value) = !type_expr_const;
+ }
+ pop_maybe_used (type != error_mark_node ? is_top_array_vla (type) : false);
+ return ret;
+}
+
/* Build a function call to function FUNCTION with parameters PARAMS.
The function call is at LOC.
PARAMS is a list--a chain of TREE_LIST nodes--in which the
diff --git a/gcc/cp/operators.def b/gcc/cp/operators.def
index d8878923602..d640ed8bd91 100644
--- a/gcc/cp/operators.def
+++ b/gcc/cp/operators.def
@@ -91,6 +91,7 @@ DEF_OPERATOR ("co_await", CO_AWAIT_EXPR, "aw", OVL_OP_FLAG_UNARY)
/* These are extensions. */
DEF_OPERATOR ("alignof", ALIGNOF_EXPR, "az", OVL_OP_FLAG_UNARY)
+DEF_OPERATOR ("__lengthof__", LENGTHOF_EXPR, "lz", OVL_OP_FLAG_UNARY)
DEF_OPERATOR ("__imag__", IMAGPART_EXPR, "v18__imag__", OVL_OP_FLAG_UNARY)
DEF_OPERATOR ("__real__", REALPART_EXPR, "v18__real__", OVL_OP_FLAG_UNARY)
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 89fe5db7aed..7aa6384a528 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -10466,6 +10466,37 @@ 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 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 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 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++]); // integer constant expression
+__lengthof__ (int [n++][7]); // run-time value; n++ is evaluated
+@end smallexample
+
@node Inline
@section An Inline Function is As Fast As a Macro
@cindex inline functions
diff --git a/gcc/target.h b/gcc/target.h
index 837651d273a..a596f3f4b43 100644
--- a/gcc/target.h
+++ b/gcc/target.h
@@ -245,6 +245,9 @@ enum type_context_kind {
/* Directly measuring the alignment of T. */
TCTX_ALIGNOF,
+ /* Directly measuring the length of array T. */
+ TCTX_LENGTHOF,
+
/* Creating objects of type T with static storage duration. */
TCTX_STATIC_STORAGE,
diff --git a/gcc/testsuite/gcc.dg/lengthof-compile.c b/gcc/testsuite/gcc.dg/lengthof-compile.c
new file mode 100644
index 00000000000..db2e323181f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/lengthof-compile.c
@@ -0,0 +1,115 @@
+/* { dg-do compile } */
+/* { dg-options "-Wno-declaration-after-statement -Wno-pedantic -Wno-vla" } */
+
+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[])
+{
+ __lengthof__ (x); /* { dg-error "incomplete" } */
+
+ /* We want to support the following one in the future,
+ but for now it should fail. */
+ __lengthof__ (p); /* { dg-error "invalid" } */
+}
+
+void
+fam (void)
+{
+ struct {
+ int x;
+ int fam[];
+ } s;
+
+ __lengthof__ (s.fam); /* { dg-error "incomplete" } */
+}
+
+void fix_fix (int i, char (*a)[3][5], int (*x)[__lengthof__ (*a)]);
+void fix_var (int i, char (*a)[3][i], int (*x)[__lengthof__ (*a)]);
+void fix_uns (int i, char (*a)[3][*], int (*x)[__lengthof__ (*a)]);
+
+void
+func (void)
+{
+ int i3[3];
+ int i5[5];
+ char c35[3][5];
+
+ fix_fix (5, &c35, &i3);
+ fix_fix (5, &c35, &i5); /* { dg-error "incompatible-pointer-types" } */
+
+ fix_var (5, &c35, &i3);
+ fix_var (5, &c35, &i5); /* { dg-error "incompatible-pointer-types" } */
+
+ 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"} */
+}
diff --git a/gcc/testsuite/gcc.dg/lengthof-vla.c b/gcc/testsuite/gcc.dg/lengthof-vla.c
new file mode 100644
index 00000000000..f415fcf5a89
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/lengthof-vla.c
@@ -0,0 +1,46 @@
+/* { 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)];
diff --git a/gcc/testsuite/gcc.dg/lengthof.c b/gcc/testsuite/gcc.dg/lengthof.c
new file mode 100644
index 00000000000..86a530d613f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/lengthof.c
@@ -0,0 +1,150 @@
+/* { dg-do run } */
+/* { dg-options "-Wno-declaration-after-statement -Wno-pedantic -Wno-vla" } */
+
+#undef NDEBUG
+#include <assert.h>
+
+void
+array (void)
+{
+ short a[7];
+
+ 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
+vla (void)
+{
+ unsigned n;
+
+ n = 99;
+ assert (__lengthof__ (short [n - 10]) == 99 - 10);
+
+ int v[n / 2];
+ assert (__lengthof__ (v) == 99 / 2);
+
+ n = 0;
+ int z[n];
+ assert (__lengthof__ (z) == 0);
+}
+
+void
+member (void)
+{
+ struct {
+ int a[8];
+ } s;
+
+ static_assert (__lengthof__ (s.a) == 8);
+}
+
+void
+vla_eval (void)
+{
+ int i;
+
+ i = 7;
+ assert (__lengthof__ (struct {int x;}[i++]) == 7);
+ assert (i == 7 + 1);
+
+ int v[i];
+ int (*p)[i];
+ p = &v;
+ assert (__lengthof__ (*p++) == i);
+ assert (p - 1 == &v);
+}
+
+void
+inner_vla_noeval (void)
+{
+ int i;
+
+ i = 3;
+ static_assert (__lengthof__ (struct {int x[i++];}[3]) == 3);
+ assert (i == 3);
+}
+
+void
+array_noeval (void)
+{
+ long a[5];
+ long (*p)[__lengthof__ (a)];
+
+ p = &a;
+ static_assert (__lengthof__ (*p++) == 5);
+ assert (p == &a);
+}
+
+void
+matrix_zero (void)
+{
+ int i;
+
+ static_assert (__lengthof__ (int [0][4]) == 0);
+ i = 3;
+ assert (__lengthof__ (int [0][i]) == 0);
+}
+
+void
+matrix_fixed (void)
+{
+ int i;
+
+ static_assert (__lengthof__ (int [7][4]) == 7);
+ i = 3;
+ static_assert (__lengthof__ (int [7][i]) == 7);
+}
+
+void
+matrix_vla (void)
+{
+ int i, j;
+
+ i = 7;
+ assert (__lengthof__ (int [i++][4]) == 7);
+ assert (i == 7 + 1);
+
+ i = 9;
+ j = 3;
+ assert (__lengthof__ (int [i++][j]) == 9);
+ 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 ();
+ inner_vla_noeval ();
+ array_noeval ();
+ matrix_zero ();
+ matrix_fixed ();
+ matrix_vla ();
+ no_parens ();
+}
--
2.45.2
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 248+ messages in thread
* Re: [PATCH v6 3/3] c: Add __lengthof__ operator
2024-08-09 13:59 ` [PATCH v6 3/3] c: Add __lengthof__ operator Alejandro Colomar
@ 2024-08-09 15:51 ` Alejandro Colomar
0 siblings, 0 replies; 248+ messages in thread
From: Alejandro Colomar @ 2024-08-09 15:51 UTC (permalink / raw)
To: gcc-patches
Cc: Martin Uecker, Xavier Del Campo Romero, Joseph Myers,
Gabriel Ravier, Jakub Jelinek, Kees Cook, Qing Zhao,
Jens Gustedt, David Brown, Florian Weimer, Andreas Schwab,
Timm Baeder
[-- Attachment #1: Type: text/plain, Size: 32857 bytes --]
On Fri, Aug 09, 2024 at 03:59:19PM GMT, Alejandro Colomar wrote:
> This operator is similar to sizeof but can only be applied to an array,
> and returns its length (number of elements).
>
> FUTURE DIRECTIONS:
>
> - 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 <josmyers@redhat.com>
> Cc: Gabriel Ravier <gabravier@gmail.com>
> Cc: Jakub Jelinek <jakub@redhat.com>
> Cc: Kees Cook <keescook@chromium.org>
> Cc: Qing Zhao <qing.zhao@oracle.com>
> Cc: Jens Gustedt <jens.gustedt@inria.fr>
> Cc: David Brown <david.brown@hesbynett.no>
> Cc: Florian Weimer <fweimer@redhat.com>
> Cc: Andreas Schwab <schwab@linux-m68k.org>
> Cc: Timm Baeder <tbaeder@redhat.com>
>
> gcc/ChangeLog:
>
> * doc/extend.texi: Document __lengthof__ operator.
> * target.h (enum type_context_kind): Add __lengthof__ operator.
>
> gcc/c-family/ChangeLog:
>
> * c-common.h:
> * c-common.def:
> * c-common.cc (c_lengthof_type): Add __lengthof__ operator.
>
> gcc/c/ChangeLog:
>
> * c-tree.h
> (c_expr_lengthof_expr, c_expr_lengthof_type):
> * c-decl.cc
> (start_struct, finish_struct):
> (start_enum, finish_enum):
> * c-parser.cc
> (c_parser_sizeof_expression):
> (c_parser_lengthof_expression):
> (c_parser_sizeof_or_lengthof_expression):
> (c_parser_unary_expression):
> * c-typeck.cc
> (build_external_ref):
> (record_maybe_used_decl, pop_maybe_used):
> (is_top_array_vla):
> (c_expr_lengthof_expr, c_expr_lengthof_type):
> Add __lengthof__operator.
>
> gcc/cp/ChangeLog:
>
> * operators.def: Add __lengthof__ operator.
>
> 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
> Link: https://inbox.sourceware.org/gcc/M8S4oQy--3-2@tutanota.com/T/
> Suggested-by: Xavier Del Campo Romero <xavi.dcr@tutanota.com>
> Co-developed-by: Martin Uecker <uecker@tugraz.at>
> Signed-off-by: Alejandro Colomar <alx@kernel.org>
> ---
> 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 | 20 +++-
> gcc/c/c-parser.cc | 61 +++++++---
> gcc/c/c-tree.h | 4 +
> gcc/c/c-typeck.cc | 118 ++++++++++++++++++-
> gcc/cp/operators.def | 1 +
> gcc/doc/extend.texi | 31 +++++
> 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 ++++++++++++++++++++++++
> 13 files changed, 556 insertions(+), 24 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
>
> diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
> index e7e371fd26f..9f5feb83345 100644
> --- a/gcc/c-family/c-common.cc
> +++ b/gcc/c-family/c-common.cc
> @@ -465,6 +465,7 @@ const struct c_common_resword c_common_reswords[] =
> { "__inline", RID_INLINE, 0 },
> { "__inline__", RID_INLINE, 0 },
> { "__label__", RID_LABEL, 0 },
> + { "__lengthof__", RID_LENGTHOF, 0 },
> { "__null", RID_NULL, 0 },
> { "__real", RID_REALPART, 0 },
> { "__real__", RID_REALPART, 0 },
> @@ -4070,6 +4071,31 @@ c_alignof_expr (location_t loc, tree expr)
>
> return fold_convert_loc (loc, size_type_node, t);
> }
> +
> +/* Implement the lengthof keyword: Return the length of an array,
> + that is, the number of elements in the array. */
> +
> +tree
> +c_lengthof_type (location_t loc, tree type)
> +{
> + 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,
> + "invalid application of %<lengthof%> to incomplete type %qT",
> + type);
> + return error_mark_node;
> + }
> +
> + return array_type_nelts_top (type);
> +}
> \f
> /* Handle C and C++ default attributes. */
>
> diff --git a/gcc/c-family/c-common.def b/gcc/c-family/c-common.def
> index 5de96e5d4a8..6d162f67104 100644
> --- a/gcc/c-family/c-common.def
> +++ b/gcc/c-family/c-common.def
> @@ -50,6 +50,9 @@ DEFTREECODE (EXCESS_PRECISION_EXPR, "excess_precision_expr", tcc_expression, 1)
> number. */
> DEFTREECODE (USERDEF_LITERAL, "userdef_literal", tcc_exceptional, 3)
>
> +/* Represents a 'lengthof' expression. */
> +DEFTREECODE (LENGTHOF_EXPR, "lengthof_expr", tcc_expression, 1)
> +
> /* Represents a 'sizeof' expression during C++ template expansion,
> or for the purpose of -Wsizeof-pointer-memaccess warning. */
> DEFTREECODE (SIZEOF_EXPR, "sizeof_expr", tcc_expression, 1)
> diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
> index 2510ee4dbc9..d2e7d7e8c40 100644
> --- a/gcc/c-family/c-common.h
> +++ b/gcc/c-family/c-common.h
> @@ -105,6 +105,7 @@ enum rid
>
> /* C extensions */
> RID_ASM, RID_TYPEOF, RID_TYPEOF_UNQUAL, RID_ALIGNOF, RID_ATTRIBUTE,
> + RID_LENGTHOF,
> RID_VA_ARG,
> RID_EXTENSION, RID_IMAGPART, RID_REALPART, RID_LABEL, RID_CHOOSE_EXPR,
> RID_TYPES_COMPATIBLE_P, RID_BUILTIN_COMPLEX, RID_BUILTIN_SHUFFLE,
> @@ -885,6 +886,7 @@ extern tree c_common_truthvalue_conversion (location_t, tree);
> extern void c_apply_type_quals_to_decl (int, tree);
> extern tree c_sizeof_or_alignof_type (location_t, tree, bool, bool, int);
> extern tree c_alignof_expr (location_t, tree);
> +extern tree c_lengthof_type (location_t, tree);
> /* Print an error message for invalid operands to arith operation CODE.
> NOP_EXPR is used as a special case (see truthvalue_conversion). */
> extern void binary_op_error (rich_location *, enum tree_code, tree, tree);
> diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
> index e7c2783e724..6bacf8c8c23 100644
> --- a/gcc/c/c-decl.cc
> +++ b/gcc/c/c-decl.cc
> @@ -8943,12 +8943,16 @@ start_struct (location_t loc, enum tree_code code, tree name,
> within a statement expr used within sizeof, et. al. This is not
> terribly serious as C++ doesn't permit statement exprs within
> sizeof anyhow. */
> - if (warn_cxx_compat && (in_sizeof || in_typeof || in_alignof))
> + if (warn_cxx_compat && (in_sizeof || in_typeof || in_alignof || in_lengthof))
> warning_at (loc, OPT_Wc___compat,
> "defining type in %qs expression is invalid in C++",
> (in_sizeof
> ? "sizeof"
> - : (in_typeof ? "typeof" : "alignof")));
> + : (in_typeof
> + ? "typeof"
> + : (in_alignof
> + ? "alignof"
> + : "lengthof"))));
>
> if (in_underspecified_init)
> error_at (loc, "%qT defined in underspecified object initializer", ref);
> @@ -9908,7 +9912,7 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes,
> struct_types. */
> if (warn_cxx_compat
> && struct_parse_info != NULL
> - && !in_sizeof && !in_typeof && !in_alignof)
> + && !in_sizeof && !in_typeof && !in_alignof && !in_lengthof)
> struct_parse_info->struct_types.safe_push (t);
> }
>
> @@ -10082,12 +10086,16 @@ start_enum (location_t loc, struct c_enum_contents *the_enum, tree name,
> /* FIXME: This will issue a warning for a use of a type defined
> within sizeof in a statement expr. This is not terribly serious
> as C++ doesn't permit statement exprs within sizeof anyhow. */
> - if (warn_cxx_compat && (in_sizeof || in_typeof || in_alignof))
> + if (warn_cxx_compat && (in_sizeof || in_typeof || in_alignof || in_lengthof))
> warning_at (loc, OPT_Wc___compat,
> "defining type in %qs expression is invalid in C++",
> (in_sizeof
> ? "sizeof"
> - : (in_typeof ? "typeof" : "alignof")));
> + : (in_typeof
> + ? "typeof"
> + : (in_alignof
> + ? "alignof"
> + : "lengthof"))));
>
> if (in_underspecified_init)
> error_at (loc, "%qT defined in underspecified object initializer",
> @@ -10281,7 +10289,7 @@ finish_enum (tree enumtype, tree values, tree attributes)
> struct_types. */
> if (warn_cxx_compat
> && struct_parse_info != NULL
> - && !in_sizeof && !in_typeof && !in_alignof)
> + && !in_sizeof && !in_typeof && !in_alignof && !in_lengthof)
> struct_parse_info->struct_types.safe_push (enumtype);
>
> /* Check for consistency with previous definition */
> diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
> index 9b9284b1ba4..b30194d9218 100644
> --- a/gcc/c/c-parser.cc
> +++ b/gcc/c/c-parser.cc
> @@ -74,7 +74,17 @@ along with GCC; see the file COPYING3. If not see
> #include "bitmap.h"
> #include "analyzer/analyzer-language.h"
> #include "toplev.h"
> +\f
> +#define c_parser_sizeof_expression(parser) \
> +( \
> + c_parser_sizeof_or_lengthof_expression (parser, RID_SIZEOF) \
> +)
>
> +#define c_parser_lengthof_expression(parser) \
> +( \
> + c_parser_sizeof_or_lengthof_expression (parser, RID_LENGTHOF) \
> +)
> +\f
> /* We need to walk over decls with incomplete struct/union/enum types
> after parsing the whole translation unit.
> In finish_decl(), if the decl is static, has incomplete
> @@ -1694,7 +1704,7 @@ static struct c_expr c_parser_binary_expression (c_parser *, struct c_expr *,
> tree);
> static struct c_expr c_parser_cast_expression (c_parser *, struct c_expr *);
> static struct c_expr c_parser_unary_expression (c_parser *);
> -static struct c_expr c_parser_sizeof_expression (c_parser *);
> +static struct c_expr c_parser_sizeof_or_lengthof_expression (c_parser *, enum rid);
> static struct c_expr c_parser_alignof_expression (c_parser *);
> static struct c_expr c_parser_postfix_expression (c_parser *);
> static struct c_expr c_parser_postfix_expression_after_paren_type (c_parser *,
> @@ -9909,6 +9919,8 @@ c_parser_unary_expression (c_parser *parser)
> case CPP_KEYWORD:
> switch (c_parser_peek_token (parser)->keyword)
> {
> + case RID_LENGTHOF:
> + return c_parser_lengthof_expression (parser);
> case RID_SIZEOF:
> return c_parser_sizeof_expression (parser);
> case RID_ALIGNOF:
> @@ -9948,12 +9960,13 @@ c_parser_unary_expression (c_parser *parser)
> /* Parse a sizeof expression. */
>
> static struct c_expr
> -c_parser_sizeof_expression (c_parser *parser)
> +c_parser_sizeof_or_lengthof_expression (c_parser *parser, enum rid rid)
> {
> + const char *op_name = (rid == RID_LENGTHOF) ? "lengthof" : "sizeof";
> struct c_expr expr;
> struct c_expr result;
> location_t expr_loc;
> - gcc_assert (c_parser_next_token_is_keyword (parser, RID_SIZEOF));
> + gcc_assert (c_parser_next_token_is_keyword (parser, rid));
>
> location_t start;
> location_t finish = UNKNOWN_LOCATION;
> @@ -9962,7 +9975,10 @@ c_parser_sizeof_expression (c_parser *parser)
>
> c_parser_consume_token (parser);
> c_inhibit_evaluation_warnings++;
> - in_sizeof++;
> + if (rid == RID_LENGTHOF)
> + in_lengthof++;
> + else
> + in_sizeof++;
> if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)
> && c_token_starts_compound_literal (c_parser_peek_2nd_token (parser)))
> {
> @@ -9981,7 +9997,10 @@ c_parser_sizeof_expression (c_parser *parser)
> {
> struct c_expr ret;
> c_inhibit_evaluation_warnings--;
> - in_sizeof--;
> + if (rid == RID_LENGTHOF)
> + in_lengthof--;
> + else
> + in_sizeof--;
> ret.set_error ();
> ret.original_code = ERROR_MARK;
> ret.original_type = NULL;
> @@ -9993,31 +10012,45 @@ c_parser_sizeof_expression (c_parser *parser)
> type_name,
> expr_loc);
> finish = expr.get_finish ();
> - goto sizeof_expr;
> + goto Xof_expr;
> }
> /* sizeof ( type-name ). */
> if (scspecs)
> - error_at (expr_loc, "storage class specifier in %<sizeof%>");
> + error_at (expr_loc, "storage class specifier in %qs", op_name);
> if (type_name->specs->alignas_p)
> error_at (type_name->specs->locations[cdw_alignas],
> - "alignment specified for type name in %<sizeof%>");
> + "alignment specified for type name in %qs", op_name);
> c_inhibit_evaluation_warnings--;
> - in_sizeof--;
> - result = c_expr_sizeof_type (expr_loc, type_name);
> + if (rid == RID_LENGTHOF)
> + {
> + in_lengthof--;
> + result = c_expr_lengthof_type (expr_loc, type_name);
> + }
> + else
> + {
> + in_sizeof--;
> + result = c_expr_sizeof_type (expr_loc, type_name);
> + }
> }
> else
> {
> expr_loc = c_parser_peek_token (parser)->location;
> expr = c_parser_unary_expression (parser);
> finish = expr.get_finish ();
> - sizeof_expr:
> + Xof_expr:
> c_inhibit_evaluation_warnings--;
> - in_sizeof--;
> + if (rid == RID_LENGTHOF)
> + in_lengthof--;
> + else
> + in_sizeof--;
> mark_exp_read (expr.value);
> if (TREE_CODE (expr.value) == COMPONENT_REF
> && DECL_C_BIT_FIELD (TREE_OPERAND (expr.value, 1)))
> - error_at (expr_loc, "%<sizeof%> applied to a bit-field");
> - result = c_expr_sizeof_expr (expr_loc, expr);
> + error_at (expr_loc, "%qs applied to a bit-field", op_name);
> + if (rid == RID_LENGTHOF)
> + result = c_expr_lengthof_expr (expr_loc, expr);
> + else
> + result = c_expr_sizeof_expr (expr_loc, expr);
> }
> if (finish == UNKNOWN_LOCATION)
> finish = start;
> diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h
> index 3dc6338bf06..81cfe002961 100644
> --- a/gcc/c/c-tree.h
> +++ b/gcc/c/c-tree.h
> @@ -736,6 +736,7 @@ extern int c_type_dwarf_attribute (const_tree, int);
> /* in c-typeck.cc */
> extern int in_alignof;
> extern int in_sizeof;
> +extern int in_lengthof;
> extern int in_typeof;
> extern bool c_in_omp_for;
> extern bool c_omp_array_section_p;
> @@ -786,6 +787,9 @@ extern tree build_external_ref (location_t, tree, bool, tree *);
> extern void pop_maybe_used (bool);
> extern struct c_expr c_expr_sizeof_expr (location_t, struct c_expr);
> extern struct c_expr c_expr_sizeof_type (location_t, struct c_type_name *);
> +extern struct c_expr c_expr_lengthof_expr (location_t, struct c_expr);
> +extern struct c_expr c_expr_lengthof_type (location_t loc,
> + struct c_type_name *);
> extern struct c_expr parser_build_unary_op (location_t, enum tree_code,
> struct c_expr);
> extern struct c_expr parser_build_binary_op (location_t,
> diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
> index 094e41fa202..9a8bbd707e8 100644
> --- a/gcc/c/c-typeck.cc
> +++ b/gcc/c/c-typeck.cc
> @@ -71,6 +71,9 @@ int in_alignof;
> /* The level of nesting inside "sizeof". */
> int in_sizeof;
>
> +/* The level of nesting inside "lengthof". */
> +int in_lengthof;
> +
> /* The level of nesting inside "typeof". */
> int in_typeof;
>
> @@ -3255,7 +3258,7 @@ build_external_ref (location_t loc, tree id, bool fun, tree *type)
>
> if (TREE_CODE (ref) == FUNCTION_DECL && !in_alignof)
> {
> - if (!in_sizeof && !in_typeof)
> + if (!in_sizeof && !in_typeof && !in_lengthof)
> C_DECL_USED (ref) = 1;
> else if (DECL_INITIAL (ref) == NULL_TREE
> && DECL_EXTERNAL (ref)
> @@ -3311,7 +3314,7 @@ struct maybe_used_decl
> {
> /* The decl. */
> tree decl;
> - /* The level seen at (in_sizeof + in_typeof). */
> + /* The level seen at (in_sizeof + in_typeof + in_lengthof). */
> int level;
> /* The next one at this level or above, or NULL. */
> struct maybe_used_decl *next;
> @@ -3329,7 +3332,7 @@ record_maybe_used_decl (tree decl)
> {
> struct maybe_used_decl *t = XOBNEW (&parser_obstack, struct maybe_used_decl);
> t->decl = decl;
> - t->level = in_sizeof + in_typeof;
> + t->level = in_sizeof + in_typeof + in_lengthof;
> t->next = maybe_used_decls;
> maybe_used_decls = t;
> }
> @@ -3343,7 +3346,7 @@ void
> pop_maybe_used (bool used)
> {
> struct maybe_used_decl *p = maybe_used_decls;
> - int cur_level = in_sizeof + in_typeof;
> + int cur_level = in_sizeof + in_typeof + in_lengthof;
> while (p && p->level > cur_level)
> {
> if (used)
> @@ -3453,6 +3456,113 @@ c_expr_sizeof_type (location_t loc, struct c_type_name *t)
> return ret;
> }
>
> +static bool
> +is_top_array_vla (tree type)
> +{
> + bool zero, star, 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);
> + 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;
> +}
> +
> +/* Return the result of lengthof applied to EXPR. */
> +
> +struct c_expr
> +c_expr_lengthof_expr (location_t loc, struct c_expr expr)
> +{
> + struct c_expr ret;
> + if (expr.value == error_mark_node)
> + {
> + ret.value = error_mark_node;
> + ret.original_code = ERROR_MARK;
> + ret.original_type = NULL;
> + ret.m_decimal = 0;
> + pop_maybe_used (false);
> + }
> + else
> + {
> + bool expr_const_operands = true;
> +
> + tree folded_expr = c_fully_fold (expr.value, require_constant_value,
> + &expr_const_operands);
> + ret.value = c_lengthof_type (loc, TREE_TYPE (folded_expr));
> + c_last_sizeof_arg = expr.value;
> + c_last_sizeof_loc = loc;
> + ret.original_code = LENGTHOF_EXPR;
> + ret.original_type = NULL;
> + ret.m_decimal = 0;
> + 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),
> + folded_expr, ret.value);
> + C_MAYBE_CONST_EXPR_NON_CONST (ret.value) = !expr_const_operands;
> + SET_EXPR_LOCATION (ret.value, loc);
> + }
> + pop_maybe_used (is_top_array_vla (TREE_TYPE (folded_expr)));
> + }
> + return ret;
> +}
> +
> +/* Return the result of lengthof applied to T, a structure for the type
> + name passed to _lengthof (rather than the type itself). LOC is the
> + location of the original expression. */
> +
> +struct c_expr
> +c_expr_lengthof_type (location_t loc, struct c_type_name *t)
> +{
> + tree type;
> + struct c_expr ret;
> + tree type_expr = NULL_TREE;
> + bool type_expr_const = true;
> + type = groktypename (t, &type_expr, &type_expr_const);
> + ret.value = c_lengthof_type (loc, type);
> + c_last_sizeof_arg = type;
> + c_last_sizeof_loc = loc;
> + ret.original_code = LENGTHOF_EXPR;
> + ret.original_type = NULL;
> + ret.m_decimal = 0;
> + if (type == error_mark_node)
> + {
> + ret.value = error_mark_node;
> + ret.original_code = ERROR_MARK;
> + }
> + else
> + if ((type_expr || TREE_CODE (ret.value) == INTEGER_CST)
> + && 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
> + the result of lengthof does not get folded to a constant by
> + c_fully_fold, because if the length is evaluated the result is
> + not constant and so constraints on zero or negative size
> + arrays must not be applied when this lengthof call is inside
> + another array declarator. */
> + if (!type_expr)
> + type_expr = integer_zero_node;
> + ret.value = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (ret.value),
> + type_expr, ret.value);
> + C_MAYBE_CONST_EXPR_NON_CONST (ret.value) = !type_expr_const;
> + }
> + pop_maybe_used (type != error_mark_node ? is_top_array_vla (type) : false);
> + return ret;
> +}
> +
> /* Build a function call to function FUNCTION with parameters PARAMS.
> The function call is at LOC.
> PARAMS is a list--a chain of TREE_LIST nodes--in which the
> diff --git a/gcc/cp/operators.def b/gcc/cp/operators.def
> index d8878923602..d640ed8bd91 100644
> --- a/gcc/cp/operators.def
> +++ b/gcc/cp/operators.def
> @@ -91,6 +91,7 @@ DEF_OPERATOR ("co_await", CO_AWAIT_EXPR, "aw", OVL_OP_FLAG_UNARY)
>
> /* These are extensions. */
> DEF_OPERATOR ("alignof", ALIGNOF_EXPR, "az", OVL_OP_FLAG_UNARY)
> +DEF_OPERATOR ("__lengthof__", LENGTHOF_EXPR, "lz", OVL_OP_FLAG_UNARY)
> DEF_OPERATOR ("__imag__", IMAGPART_EXPR, "v18__imag__", OVL_OP_FLAG_UNARY)
> DEF_OPERATOR ("__real__", REALPART_EXPR, "v18__real__", OVL_OP_FLAG_UNARY)
>
> diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
> index 89fe5db7aed..7aa6384a528 100644
> --- a/gcc/doc/extend.texi
> +++ b/gcc/doc/extend.texi
> @@ -10466,6 +10466,37 @@ 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 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 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 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++]); // integer constant expression
> +__lengthof__ (int [n++][7]); // run-time value; n++ is evaluated
> +@end smallexample
> +
> @node Inline
> @section An Inline Function is As Fast As a Macro
> @cindex inline functions
> diff --git a/gcc/target.h b/gcc/target.h
> index 837651d273a..a596f3f4b43 100644
> --- a/gcc/target.h
> +++ b/gcc/target.h
> @@ -245,6 +245,9 @@ enum type_context_kind {
> /* Directly measuring the alignment of T. */
> TCTX_ALIGNOF,
>
> + /* Directly measuring the length of array T. */
> + TCTX_LENGTHOF,
> +
> /* Creating objects of type T with static storage duration. */
> TCTX_STATIC_STORAGE,
>
> diff --git a/gcc/testsuite/gcc.dg/lengthof-compile.c b/gcc/testsuite/gcc.dg/lengthof-compile.c
> new file mode 100644
> index 00000000000..db2e323181f
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/lengthof-compile.c
> @@ -0,0 +1,115 @@
> +/* { dg-do compile } */
> +/* { dg-options "-Wno-declaration-after-statement -Wno-pedantic -Wno-vla" } */
> +
> +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[])
> +{
> + __lengthof__ (x); /* { dg-error "incomplete" } */
> +
> + /* We want to support the following one in the future,
> + but for now it should fail. */
> + __lengthof__ (p); /* { dg-error "invalid" } */
> +}
> +
> +void
> +fam (void)
> +{
> + struct {
> + int x;
> + int fam[];
> + } s;
> +
> + __lengthof__ (s.fam); /* { dg-error "incomplete" } */
> +}
> +
> +void fix_fix (int i, char (*a)[3][5], int (*x)[__lengthof__ (*a)]);
> +void fix_var (int i, char (*a)[3][i], int (*x)[__lengthof__ (*a)]);
> +void fix_uns (int i, char (*a)[3][*], int (*x)[__lengthof__ (*a)]);
> +
> +void
> +func (void)
> +{
> + int i3[3];
> + int i5[5];
> + char c35[3][5];
> +
> + fix_fix (5, &c35, &i3);
> + fix_fix (5, &c35, &i5); /* { dg-error "incompatible-pointer-types" } */
> +
> + fix_var (5, &c35, &i3);
> + fix_var (5, &c35, &i5); /* { dg-error "incompatible-pointer-types" } */
> +
> + 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"} */
There was a small white-space problem with the tests above which I
forgot to include in the version I sent. It will be included in v7.
diff --git a/gcc/testsuite/gcc.dg/lengthof-compile.c b/gcc/testsuite/gcc.dg/lengthof-compile.c
index db2e323181f..72211fa5fa7 100644
--- a/gcc/testsuite/gcc.dg/lengthof-compile.c
+++ b/gcc/testsuite/gcc.dg/lengthof-compile.c
@@ -106,10 +106,10 @@ 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 [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"} */
+ _Static_assert (__lengthof__ (int [0][n]) == 0); /* { dg-error "not constant" } */
}
> +}
> diff --git a/gcc/testsuite/gcc.dg/lengthof-vla.c b/gcc/testsuite/gcc.dg/lengthof-vla.c
> new file mode 100644
> index 00000000000..f415fcf5a89
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/lengthof-vla.c
> @@ -0,0 +1,46 @@
> +/* { 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)];
> diff --git a/gcc/testsuite/gcc.dg/lengthof.c b/gcc/testsuite/gcc.dg/lengthof.c
> new file mode 100644
> index 00000000000..86a530d613f
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/lengthof.c
> @@ -0,0 +1,150 @@
> +/* { dg-do run } */
> +/* { dg-options "-Wno-declaration-after-statement -Wno-pedantic -Wno-vla" } */
> +
> +#undef NDEBUG
> +#include <assert.h>
> +
> +void
> +array (void)
> +{
> + short a[7];
> +
> + 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
> +vla (void)
> +{
> + unsigned n;
> +
> + n = 99;
> + assert (__lengthof__ (short [n - 10]) == 99 - 10);
> +
> + int v[n / 2];
> + assert (__lengthof__ (v) == 99 / 2);
> +
> + n = 0;
> + int z[n];
> + assert (__lengthof__ (z) == 0);
> +}
> +
> +void
> +member (void)
> +{
> + struct {
> + int a[8];
> + } s;
> +
> + static_assert (__lengthof__ (s.a) == 8);
> +}
> +
> +void
> +vla_eval (void)
> +{
> + int i;
> +
> + i = 7;
> + assert (__lengthof__ (struct {int x;}[i++]) == 7);
> + assert (i == 7 + 1);
> +
> + int v[i];
> + int (*p)[i];
> + p = &v;
> + assert (__lengthof__ (*p++) == i);
> + assert (p - 1 == &v);
> +}
> +
> +void
> +inner_vla_noeval (void)
> +{
> + int i;
> +
> + i = 3;
> + static_assert (__lengthof__ (struct {int x[i++];}[3]) == 3);
> + assert (i == 3);
> +}
> +
> +void
> +array_noeval (void)
> +{
> + long a[5];
> + long (*p)[__lengthof__ (a)];
> +
> + p = &a;
> + static_assert (__lengthof__ (*p++) == 5);
> + assert (p == &a);
> +}
> +
> +void
> +matrix_zero (void)
> +{
> + int i;
> +
> + static_assert (__lengthof__ (int [0][4]) == 0);
> + i = 3;
> + assert (__lengthof__ (int [0][i]) == 0);
> +}
> +
> +void
> +matrix_fixed (void)
> +{
> + int i;
> +
> + static_assert (__lengthof__ (int [7][4]) == 7);
> + i = 3;
> + static_assert (__lengthof__ (int [7][i]) == 7);
> +}
> +
> +void
> +matrix_vla (void)
> +{
> + int i, j;
> +
> + i = 7;
> + assert (__lengthof__ (int [i++][4]) == 7);
> + assert (i == 7 + 1);
> +
> + i = 9;
> + j = 3;
> + assert (__lengthof__ (int [i++][j]) == 9);
> + 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 ();
> + inner_vla_noeval ();
> + array_noeval ();
> + matrix_zero ();
> + matrix_fixed ();
> + matrix_vla ();
> + no_parens ();
> +}
> --
> 2.45.2
>
--
<https://www.alejandro-colomar.es/>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 248+ messages in thread
* [committed] testsuite: Fix up sse3-addsubps.c
2024-08-08 20:01 ` Alejandro Colomar
` (2 preceding siblings ...)
2024-08-08 22:48 ` Jakub Jelinek
@ 2024-08-10 8:57 ` Jakub Jelinek
2024-08-12 23:43 ` Alejandro Colomar
3 siblings, 1 reply; 248+ messages in thread
From: Jakub Jelinek @ 2024-08-10 8:57 UTC (permalink / raw)
To: Alejandro Colomar; +Cc: gcc-patches
On Thu, Aug 08, 2024 at 10:01:14PM +0200, Alejandro Colomar wrote:
> Here are the suspects:
>
> ./gcc/testsuite/gcc.target/powerpc/sse3-addsubps.c:80:
> for (i = 0; i < sizeof (vals) / sizeof (vals); i += 8)
This is an obvious typo as can be seen in what the test does, what similar
tests committed in the same commit do (all the others use sizeof (vals) /
sizeof (vals[0])) and what the test originates from (i386/sse3-addsubps.c
uses there constant 80, which is that sizeof (vals) / sizeof (vals[0])).
Tested on powerpc64-linux (where the test is UNSUPPORTED) and
powerpc64le-linux, where the test passes before (in that case it tests just
one vector rather than all 10) and after the change.
Committed to trunk as obvious.
2024-08-10 Jakub Jelinek <jakub@redhat.com>
* gcc.target/powerpc/sse3-addsubps.c (TEST): Divide by
sizeof (vals[0]) rather than sizeof (vals).
--- gcc/testsuite/gcc.target/powerpc/sse3-addsubps.c.jj3 2024-03-18 11:02:16.152884555 +0000
+++ gcc/testsuite/gcc.target/powerpc/sse3-addsubps.c 2024-08-10 08:46:57.259430503 +0000
@@ -77,7 +77,7 @@ TEST (void)
int i;
int fail = 0;
- for (i = 0; i < sizeof (vals) / sizeof (vals); i += 8)
+ for (i = 0; i < sizeof (vals) / sizeof (vals[0]); i += 8)
{
p1[0] = vals[i+0];
p1[1] = vals[i+1];
Jakub
^ permalink raw reply [flat|nested] 248+ messages in thread
* [PATCH v7 0/3] c: Add __lengthof__ operator
2024-07-28 14:15 ` [RFC v1 0/2] c: Add _Lengthof operator Alejandro Colomar
` (11 preceding siblings ...)
2024-08-09 13:59 ` [PATCH v6 3/3] c: Add __lengthof__ operator Alejandro Colomar
@ 2024-08-10 20:54 ` Alejandro Colomar
2024-08-10 20:54 ` [PATCH v7 1/3] gcc/: Rename array_type_nelts() => array_type_nelts_minus_one() Alejandro Colomar
` (2 more replies)
2024-08-11 23:46 ` [PATCH v8 0/3] " Alejandro Colomar
` (9 subsequent siblings)
22 siblings, 3 replies; 248+ messages in thread
From: Alejandro Colomar @ 2024-08-10 20:54 UTC (permalink / raw)
To: gcc-patches
Cc: Alejandro Colomar, Martin Uecker, Xavier Del Campo Romero,
Joseph Myers, Gabriel Ravier, Jakub Jelinek, Kees Cook,
Qing Zhao, Jens Gustedt, David Brown, Florian Weimer,
Andreas Schwab, Timm Baeder
[-- Attachment #1: Type: text/plain, Size: 3140 bytes --]
Hi!
v7:
- Tests:
- Fix 2 tests (whitespace fix).
- Fix typo in comment.
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/test