public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [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
                     ` (28 more replies)
  0 siblings, 29 replies; 318+ 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] 318+ 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
                     ` (27 subsequent siblings)
  28 siblings, 1 reply; 318+ 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] 318+ 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
                     ` (26 subsequent siblings)
  28 siblings, 0 replies; 318+ 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] 318+ 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
                     ` (25 subsequent siblings)
  28 siblings, 1 reply; 318+ 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] 318+ 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; 318+ 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] 318+ 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
                     ` (24 subsequent siblings)
  28 siblings, 2 replies; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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
                     ` (23 subsequent siblings)
  28 siblings, 1 reply; 318+ 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] 318+ 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; 318+ 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] 318+ 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
                     ` (22 subsequent siblings)
  28 siblings, 3 replies; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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
                     ` (21 subsequent siblings)
  28 siblings, 8 replies; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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
                     ` (20 subsequent siblings)
  28 siblings, 5 replies; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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 standardisa­tion we will give such considerations a careful look.

Jens
-- 
Jens Gustedt - INRIA & ICube, Strasbourg, France 

^ permalink raw reply	[flat|nested] 318+ 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; 318+ 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 standardisa­tion we will give such considerations a careful look.

> Jens


^ permalink raw reply	[flat|nested] 318+ 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; 318+ 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 standardisa­tion we will give such considerations a careful look.
> 
> > Jens
> 


-- 
Jens Gustedt - INRIA & ICube, Strasbourg, France

^ permalink raw reply	[flat|nested] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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
                     ` (19 subsequent siblings)
  28 siblings, 0 replies; 318+ 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] 318+ 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
                     ` (18 subsequent siblings)
  28 siblings, 0 replies; 318+ 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] 318+ 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
                     ` (17 subsequent siblings)
  28 siblings, 0 replies; 318+ 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] 318+ 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
                     ` (16 subsequent siblings)
  28 siblings, 1 reply; 318+ 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] 318+ 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; 318+ 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] 318+ 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; 318+ 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] 318+ 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
                     ` (15 subsequent siblings)
  28 siblings, 3 replies; 318+ 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/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 v6:
1:  8b68e250503 = 1:  8b68e250503 gcc/: Rename array_type_nelts() => array_type_nelts_minus_one()
2:  21433097103 = 2:  21433097103 Merge definitions of array_type_nelts_top()
3:  71fd2013967 ! 3:  4bd3837d09c c: Add __lengthof__ operator
    @@ gcc/testsuite/gcc.dg/lengthof-compile.c (new)
     +  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"} */
    ++  /* FIXME: lengthof(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) ##
-- 
2.45.2


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 318+ messages in thread

* [PATCH v7 1/3] gcc/: Rename array_type_nelts() => array_type_nelts_minus_one()
  2024-08-10 20:54   ` [PATCH v7 0/3] " Alejandro Colomar
@ 2024-08-10 20:54     ` Alejandro Colomar
  2024-08-10 20:54     ` [PATCH v7 2/3] Merge definitions of array_type_nelts_top() Alejandro Colomar
  2024-08-10 20:54     ` [PATCH v7 3/3] c: Add __lengthof__ operator Alejandro Colomar
  2 siblings, 0 replies; 318+ 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, 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] 318+ messages in thread

* [PATCH v7 2/3] Merge definitions of array_type_nelts_top()
  2024-08-10 20:54   ` [PATCH v7 0/3] " Alejandro Colomar
  2024-08-10 20:54     ` [PATCH v7 1/3] gcc/: Rename array_type_nelts() => array_type_nelts_minus_one() Alejandro Colomar
@ 2024-08-10 20:54     ` Alejandro Colomar
  2024-08-10 20:54     ` [PATCH v7 3/3] c: Add __lengthof__ operator Alejandro Colomar
  2 siblings, 0 replies; 318+ 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: 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] 318+ messages in thread

* [PATCH v7 3/3] c: Add __lengthof__ operator
  2024-08-10 20:54   ` [PATCH v7 0/3] " Alejandro Colomar
  2024-08-10 20:54     ` [PATCH v7 1/3] gcc/: Rename array_type_nelts() => array_type_nelts_minus_one() Alejandro Colomar
  2024-08-10 20:54     ` [PATCH v7 2/3] Merge definitions of array_type_nelts_top() Alejandro Colomar
@ 2024-08-10 20:54     ` Alejandro Colomar
  2 siblings, 0 replies; 318+ 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: 29834 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..297ffe75f60
--- /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: lengthof(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] 318+ messages in thread

* [PATCH v8 0/3] c: Add __lengthof__ operator
  2024-07-28 14:15 ` [RFC v1 0/2] c: Add _Lengthof operator Alejandro Colomar
                     ` (12 preceding siblings ...)
  2024-08-10 20:54   ` [PATCH v7 0/3] " Alejandro Colomar
@ 2024-08-11 23:46   ` Alejandro Colomar
  2024-08-11 23:46     ` [PATCH v8 1/3] gcc/: Rename array_type_nelts() => array_type_nelts_minus_one() Alejandro Colomar
                       ` (3 more replies)
  2024-08-14 20:58   ` [PATCH v9 0/3] c: Add __elementsof__ operator Alejandro Colomar
                     ` (14 subsequent siblings)
  28 siblings, 4 replies; 318+ messages in thread
From: Alejandro Colomar @ 2024-08-11 23:46 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: 7968 bytes --]

Hi!

v8:

-  Reformat (simplify) change-log entries.
-  Improve wording of documentation.
-  Add link to LLVM issue in commit message.

I've added a GitHub issue in the LLVM project reporting about the
existence of this patch set:
<https://github.com/llvm/llvm-project/issues/102836>

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                       | 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 v7:
1:  8b68e250503 ! 1:  a6aa38c9013 gcc/: Rename array_type_nelts() => array_type_nelts_minus_one()
    @@ Commit message
     
         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.
    +            * tree.cc (array_type_nelts, array_type_nelts_minus_one):
    +            * tree.h (array_type_nelts, array_type_nelts_minus_one):
                 * 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.
    +            (pure_scalable_type_info::analyze_array):
    +            * config/i386/i386.cc (ix86_canonical_va_list_type):
    +            Rename array_type_nelts() => array_type_nelts_minus_one()
    +            The old name was misleading.
     
         gcc/c/ChangeLog:
     
                 * c-decl.cc (one_element_array_type_p, get_parm_array_spec):
    +            * c-fold.cc (c_fold_array_ref):
                 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):
    +            * init.cc
    +            (build_zero_init_1):
    +            (build_value_init_noctor):
    +            (build_vec_init):
    +            (build_delete):
    +            * lambda.cc (add_capture):
    +            * tree.cc (array_type_nelts_top):
                 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):
    +            * trans-openmp.cc
    +            (gfc_walk_alloc_comps):
    +            (gfc_omp_clause_linear_ctor):
                 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:
     
2:  21433097103 ! 2:  43300a17e4a Merge definitions of array_type_nelts_top()
    @@ Commit message
         gcc/ChangeLog:
     
                 * tree.h (array_type_nelts_top):
    -            * tree.cc (array_type_nelts_top): Define function (moved from
    -            gcc/cp/).
    +            * 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/).
    +            * 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.
    +            * backend/rust-tree.cc (array_type_nelts_top):
    +            Remove function.
     
         Signed-off-by: Alejandro Colomar <alx@kernel.org>
     
3:  4bd3837d09c ! 3:  e6af87d54af c: Add __lengthof__ operator
    @@ Commit message
     
         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/
    +    Link: https://github.com/llvm/llvm-project/issues/102836
         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/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 similar to @code{sizeof}.
    -+The operand must be a complete array type or an expression of that type.
    ++The operand must be
    ++a parenthesized complete array type name
    ++or an expression of such a type.
     +For example:
     +
     +@smallexample
    @@ gcc/doc/extend.texi: If the operand of the @code{__alignof__} expression is a fu
     +__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).
    ++The result of this operator is an integer constant expression,
    ++unless the top-level array is a variable-length array.
    ++The operand is only evaluated
    ++if the top-level array is a variable-length array.
     +For example:
     +
     +@smallexample
-- 
2.45.2


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 318+ messages in thread

* [PATCH v8 1/3] gcc/: Rename array_type_nelts() => array_type_nelts_minus_one()
  2024-08-11 23:46   ` [PATCH v8 0/3] " Alejandro Colomar
@ 2024-08-11 23:46     ` Alejandro Colomar
  2024-08-11 23:46     ` [PATCH v8 2/3] Merge definitions of array_type_nelts_top() Alejandro Colomar
                       ` (2 subsequent siblings)
  3 siblings, 0 replies; 318+ messages in thread
From: Alejandro Colomar @ 2024-08-11 23:46 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: 12760 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, array_type_nelts_minus_one):
	* tree.h (array_type_nelts, array_type_nelts_minus_one):
	* expr.cc (count_type_elements):
	* config/aarch64/aarch64.cc
	(pure_scalable_type_info::analyze_array):
	* config/i386/i386.cc (ix86_canonical_va_list_type):
	Rename array_type_nelts() => array_type_nelts_minus_one()
	The old name was misleading.

gcc/c/ChangeLog:

	* c-decl.cc (one_element_array_type_p, get_parm_array_spec):
	* c-fold.cc (c_fold_array_ref):
	Rename array_type_nelts() => array_type_nelts_minus_one()

gcc/cp/ChangeLog:

	* decl.cc (reshape_init_array):
	* init.cc
	(build_zero_init_1):
	(build_value_init_noctor):
	(build_vec_init):
	(build_delete):
	* lambda.cc (add_capture):
	* tree.cc (array_type_nelts_top):
	Rename array_type_nelts() => array_type_nelts_minus_one()

gcc/fortran/ChangeLog:

	* trans-array.cc (structure_alloc_comps):
	* trans-openmp.cc
	(gfc_walk_alloc_comps):
	(gfc_omp_clause_linear_ctor):
	Rename array_type_nelts() => array_type_nelts_minus_one()

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] 318+ messages in thread

* [PATCH v8 2/3] Merge definitions of array_type_nelts_top()
  2024-08-11 23:46   ` [PATCH v8 0/3] " Alejandro Colomar
  2024-08-11 23:46     ` [PATCH v8 1/3] gcc/: Rename array_type_nelts() => array_type_nelts_minus_one() Alejandro Colomar
@ 2024-08-11 23:46     ` Alejandro Colomar
  2024-08-11 23:46     ` [PATCH v8 3/3] c: Add __lengthof__ operator Alejandro Colomar
  2024-08-12 23:34     ` [WG14] Request for document number; _Lengthof Alejandro Colomar
  3 siblings, 0 replies; 318+ messages in thread
From: Alejandro Colomar @ 2024-08-11 23:46 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: 4877 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] 318+ messages in thread

* [PATCH v8 3/3] c: Add __lengthof__ operator
  2024-08-11 23:46   ` [PATCH v8 0/3] " Alejandro Colomar
  2024-08-11 23:46     ` [PATCH v8 1/3] gcc/: Rename array_type_nelts() => array_type_nelts_minus_one() Alejandro Colomar
  2024-08-11 23:46     ` [PATCH v8 2/3] Merge definitions of array_type_nelts_top() Alejandro Colomar
@ 2024-08-11 23:46     ` Alejandro Colomar
  2024-08-12 23:34     ` [WG14] Request for document number; _Lengthof Alejandro Colomar
  3 siblings, 0 replies; 318+ messages in thread
From: Alejandro Colomar @ 2024-08-11 23:46 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: 29791 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/
Link: https://github.com/llvm/llvm-project/issues/102836
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..e7d63fc57ad 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 parenthesized complete array type name
+or an expression of such a type.
+For example:
+
+@smallexample
+int a[n];
+__lengthof__ (a);  // returns n
+__lengthof__ (int [7][3]);  // returns 7
+@end smallexample
+
+The result of this operator is an integer constant expression,
+unless the top-level array is a variable-length array.
+The operand is only evaluated
+if the top-level array is a variable-length array.
+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..297ffe75f60
--- /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: lengthof(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] 318+ messages in thread

* [WG14] Request for document number; _Lengthof
  2024-08-11 23:46   ` [PATCH v8 0/3] " Alejandro Colomar
                       ` (2 preceding siblings ...)
  2024-08-11 23:46     ` [PATCH v8 3/3] c: Add __lengthof__ operator Alejandro Colomar
@ 2024-08-12 23:34     ` Alejandro Colomar
  2024-08-13  7:33       ` Alejandro Colomar
  2024-08-13 15:02       ` v2.1 Draft for a lengthof paper Alejandro Colomar
  3 siblings, 2 replies; 318+ messages in thread
From: Alejandro Colomar @ 2024-08-12 23:34 UTC (permalink / raw)
  To: Daniel Plakosh
  Cc: gcc-patches, 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, A. Jiang, Eugene Zelenko,
	Aaron Ballman

[-- Attachment #1: Type: text/plain, Size: 460 bytes --]

Hi David,

I want to send an updated version of n2529.  The original author didn't
respond to my mail, so I'll take over.  I've been preparing a GCC patch
set for adding the feature to GCC, and have informed Clang developers
about it too.

The title would be

    _Lengthof - New pointer-proof keyword to determine array length (v2)

Can you please assign me a number for it?  Thanks.

Cheers,
Alex


-- 
<https://www.alejandro-colomar.es/>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 318+ messages in thread

* Re: [committed] testsuite: Fix up sse3-addsubps.c
  2024-08-10  8:57                                         ` [committed] testsuite: Fix up sse3-addsubps.c Jakub Jelinek
@ 2024-08-12 23:43                                           ` Alejandro Colomar
  0 siblings, 0 replies; 318+ messages in thread
From: Alejandro Colomar @ 2024-08-12 23:43 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 2236 bytes --]

Hi Jakub,

On Sat, Aug 10, 2024 at 10:57:25AM GMT, Jakub Jelinek wrote:
> 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];

Thanks for this, and also for

	commit 723e0f724e0c884a31ddf4a688604e7163ed31f2
	Author: Jakub Jelinek <jakub@redhat.com>
	Date:   Fri Aug 9 09:34:50 2024 +0200

	    c-family: Add some more ARRAY_SIZE uses
	    
	    These two spots were just non-standard, because they divided
	    sizeof (omp_pragmas_simd) by sizeof (*omp_pragmas) and not
	    the expected sizeof (*omp_pragmas_simd) and so weren't converted
	    into ARRAY_SIZE.  Both of the latter sizes are the same though,
	    as both arrays have the same type, so this patch doesn't change
	    anything but readability.
	    
	    2024-08-09  Jakub Jelinek  <jakub@redhat.com>
	    
		    * c-pragma.cc (c_pp_lookup_pragma): Use ARRAY_SIZE in
		    n_omp_pragmas_simd initializer.
		    (init_pragmas): Likewise.


(It would be nice if the commit messages would have included something
 like Reported-by or an equivalent.)  :)

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] 318+ messages in thread

* Re: [WG14] Request for document number; _Lengthof
  2024-08-12 23:34     ` [WG14] Request for document number; _Lengthof Alejandro Colomar
@ 2024-08-13  7:33       ` Alejandro Colomar
  2024-08-13 15:02       ` v2.1 Draft for a lengthof paper Alejandro Colomar
  1 sibling, 0 replies; 318+ messages in thread
From: Alejandro Colomar @ 2024-08-13  7:33 UTC (permalink / raw)
  To: Daniel Plakosh
  Cc: gcc-patches, 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, A. Jiang, Eugene Zelenko,
	Aaron Ballman

[-- Attachment #1: Type: text/plain, Size: 648 bytes --]

On Tue, Aug 13, 2024 at 01:34:58AM GMT, Alejandro Colomar wrote:
> Hi David,

I obviously meant Daniel.  :-)

> 
> I want to send an updated version of n2529.  The original author didn't
> respond to my mail, so I'll take over.  I've been preparing a GCC patch
> set for adding the feature to GCC, and have informed Clang developers
> about it too.
> 
> The title would be
> 
>     _Lengthof - New pointer-proof keyword to determine array length (v2)
> 
> Can you please assign me a number for it?  Thanks.
> 
> Cheers,
> 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] 318+ messages in thread

* v2.1 Draft for a lengthof paper
  2024-08-12 23:34     ` [WG14] Request for document number; _Lengthof Alejandro Colomar
  2024-08-13  7:33       ` Alejandro Colomar
@ 2024-08-13 15:02       ` Alejandro Colomar
  2024-08-13 22:38         ` Xavier Del Campo Romero
  1 sibling, 1 reply; 318+ messages in thread
From: Alejandro Colomar @ 2024-08-13 15:02 UTC (permalink / raw)
  To: gcc-patches
  Cc: Daniel Plakosh, 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, A. Jiang, Eugene Zelenko,
	Aaron Ballman


[-- Attachment #1.1: Type: text/plain, Size: 757 bytes --]

Hi,

On Tue, Aug 13, 2024 at 01:34:58AM GMT, Alejandro Colomar wrote:
> I want to send an updated version of n2529.  The original author didn't
> respond to my mail, so I'll take over.  I've been preparing a GCC patch
> set for adding the feature to GCC, and have informed Clang developers
> about it too.
> 
> The title would be
> 
>     _Lengthof - New pointer-proof keyword to determine array length (v2)
> 
> Can you please assign me a number for it?  Thanks.

Attached is a draft for a paper (both the man(7) source and the
generated PDF).

I have only added lengthof for now, not _Lengthof, as suggested by Jens.
Depending on feedback, I'll propose the uglified version.

Cheers,
Alex

-- 
<https://www.alejandro-colomar.es/>

[-- Attachment #1.2: lengthof.man --]
[-- Type: application/x-troff-man, Size: 16578 bytes --]

[-- Attachment #1.3: lengthof.pdf --]
[-- Type: application/pdf, Size: 19830 bytes --]

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 318+ messages in thread

* Re: v2.1 Draft for a lengthof paper
  2024-08-13 15:02       ` v2.1 Draft for a lengthof paper Alejandro Colomar
@ 2024-08-13 22:38         ` Xavier Del Campo Romero
  2024-08-13 23:27           ` Alejandro Colomar
  2024-08-14  5:58           ` v2.1 Draft for a lengthof paper Jens Gustedt
  0 siblings, 2 replies; 318+ messages in thread
From: Xavier Del Campo Romero @ 2024-08-13 22:38 UTC (permalink / raw)
  To: Alejandro Colomar
  Cc: Gcc Patches, Daniel Plakosh, Martin Uecker, Joseph Myers,
	Gabriel Ravier, Jakub Jelinek, Kees Cook, Qing Zhao,
	Jens Gustedt, David Brown, Florian Weimer, Andreas Schwab,
	Timm Baeder, A. Jiang, Eugene Zelenko, Aaron Ballman

I have been overseeing these last emails - thank you very much for your
efforts, Alex! I did not reply until now because I do not have prior
experience with gcc internals, so my feedback would probably have not
been that useful.

Those emails from 2020 were in fact discussing two completely different
proposals at once:

1. Add _Lengthof + #include <stdlengthof.h>
2. Allow static qualifier on compound literals

Whereas proposal #2 made it into C23 (kudos to Jens Gustedt!), and as
you already know by now, proposal #1 received some negative feedback,
suggesting _Typeof/typeof + some macro magic as a pragmatic workaround
instead.

Since the proposal did not get much traction and I would had been
unable to contribute to gcc myself, I just gave up on it. IIRC the
deadline for new proposals closed soon after, anyway.

But I am glad that someone with proper experience took the initiative.
I still think the proposal is relevant and has interesting use cases.

> I have only added lengthof for now, not _Lengthof, as suggested by Jens.
> Depending on feedback, I'll propose the uglified version.

Probably, all of us know why the uglified version is the usual approach
preferred by the C standard: we do not know how many applications would
break otherwise.

However, we see that this trend is now changing with C23, so probably
it makes sense to define lengthof directly.

As for the parentheses, I personally think lengthof should follow
similar rules compared to sizeof.

Best regards,

--
Xavier Del Campo Romero



Aug 13, 2024, 15:02 by alx@kernel.org:

> Hi,
>
> On Tue, Aug 13, 2024 at 01:34:58AM GMT, Alejandro Colomar wrote:
>
>> I want to send an updated version of n2529.  The original author didn't
>> respond to my mail, so I'll take over.  I've been preparing a GCC patch
>> set for adding the feature to GCC, and have informed Clang developers
>> about it too.
>>
>> The title would be
>>
>> _Lengthof - New pointer-proof keyword to determine array length (v2)
>>
>> Can you please assign me a number for it?  Thanks.
>>
>
> Attached is a draft for a paper (both the man(7) source and the
> generated PDF).
>
> I have only added lengthof for now, not _Lengthof, as suggested by Jens.
> Depending on feedback, I'll propose the uglified version.
>
> Cheers,
> Alex
>
> --
> <https://www.alejandro-colomar.es/>
>


^ permalink raw reply	[flat|nested] 318+ messages in thread

* Re: v2.1 Draft for a lengthof paper
  2024-08-13 22:38         ` Xavier Del Campo Romero
@ 2024-08-13 23:27           ` Alejandro Colomar
  2024-08-14  6:11             ` Jens Gustedt
  2024-08-14  5:58           ` v2.1 Draft for a lengthof paper Jens Gustedt
  1 sibling, 1 reply; 318+ messages in thread
From: Alejandro Colomar @ 2024-08-13 23:27 UTC (permalink / raw)
  To: Xavier Del Campo Romero
  Cc: Gcc Patches, Daniel Plakosh, Martin Uecker, Joseph Myers,
	Gabriel Ravier, Jakub Jelinek, Kees Cook, Qing Zhao,
	Jens Gustedt, David Brown, Florian Weimer, Andreas Schwab,
	Timm Baeder, A. Jiang, Eugene Zelenko, Aaron Ballman

[-- Attachment #1: Type: text/plain, Size: 2784 bytes --]

Hi Xavier,

On Wed, Aug 14, 2024 at 12:38:53AM GMT, Xavier Del Campo Romero wrote:
> I have been overseeing these last emails -

Ahhh, good to know; thanks!  :)

> thank you very much for your
> efforts, Alex!

:-)

> I did not reply until now because I do not have prior
> experience with gcc internals, so my feedback would probably have not
> been that useful.

Ok.

> Those emails from 2020 were in fact discussing two completely different
> proposals at once:
> 
> 1. Add _Lengthof + #include <stdlengthof.h>
> 2. Allow static qualifier on compound literals

Yup.

> Whereas proposal #2 made it into C23 (kudos to Jens Gustedt!), and as
> you already know by now, proposal #1 received some negative feedback,
> suggesting _Typeof/typeof + some macro magic as a pragmatic workaround
> instead.

The original author of that negative feedback talked to me in private
a week ago, and said he likes my proposal.  We have no negative feedback
anymore.  :)

> Since the proposal did not get much traction and I would had been
> unable to contribute to gcc myself, I just gave up on it. IIRC the
> deadline for new proposals closed soon after, anyway.

Ok.

> But I am glad that someone with proper experience took the initiative.

Fun fact: this is my second non-trivial patch to GCC.  I wouldn't say I
had the proper experience with GCC internals when I started this patch
set.  But I'm unemployed at the moment, which gives me all the time I
need for learning those.  :)

> I still think the proposal is relevant and has interesting use cases.
> 
> > I have only added lengthof for now, not _Lengthof, as suggested by Jens.
> > Depending on feedback, I'll propose the uglified version.
> 
> Probably, all of us know why the uglified version is the usual approach
> preferred by the C standard: we do not know how many applications would
> break otherwise.

Yup.

> However, we see that this trend is now changing with C23, so probably
> it makes sense to define lengthof directly.

Yeah, since Jens is in WG14 and he suggested to follow this trend, maybe
we can.  If not, it's trivial to change the proposal to use the uglified
name plus a macro.

Checking <https://codesearch.debian.net>, I see that while several
projects have a lengthof() macro, all of them use it with semantics
compatible with this keyword, so it shouldn't break too much.  Maybe
those projects will start receiving diagnostics that they're redefining
a standard keyword, but that's not too bad.

> As for the parentheses, I personally think lengthof should follow
> similar rules compared to sizeof.

I think most people agree with this.

> 
> Best regards,

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] 318+ messages in thread

* Re: v2.1 Draft for a lengthof paper
  2024-08-13 22:38         ` Xavier Del Campo Romero
  2024-08-13 23:27           ` Alejandro Colomar
@ 2024-08-14  5:58           ` Jens Gustedt
  1 sibling, 0 replies; 318+ messages in thread
From: Jens Gustedt @ 2024-08-14  5:58 UTC (permalink / raw)
  To: Xavier Del Campo Romero, Alejandro Colomar
  Cc: Gcc Patches, Daniel Plakosh, Martin Uecker, Joseph Myers,
	Gabriel Ravier, Jakub Jelinek, Kees Cook, Qing Zhao, David Brown,
	Florian Weimer, Andreas Schwab, Timm Baeder, A. Jiang,
	Eugene Zelenko, Aaron Ballman

Hi, 

Am 14. August 2024 00:38:53 MESZ schrieb Xavier Del Campo Romero <xavi.dcr@tutanota.com>:
> I have been overseeing these last emails - thank you very much for your
> efforts, Alex! I did not reply until now because I do not have prior
> experience with gcc internals, so my feedback would probably have not
> been that useful.
> 
> Those emails from 2020 were in fact discussing two completely different
> proposals at once:
> 
> 1. Add _Lengthof + #include <stdlengthof.h>
> 2. Allow static qualifier on compound literals
> 
> Whereas proposal #2 made it into C23 (kudos to Jens Gustedt!), 

this was together with Alex

> and as
> you already know by now, proposal #1 received some negative feedback,
> suggesting _Typeof/typeof + some macro magic as a pragmatic workaround
> instead.
> 
> Since the proposal did not get much traction and I would had been
> unable to contribute to gcc myself, I just gave up on it. IIRC the
> deadline for new proposals closed soon after, anyway.
> 
> But I am glad that someone with proper experience took the initiative.
> I still think the proposal is relevant and has interesting use cases.
> 
> > I have only added lengthof for now, not _Lengthof, as suggested by Jens.
> > Depending on feedback, I'll propose the uglified version.
> 
> Probably, all of us know why the uglified version is the usual approach
> preferred by the C standard: we do not know how many applications would
> break otherwise.
> 
> However, we see that this trend is now changing with C23, so probably
> it makes sense to define lengthof directly.

When I suggested that the double-underscore version is sufficient, I was not thinking that there would be a paper to WG 14 so quickly. For integration into go and clang
the double underscore is certainly enough. Then for a standardization
that is another question.


> As for the parentheses, I personally think lengthof should follow
> similar rules compared to sizeof.
> 
> Best regards,
> 
> --
> Xavier Del Campo Romero
> 
> 
> 
> Aug 13, 2024, 15:02 by alx@kernel.org:
> 
> > Hi,
> >
> > On Tue, Aug 13, 2024 at 01:34:58AM GMT, Alejandro Colomar wrote:
> >
> >> I want to send an updated version of n2529.  The original author didn't
> >> respond to my mail, so I'll take over.  I've been preparing a GCC patch
> >> set for adding the feature to GCC, and have informed Clang developers
> >> about it too.
> >>
> >> The title would be
> >>
> >> _Lengthof - New pointer-proof keyword to determine array length (v2)
> >>
> >> Can you please assign me a number for it?  Thanks.
> >>
> >
> > Attached is a draft for a paper (both the man(7) source and the
> > generated PDF).
> >
> > I have only added lengthof for now, not _Lengthof, as suggested by Jens.
> > Depending on feedback, I'll propose the uglified version.
> >
> > Cheers,
> > Alex
> >
> > --
> > <https://www.alejandro-colomar.es/>
> >
> 

Jens


-- 
Jens Gustedt - INRIA & ICube, Strasbourg, France

^ permalink raw reply	[flat|nested] 318+ messages in thread

* Re: v2.1 Draft for a lengthof paper
  2024-08-13 23:27           ` Alejandro Colomar
@ 2024-08-14  6:11             ` Jens Gustedt
  2024-08-14  8:41               ` Alejandro Colomar
  2024-08-14 11:31               ` Ballman, Aaron
  0 siblings, 2 replies; 318+ messages in thread
From: Jens Gustedt @ 2024-08-14  6:11 UTC (permalink / raw)
  To: Alejandro Colomar, Xavier Del Campo Romero
  Cc: Gcc Patches, Daniel Plakosh, Martin Uecker, Joseph Myers,
	Gabriel Ravier, Jakub Jelinek, Kees Cook, Qing Zhao, David Brown,
	Florian Weimer, Andreas Schwab, Timm Baeder, A. Jiang,
	Eugene Zelenko, Aaron Ballman

Am 14. August 2024 01:27:33 MESZ schrieb Alejandro Colomar <alx@kernel.org>:
> Hi Xavier,
> 
> On Wed, Aug 14, 2024 at 12:38:53AM GMT, Xavier Del Campo Romero wrote:
> > I have been overseeing these last emails -
> 
> Ahhh, good to know; thanks!  :)
> 
> > thank you very much for your
> > efforts, Alex!
> 
> :-)
> 
> > I did not reply until now because I do not have prior
> > experience with gcc internals, so my feedback would probably have not
> > been that useful.
> 
> Ok.
> 
> > Those emails from 2020 were in fact discussing two completely different
> > proposals at once:
> > 
> > 1. Add _Lengthof + #include <stdlengthof.h>
> > 2. Allow static qualifier on compound literals
> 
> Yup.
> 
> > Whereas proposal #2 made it into C23 (kudos to Jens Gustedt!), and as
> > you already know by now, proposal #1 received some negative feedback,
> > suggesting _Typeof/typeof + some macro magic as a pragmatic workaround
> > instead.
> 
> The original author of that negative feedback talked to me in private
> a week ago, and said he likes my proposal.  We have no negative feedback
> anymore.  :)
> 
> > Since the proposal did not get much traction and I would had been
> > unable to contribute to gcc myself, I just gave up on it. IIRC the
> > deadline for new proposals closed soon after, anyway.
> 
> Ok.
> 
> > But I am glad that someone with proper experience took the initiative.
> 
> Fun fact: this is my second non-trivial patch to GCC.  I wouldn't say I
> had the proper experience with GCC internals when I started this patch
> set.  But I'm unemployed at the moment, which gives me all the time I
> need for learning those.  :)
> 
> > I still think the proposal is relevant and has interesting use cases.
> > 
> > > I have only added lengthof for now, not _Lengthof, as suggested by Jens.
> > > Depending on feedback, I'll propose the uglified version.
> > 
> > Probably, all of us know why the uglified version is the usual approach
> > preferred by the C standard: we do not know how many applications would
> > break otherwise.
> 
> Yup.
> 
> > However, we see that this trend is now changing with C23, so probably
> > it makes sense to define lengthof directly.
> 
> Yeah, since Jens is in WG14 and he suggested to follow this trend, maybe
> we can.  If not, it's trivial to change the proposal to use the uglified
> name plus a macro.
> 
> Checking <https://codesearch.debian.net>, I see that while several
> projects have a lengthof() macro, all of them use it with semantics
> compatible with this keyword, so it shouldn't break too much.  Maybe
> those projects will start receiving diagnostics that they're redefining
> a standard keyword, but that's not too bad.

For a WG14 paper you should add these findings to support that choice.
Another option would be for WG14 to standardize the then existing implementation with the double underscores.

> > As for the parentheses, I personally think lengthof should follow
> > similar rules compared to sizeof.
> 
> I think most people agree with this.

I still don't, in particular not for standardisation.

We have to remember that there are many small C compilers out there. 
I would not want unnecessary burden on them. So my preferred choice would be
a standardisation as a macro, similar to offsetof.
gcc (and clang) could then just map that to their builtin, other compilers could use
whatever they have at the moment, even just the macros that you have in the paper as a starting point. 

The rest would be "quality of implementation"

What time horizon do you see to add the feature for array parameters?

Thanks
Jens


> > Best regards,
> 
> Have a lovely night!
> Alex
> 


-- 
Jens Gustedt - INRIA & ICube, Strasbourg, France

^ permalink raw reply	[flat|nested] 318+ messages in thread

* Re: v2.1 Draft for a lengthof paper
  2024-08-14  6:11             ` Jens Gustedt
@ 2024-08-14  8:41               ` Alejandro Colomar
  2024-08-14 11:31               ` Ballman, Aaron
  1 sibling, 0 replies; 318+ messages in thread
From: Alejandro Colomar @ 2024-08-14  8:41 UTC (permalink / raw)
  To: Jens Gustedt, Martin Uecker
  Cc: Xavier Del Campo Romero, Gcc Patches, Daniel Plakosh,
	Joseph Myers, Gabriel Ravier, Jakub Jelinek, Kees Cook,
	Qing Zhao, David Brown, Florian Weimer, Andreas Schwab,
	Timm Baeder, A. Jiang, Eugene Zelenko, Aaron Ballman

[-- Attachment #1: Type: text/plain, Size: 2430 bytes --]

Hi Jens, Martin,

On Wed, Aug 14, 2024 at 08:11:20AM GMT, Jens Gustedt wrote:
> > Checking <https://codesearch.debian.net>, I see that while several
> > projects have a lengthof() macro, all of them use it with semantics
> > compatible with this keyword, so it shouldn't break too much.  Maybe
> > those projects will start receiving diagnostics that they're redefining
> > a standard keyword, but that's not too bad.
> 
> For a WG14 paper you should add these findings to support that choice.
> Another option would be for WG14 to standardize the then existing implementation with the double underscores.

Makes sense; I'll add that into new "Prior art" and "Backwards
compatibility" sections within the paper.

> > > As for the parentheses, I personally think lengthof should follow
> > > similar rules compared to sizeof.
> > 
> > I think most people agree with this.
> 
> I still don't, in particular not for standardisation.
> 
> We have to remember that there are many small C compilers out there. 
> I would not want unnecessary burden on them. So my preferred choice would be
> a standardisation as a macro, similar to offsetof.
> gcc (and clang) could then just map that to their builtin, other compilers could use
> whatever they have at the moment, even just the macros that you have in the paper as a starting point. 
> 
> The rest would be "quality of implementation"

Hmmm, sounds reasonable.

Some doubts:

If we allow a compiler to implement it as a predefined macro that
expands to the usual sizeof division, it might produce double evaluation
in some VLA cases.  That would be surprising to some programs, which may
expect either 0 or 1 evaluations, but not 2.  Maybe we can leave it as
unspecified behavior, and an implementation may document that double
evaluation may happen if the input is a VLA?

> What time horizon do you see to add the feature for array parameters?

Martin, what do you think?  I think the only blocking thing for me is
what you mentioned about turning function parameters into arrays that
decay almost everywhere.  Once that's set up, my code will probably work
with them without modification, or maybe with just a little tweak.  Do
you have an idea of how much time that can take you?

I expect it to be well before C2y.  Maybe a year or two?

Have a lovely day!
Alex

> Thanks
> Jens

-- 
<https://www.alejandro-colomar.es/>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 318+ messages in thread

* RE: v2.1 Draft for a lengthof paper
  2024-08-14  6:11             ` Jens Gustedt
  2024-08-14  8:41               ` Alejandro Colomar
@ 2024-08-14 11:31               ` Ballman, Aaron
  2024-08-14 12:17                 ` Jens Gustedt
  1 sibling, 1 reply; 318+ messages in thread
From: Ballman, Aaron @ 2024-08-14 11:31 UTC (permalink / raw)
  To: Jens Gustedt, Alejandro Colomar, Xavier Del Campo Romero
  Cc: Gcc Patches, Daniel Plakosh, Martin Uecker, Joseph Myers,
	Gabriel Ravier, Jakub Jelinek, Kees Cook, Qing Zhao, David Brown,
	Florian Weimer, Andreas Schwab, Timm Baeder, A. Jiang,
	Eugene Zelenko

Sorry for top-posting, my work account is stuck on Outlook. :-/

> For a WG14 paper you should add these findings to support that choice.
> Another option would be for WG14 to standardize the then existing implementation with the double underscores.

+1, it's always good to explain prior art and existing uses as part of the paper. However, please also point out that C++ has a prior art as well which is slightly different and very much worth considering: they have one API for getting the array's rank, and another for getting a specific rank's extent. This is a general solution that doesn't require the programmer to have deep knowledge of C's declarator syntax and how it relates to multidimensional arrays.

That said, I suspect WG14 would not be keen on standardizing `lengthof` without an ugly keyword given that there are plenty of other uses of it that would break: 

https://sourcegraph.com/github.com/illumos/illumos-gate/-/blob/usr/src/cmd/mailx/names.c?L53-55
https://sourcegraph.com/github.com/Rockbox/rockbox/-/blob/tools/ipod_fw.c?L292-294
https://sourcegraph.com/github.com/OpenSmalltalk/opensmalltalk-vm/-/blob/src/spur64.stack/validImage.c?L7014-7018
(and many, many others)

>> > As for the parentheses, I personally think lengthof should follow 
>> > similar rules compared to sizeof.
>> 
>> I think most people agree with this.
>
> I still don't, in particular not for standardisation.
> 
> We have to remember that there are many small C compilers out there.

Those compilers already have to handle parsing this for sizeof, so that's not particularly compelling (even if we wanted to design C for the lowest common denominator of implementation effort, which I'm not convinced is a good approach these days). That said, if we went with a rank/extent design, I think we'd *have* to use parens because the extent interface would take two operands (the array and the rank you're interested in getting the extent of) and it would be inconsistent for the rank interface to then not require parens.

~Aaron

-----Original Message-----
From: Jens Gustedt <jens.gustedt@inria.fr> 
Sent: Wednesday, August 14, 2024 2:11 AM
To: Alejandro Colomar <alx@kernel.org>; Xavier Del Campo Romero <xavi.dcr@tutanota.com>
Cc: Gcc Patches <gcc-patches@gcc.gnu.org>; Daniel Plakosh <dplakosh@cert.org>; Martin Uecker <uecker@tugraz.at>; 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>; David Brown <david.brown@hesbynett.no>; Florian Weimer <fweimer@redhat.com>; Andreas Schwab <schwab@linux-m68k.org>; Timm Baeder <tbaeder@redhat.com>; A. Jiang <de34@live.cn>; Eugene Zelenko <eugene.zelenko@gmail.com>; Ballman, Aaron <aaron.ballman@intel.com>
Subject: Re: v2.1 Draft for a lengthof paper

Am 14. August 2024 01:27:33 MESZ schrieb Alejandro Colomar <alx@kernel.org>:
> Hi Xavier,
> 
> On Wed, Aug 14, 2024 at 12:38:53AM GMT, Xavier Del Campo Romero wrote:
> > I have been overseeing these last emails -
> 
> Ahhh, good to know; thanks!  :)
> 
> > thank you very much for your
> > efforts, Alex!
> 
> :-)
> 
> > I did not reply until now because I do not have prior experience 
> > with gcc internals, so my feedback would probably have not been that 
> > useful.
> 
> Ok.
> 
> > Those emails from 2020 were in fact discussing two completely 
> > different proposals at once:
> > 
> > 1. Add _Lengthof + #include <stdlengthof.h> 2. Allow static 
> > qualifier on compound literals
> 
> Yup.
> 
> > Whereas proposal #2 made it into C23 (kudos to Jens Gustedt!), and 
> > as you already know by now, proposal #1 received some negative 
> > feedback, suggesting _Typeof/typeof + some macro magic as a 
> > pragmatic workaround instead.
> 
> The original author of that negative feedback talked to me in private 
> a week ago, and said he likes my proposal.  We have no negative 
> feedback anymore.  :)
> 
> > Since the proposal did not get much traction and I would had been 
> > unable to contribute to gcc myself, I just gave up on it. IIRC the 
> > deadline for new proposals closed soon after, anyway.
> 
> Ok.
> 
> > But I am glad that someone with proper experience took the initiative.
> 
> Fun fact: this is my second non-trivial patch to GCC.  I wouldn't say 
> I had the proper experience with GCC internals when I started this 
> patch set.  But I'm unemployed at the moment, which gives me all the 
> time I need for learning those.  :)
> 
> > I still think the proposal is relevant and has interesting use cases.
> > 
> > > I have only added lengthof for now, not _Lengthof, as suggested by Jens.
> > > Depending on feedback, I'll propose the uglified version.
> > 
> > Probably, all of us know why the uglified version is the usual 
> > approach preferred by the C standard: we do not know how many 
> > applications would break otherwise.
> 
> Yup.
> 
> > However, we see that this trend is now changing with C23, so 
> > probably it makes sense to define lengthof directly.
> 
> Yeah, since Jens is in WG14 and he suggested to follow this trend, 
> maybe we can.  If not, it's trivial to change the proposal to use the 
> uglified name plus a macro.
> 
> Checking <https://codesearch.debian.net>, I see that while several 
> projects have a lengthof() macro, all of them use it with semantics 
> compatible with this keyword, so it shouldn't break too much.  Maybe 
> those projects will start receiving diagnostics that they're 
> redefining a standard keyword, but that's not too bad.

For a WG14 paper you should add these findings to support that choice.
Another option would be for WG14 to standardize the then existing implementation with the double underscores.

> > As for the parentheses, I personally think lengthof should follow 
> > similar rules compared to sizeof.
> 
> I think most people agree with this.

I still don't, in particular not for standardisation.

We have to remember that there are many small C compilers out there. 
I would not want unnecessary burden on them. So my preferred choice would be a standardisation as a macro, similar to offsetof.
gcc (and clang) could then just map that to their builtin, other compilers could use whatever they have at the moment, even just the macros that you have in the paper as a starting point. 

The rest would be "quality of implementation"

What time horizon do you see to add the feature for array parameters?

Thanks
Jens


> > Best regards,
> 
> Have a lovely night!
> Alex
> 


--
Jens Gustedt - INRIA & ICube, Strasbourg, France 

^ permalink raw reply	[flat|nested] 318+ messages in thread

* RE: v2.1 Draft for a lengthof paper
  2024-08-14 11:31               ` Ballman, Aaron
@ 2024-08-14 12:17                 ` Jens Gustedt
  2024-08-14 12:40                   ` Ballman, Aaron
  2024-08-14 12:58                   ` Alejandro Colomar
  0 siblings, 2 replies; 318+ messages in thread
From: Jens Gustedt @ 2024-08-14 12:17 UTC (permalink / raw)
  To: Ballman, Aaron, Alejandro Colomar, Xavier Del Campo Romero
  Cc: Gcc Patches, Daniel Plakosh, Martin Uecker, Joseph Myers,
	Gabriel Ravier, Jakub Jelinek, Kees Cook, Qing Zhao, David Brown,
	Florian Weimer, Andreas Schwab, Timm Baeder, A. Jiang,
	Eugene Zelenko

Hi Aaron,

Am 14. August 2024 13:31:19 MESZ schrieb "Ballman, Aaron" <aaron.ballman@intel.com>:
> Sorry for top-posting, my work account is stuck on Outlook. :-/
> 
> > For a WG14 paper you should add these findings to support that choice.
> > Another option would be for WG14 to standardize the then existing implementation with the double underscores.
> 
> +1, it's always good to explain prior art and existing uses as part of the paper. However, please also point out that C++ has a prior art as well which is slightly different and very much worth considering: they have one API for getting the array's rank, and another for getting a specific rank's extent. This is a general solution that doesn't require the programmer to have deep knowledge of C's declarator syntax and how it relates to multidimensional arrays.
> 
> That said, I suspect WG14 would not be keen on standardizing `lengthof` without an ugly keyword given that there are plenty of other uses of it that would break: 
> 
> https://sourcegraph.com/github.com/illumos/illumos-gate/-/blob/usr/src/cmd/mailx/names.c?L53-55
> https://sourcegraph.com/github.com/Rockbox/rockbox/-/blob/tools/ipod_fw.c?L292-294
> https://sourcegraph.com/github.com/OpenSmalltalk/opensmalltalk-vm/-/blob/src/spur64.stack/validImage.c?L7014-7018
> (and many, many others)
> 
> >> > As for the parentheses, I personally think lengthof should follow 
> >> > similar rules compared to sizeof.
> >> 
> >> I think most people agree with this.
> >
> > I still don't, in particular not for standardisation.
> > 
> > We have to remember that there are many small C compilers out there.
> 
> Those compilers already have to handle parsing this for sizeof, so that's not particularly compelling (even if we wanted to design C for the lowest common denominator of implementation effort, which I'm not convinced is a good approach these days). That said, if we went with a rank/extent design, I think we'd *have* to use parens because the extent interface would take two operands (the array and the rank you're interested in getting the extent of) and it would be inconsistent for the rank interface to then not require parens.

I think that this argument goes too short. E. g. implementation that already have
compound expressions (or lambdas ;-) may provide a quality implementation using `static_assert` and `typeof` alone, and don't have to touch their compiler at all.

We should not impose an implementation in the language where doing it in a header can be completely sufficient.

Plus, implementing as a macro in a header (probably <stddef.h>) makes also a feature test, for those applications that already have something similar. 
this was basically what we did for `unreachable` and I think it worked out fine.

Jens

> ~Aaron
> 
> -----Original Message-----
> From: Jens Gustedt <jens.gustedt@inria.fr> 
> Sent: Wednesday, August 14, 2024 2:11 AM
> To: Alejandro Colomar <alx@kernel.org>; Xavier Del Campo Romero <xavi.dcr@tutanota.com>
> Cc: Gcc Patches <gcc-patches@gcc.gnu.org>; Daniel Plakosh <dplakosh@cert.org>; Martin Uecker <uecker@tugraz.at>; 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>; David Brown <david.brown@hesbynett.no>; Florian Weimer <fweimer@redhat.com>; Andreas Schwab <schwab@linux-m68k.org>; Timm Baeder <tbaeder@redhat.com>; A. Jiang <de34@live.cn>; Eugene Zelenko <eugene.zelenko@gmail.com>; Ballman, Aaron <aaron.ballman@intel.com>
> Subject: Re: v2.1 Draft for a lengthof paper
> 
> Am 14. August 2024 01:27:33 MESZ schrieb Alejandro Colomar <alx@kernel.org>:
> > Hi Xavier,
> > 
> > On Wed, Aug 14, 2024 at 12:38:53AM GMT, Xavier Del Campo Romero wrote:
> > > I have been overseeing these last emails -
> > 
> > Ahhh, good to know; thanks!  :)
> > 
> > > thank you very much for your
> > > efforts, Alex!
> > 
> > :-)
> > 
> > > I did not reply until now because I do not have prior experience 
> > > with gcc internals, so my feedback would probably have not been that 
> > > useful.
> > 
> > Ok.
> > 
> > > Those emails from 2020 were in fact discussing two completely 
> > > different proposals at once:
> > > 
> > > 1. Add _Lengthof + #include <stdlengthof.h> 2. Allow static 
> > > qualifier on compound literals
> > 
> > Yup.
> > 
> > > Whereas proposal #2 made it into C23 (kudos to Jens Gustedt!), and 
> > > as you already know by now, proposal #1 received some negative 
> > > feedback, suggesting _Typeof/typeof + some macro magic as a 
> > > pragmatic workaround instead.
> > 
> > The original author of that negative feedback talked to me in private 
> > a week ago, and said he likes my proposal.  We have no negative 
> > feedback anymore.  :)
> > 
> > > Since the proposal did not get much traction and I would had been 
> > > unable to contribute to gcc myself, I just gave up on it. IIRC the 
> > > deadline for new proposals closed soon after, anyway.
> > 
> > Ok.
> > 
> > > But I am glad that someone with proper experience took the initiative.
> > 
> > Fun fact: this is my second non-trivial patch to GCC.  I wouldn't say 
> > I had the proper experience with GCC internals when I started this 
> > patch set.  But I'm unemployed at the moment, which gives me all the 
> > time I need for learning those.  :)
> > 
> > > I still think the proposal is relevant and has interesting use cases.
> > > 
> > > > I have only added lengthof for now, not _Lengthof, as suggested by Jens.
> > > > Depending on feedback, I'll propose the uglified version.
> > > 
> > > Probably, all of us know why the uglified version is the usual 
> > > approach preferred by the C standard: we do not know how many 
> > > applications would break otherwise.
> > 
> > Yup.
> > 
> > > However, we see that this trend is now changing with C23, so 
> > > probably it makes sense to define lengthof directly.
> > 
> > Yeah, since Jens is in WG14 and he suggested to follow this trend, 
> > maybe we can.  If not, it's trivial to change the proposal to use the 
> > uglified name plus a macro.
> > 
> > Checking <https://codesearch.debian.net>, I see that while several 
> > projects have a lengthof() macro, all of them use it with semantics 
> > compatible with this keyword, so it shouldn't break too much.  Maybe 
> > those projects will start receiving diagnostics that they're 
> > redefining a standard keyword, but that's not too bad.
> 
> For a WG14 paper you should add these findings to support that choice.
> Another option would be for WG14 to standardize the then existing implementation with the double underscores.
> 
> > > As for the parentheses, I personally think lengthof should follow 
> > > similar rules compared to sizeof.
> > 
> > I think most people agree with this.
> 
> I still don't, in particular not for standardisation.
> 
> We have to remember that there are many small C compilers out there. 
> I would not want unnecessary burden on them. So my preferred choice would be a standardisation as a macro, similar to offsetof.
> gcc (and clang) could then just map that to their builtin, other compilers could use whatever they have at the moment, even just the macros that you have in the paper as a starting point. 
> 
> The rest would be "quality of implementation"
> 
> What time horizon do you see to add the feature for array parameters?
> 
> Thanks
> Jens
> 
> 
> > > Best regards,
> > 
> > Have a lovely night!
> > Alex
> > 
> 
> 
> --
> Jens Gustedt - INRIA & ICube, Strasbourg, France 


-- 
Jens Gustedt - INRIA & ICube, Strasbourg, France

^ permalink raw reply	[flat|nested] 318+ messages in thread

* RE: v2.1 Draft for a lengthof paper
  2024-08-14 12:17                 ` Jens Gustedt
@ 2024-08-14 12:40                   ` Ballman, Aaron
  2024-08-14 13:13                     ` Alejandro Colomar
                                       ` (2 more replies)
  2024-08-14 12:58                   ` Alejandro Colomar
  1 sibling, 3 replies; 318+ messages in thread
From: Ballman, Aaron @ 2024-08-14 12:40 UTC (permalink / raw)
  To: Jens Gustedt, Alejandro Colomar, Xavier Del Campo Romero
  Cc: Gcc Patches, Daniel Plakosh, Martin Uecker, Joseph Myers,
	Gabriel Ravier, Jakub Jelinek, Kees Cook, Qing Zhao, David Brown,
	Florian Weimer, Andreas Schwab, Timm Baeder, A. Jiang,
	Eugene Zelenko

> I think that this argument goes too short. E. g. implementation that already have compound expressions (or lambdas ;-) may provide a > quality implementation using `static_assert` and `typeof` alone, and don't have to touch their compiler at all.
>
> We should not impose an implementation in the language where doing it in a header can be completely sufficient.

But can doing this in a header be completely sufficient in practice? e.g., the user who passes a pointer rather than an array is in for quite a surprise, or passing a struct, or passing a FAM, etc. If we want to put constraints on the interface, that may be more challenging to do from a header file than from the compiler. offsetof is a cautionary tale in that compilers that want a reasonable QoI basically all implement this as a builtin rather than the header-only version.

> Plus, implementing as a macro in a header (probably <stddef.h>) makes also a feature test, for those applications that already have something similar. 
> this was basically what we did for `unreachable` and I think it worked out fine.

True!

I'm still thinking on how important rank + extent is vs overall array length. If C had constexpr functions, then I'd almost certainly want array rank and extent to be the building blocks and then lengthof can be a constexpr function looping over rank and summing extents. But we don't have that yet, and "bird hand" vs "bird in bush"... :-D

~Aaron

-----Original Message-----
From: Jens Gustedt <jens.gustedt@inria.fr> 
Sent: Wednesday, August 14, 2024 8:18 AM
To: Ballman, Aaron <aaron.ballman@intel.com>; Alejandro Colomar <alx@kernel.org>; Xavier Del Campo Romero <xavi.dcr@tutanota.com>
Cc: Gcc Patches <gcc-patches@gcc.gnu.org>; Daniel Plakosh <dplakosh@cert.org>; Martin Uecker <uecker@tugraz.at>; 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>; David Brown <david.brown@hesbynett.no>; Florian Weimer <fweimer@redhat.com>; Andreas Schwab <schwab@linux-m68k.org>; Timm Baeder <tbaeder@redhat.com>; A. Jiang <de34@live.cn>; Eugene Zelenko <eugene.zelenko@gmail.com>
Subject: RE: v2.1 Draft for a lengthof paper

Hi Aaron,

Am 14. August 2024 13:31:19 MESZ schrieb "Ballman, Aaron" <aaron.ballman@intel.com>:
> Sorry for top-posting, my work account is stuck on Outlook. :-/
> 
> > For a WG14 paper you should add these findings to support that choice.
> > Another option would be for WG14 to standardize the then existing implementation with the double underscores.
> 
> +1, it's always good to explain prior art and existing uses as part of the paper. However, please also point out that C++ has a prior art as well which is slightly different and very much worth considering: they have one API for getting the array's rank, and another for getting a specific rank's extent. This is a general solution that doesn't require the programmer to have deep knowledge of C's declarator syntax and how it relates to multidimensional arrays.
> 
> That said, I suspect WG14 would not be keen on standardizing `lengthof` without an ugly keyword given that there are plenty of other uses of it that would break: 
> 
> https://sourcegraph.com/github.com/illumos/illumos-gate/-/blob/usr/src
> /cmd/mailx/names.c?L53-55
> https://sourcegraph.com/github.com/Rockbox/rockbox/-/blob/tools/ipod_f
> w.c?L292-294
> https://sourcegraph.com/github.com/OpenSmalltalk/opensmalltalk-vm/-/bl
> ob/src/spur64.stack/validImage.c?L7014-7018
> (and many, many others)
> 
> >> > As for the parentheses, I personally think lengthof should follow 
> >> > similar rules compared to sizeof.
> >> 
> >> I think most people agree with this.
> >
> > I still don't, in particular not for standardisation.
> > 
> > We have to remember that there are many small C compilers out there.
> 
> Those compilers already have to handle parsing this for sizeof, so that's not particularly compelling (even if we wanted to design C for the lowest common denominator of implementation effort, which I'm not convinced is a good approach these days). That said, if we went with a rank/extent design, I think we'd *have* to use parens because the extent interface would take two operands (the array and the rank you're interested in getting the extent of) and it would be inconsistent for the rank interface to then not require parens.

I think that this argument goes too short. E. g. implementation that already have compound expressions (or lambdas ;-) may provide a quality implementation using `static_assert` and `typeof` alone, and don't have to touch their compiler at all.

We should not impose an implementation in the language where doing it in a header can be completely sufficient.

Plus, implementing as a macro in a header (probably <stddef.h>) makes also a feature test, for those applications that already have something similar. 
this was basically what we did for `unreachable` and I think it worked out fine.

Jens

> ~Aaron
> 
> -----Original Message-----
> From: Jens Gustedt <jens.gustedt@inria.fr>
> Sent: Wednesday, August 14, 2024 2:11 AM
> To: Alejandro Colomar <alx@kernel.org>; Xavier Del Campo Romero 
> <xavi.dcr@tutanota.com>
> Cc: Gcc Patches <gcc-patches@gcc.gnu.org>; Daniel Plakosh 
> <dplakosh@cert.org>; Martin Uecker <uecker@tugraz.at>; 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>; David Brown <david.brown@hesbynett.no>; 
> Florian Weimer <fweimer@redhat.com>; Andreas Schwab 
> <schwab@linux-m68k.org>; Timm Baeder <tbaeder@redhat.com>; A. Jiang 
> <de34@live.cn>; Eugene Zelenko <eugene.zelenko@gmail.com>; Ballman, 
> Aaron <aaron.ballman@intel.com>
> Subject: Re: v2.1 Draft for a lengthof paper
> 
> Am 14. August 2024 01:27:33 MESZ schrieb Alejandro Colomar <alx@kernel.org>:
> > Hi Xavier,
> > 
> > On Wed, Aug 14, 2024 at 12:38:53AM GMT, Xavier Del Campo Romero wrote:
> > > I have been overseeing these last emails -
> > 
> > Ahhh, good to know; thanks!  :)
> > 
> > > thank you very much for your
> > > efforts, Alex!
> > 
> > :-)
> > 
> > > I did not reply until now because I do not have prior experience 
> > > with gcc internals, so my feedback would probably have not been 
> > > that useful.
> > 
> > Ok.
> > 
> > > Those emails from 2020 were in fact discussing two completely 
> > > different proposals at once:
> > > 
> > > 1. Add _Lengthof + #include <stdlengthof.h> 2. Allow static 
> > > qualifier on compound literals
> > 
> > Yup.
> > 
> > > Whereas proposal #2 made it into C23 (kudos to Jens Gustedt!), and 
> > > as you already know by now, proposal #1 received some negative 
> > > feedback, suggesting _Typeof/typeof + some macro magic as a 
> > > pragmatic workaround instead.
> > 
> > The original author of that negative feedback talked to me in 
> > private a week ago, and said he likes my proposal.  We have no 
> > negative feedback anymore.  :)
> > 
> > > Since the proposal did not get much traction and I would had been 
> > > unable to contribute to gcc myself, I just gave up on it. IIRC the 
> > > deadline for new proposals closed soon after, anyway.
> > 
> > Ok.
> > 
> > > But I am glad that someone with proper experience took the initiative.
> > 
> > Fun fact: this is my second non-trivial patch to GCC.  I wouldn't 
> > say I had the proper experience with GCC internals when I started 
> > this patch set.  But I'm unemployed at the moment, which gives me 
> > all the time I need for learning those.  :)
> > 
> > > I still think the proposal is relevant and has interesting use cases.
> > > 
> > > > I have only added lengthof for now, not _Lengthof, as suggested by Jens.
> > > > Depending on feedback, I'll propose the uglified version.
> > > 
> > > Probably, all of us know why the uglified version is the usual 
> > > approach preferred by the C standard: we do not know how many 
> > > applications would break otherwise.
> > 
> > Yup.
> > 
> > > However, we see that this trend is now changing with C23, so 
> > > probably it makes sense to define lengthof directly.
> > 
> > Yeah, since Jens is in WG14 and he suggested to follow this trend, 
> > maybe we can.  If not, it's trivial to change the proposal to use 
> > the uglified name plus a macro.
> > 
> > Checking <https://codesearch.debian.net>, I see that while several 
> > projects have a lengthof() macro, all of them use it with semantics 
> > compatible with this keyword, so it shouldn't break too much.  Maybe 
> > those projects will start receiving diagnostics that they're 
> > redefining a standard keyword, but that's not too bad.
> 
> For a WG14 paper you should add these findings to support that choice.
> Another option would be for WG14 to standardize the then existing implementation with the double underscores.
> 
> > > As for the parentheses, I personally think lengthof should follow 
> > > similar rules compared to sizeof.
> > 
> > I think most people agree with this.
> 
> I still don't, in particular not for standardisation.
> 
> We have to remember that there are many small C compilers out there. 
> I would not want unnecessary burden on them. So my preferred choice would be a standardisation as a macro, similar to offsetof.
> gcc (and clang) could then just map that to their builtin, other compilers could use whatever they have at the moment, even just the macros that you have in the paper as a starting point. 
> 
> The rest would be "quality of implementation"
> 
> What time horizon do you see to add the feature for array parameters?
> 
> Thanks
> Jens
> 
> 
> > > Best regards,
> > 
> > Have a lovely night!
> > Alex
> > 
> 
> 
> --
> Jens Gustedt - INRIA & ICube, Strasbourg, France


-- 
Jens Gustedt - INRIA & ICube, Strasbourg, France 

^ permalink raw reply	[flat|nested] 318+ messages in thread

* Re: v2.1 Draft for a lengthof paper
  2024-08-14 12:17                 ` Jens Gustedt
  2024-08-14 12:40                   ` Ballman, Aaron
@ 2024-08-14 12:58                   ` Alejandro Colomar
  2024-08-14 13:21                     ` Ballman, Aaron
  2024-08-14 13:50                     ` Jens Gustedt
  1 sibling, 2 replies; 318+ messages in thread
From: Alejandro Colomar @ 2024-08-14 12:58 UTC (permalink / raw)
  To: Jens Gustedt, Ballman, Aaron
  Cc: Xavier Del Campo Romero, Gcc Patches, Daniel Plakosh,
	Martin Uecker, Joseph Myers, Gabriel Ravier, Jakub Jelinek,
	Kees Cook, Qing Zhao, David Brown, Florian Weimer,
	Andreas Schwab, Timm Baeder, A. Jiang, Eugene Zelenko

[-- Attachment #1: Type: text/plain, Size: 8173 bytes --]

Hi Aaron, Jens,

On Wed, Aug 14, 2024 at 02:17:52PM GMT, Jens Gustedt wrote:
> Am 14. August 2024 13:31:19 MESZ schrieb "Ballman, Aaron" <aaron.ballman@intel.com>:
> > Sorry for top-posting, my work account is stuck on Outlook. :-/
> > 
> > > For a WG14 paper you should add these findings to support that choice.
> > > Another option would be for WG14 to standardize the then existing implementation with the double underscores.
> > 
> > +1, it's always good to explain prior art and existing uses as part
> > of the paper. However, please also point out that C++ has a prior
> > art as well which is slightly different and very much worth
> > considering: they have one API for getting the array's rank,
> > and another for getting a specific rank's extent. This is a general
> > solution that doesn't require the programmer to have deep knowledge
> > of C's declarator syntax and how it relates to multidimensional
> > arrays.

I have added that to my draft.  I'll publish it soon as a reply to the
GCC mailing list.  See below for details of what I have added for now.

> > 
> > That said, I suspect WG14 would not be keen on standardizing
> > `lengthof` without an ugly keyword given that there are plenty of other uses of it that would break: 
> > 
> > https://sourcegraph.com/github.com/illumos/illumos-gate/-/blob/usr/src/cmd/mailx/names.c?L53-55
> > https://sourcegraph.com/github.com/Rockbox/rockbox/-/blob/tools/ipod_fw.c?L292-294
> > https://sourcegraph.com/github.com/OpenSmalltalk/opensmalltalk-vm/-/blob/src/spur64.stack/validImage.c?L7014-7018
> > (and many, many others)

What regex did you use for searching?

I was thinking of renaming the proposal to elementsof(), to avoid
confusion between length of an array and length of a string.  Would you
mind checking if elementsof() is ok?

> > >> > As for the parentheses, I personally think lengthof should follow 
> > >> > similar rules compared to sizeof.
> > >> 
> > >> I think most people agree with this.
> > >
> > > I still don't, in particular not for standardisation.
> > > 
> > > We have to remember that there are many small C compilers out there.
> > 
> > Those compilers already have to handle parsing this for sizeof, so
> > that's not particularly compelling

Agree.  I suspect it will be simpler for existing compilers to follow
sizeof than to have new syntax.  However, it's easy to keep it as a QoI
detail, so I've temporarily changed the wording to require parentheses,
and let implementations lift that restriction.

> > (even if we wanted to design C
> > for the lowest common denominator of implementation effort, which
> > I'm not convinced is a good approach these days).

Off-topic, but I wish that had been the approach when a few
implementations (I suspect proprietary vendors; this was never
disclosed) rejected redefining NULL as the right thing: (void *) 0.

I fixed one of the last free-software implementations of NULL that
expanded to 0, and nullptr would probably never have been added if WG14
had not accepted the pressure from such horrible implementations.

<https://github.com/cc65/cc65/issues/1823>

> > That said, if we went with a rank/extent design, I think we'd *have*
> > to use parens because the extent interface would take two operands
> > (the array and the rank you're interested in getting the extent of)
> > and it would be inconsistent for the rank interface to then not
> > require parens.

   Prior art
     C
            It is common in C programs to get the number of elements of
            an array via the usual sizeof division and  wrap  it  in  a
            macro.  Common names include:

            •  ARRAY_SIZE()
            •  NELEM()
            •  NELEMS()
            •  NITEMS()
            •  NELTS()
            •  elementsof()
            •  lengthof()

     C++
            In  C++,  there  are several standard features to determine
            the number of elements of an array:

            std::size()   (since C++17)
            std::ssize()  (since C++20)
                   The syntax of these is  identical  to  the  usual  C
                   macros named above.

                   It’s  a  bit different, since it’s a general purpose
                   sizing template, which works on non‐array types too,
                   with different semantics.

                   But when applied to an array, it has the same seman‐
                   tics as the macros above.

            std::extent  (since C++23)
                   The syntax of this is quite different.   It  uses  a
                   numeric index as a second parameter to determine the
                   dimension  in which the number of elements should be
                   counted.

                   C arrays are much simpler than C++’s many array‐like
                   types, and I don’t see a reason why  we  would  need
                   something  as  complex  as  std::extent  in C.  Cer‐
                   tainly, existing projects have not developed such  a
                   macro, even if it is technically possible:

                       #define DEREFERENCE(a, n) DEREFERENCE_ ## n (a, c)
                       #define DEREFERENCE_9(a)  (*********(a))
                       #define DEREFERENCE_8(a)  (********(a))
                       #define DEREFERENCE_7(a)  (*******(a))
                       #define DEREFERENCE_6(a)  (******(a))
                       #define DEREFERENCE_5(a)  (*****(a))
                       #define DEREFERENCE_4(a)  (****(a))
                       #define DEREFERENCE_3(a)  (***(a))
                       #define DEREFERENCE_2(a)  (**(a))
                       #define DEREFERENCE_1(a)  (*(a))
                       #define DEREFERENCE_0(a)  ((a))
                       #define extent(a, n)      nitems(DEREFERENCE(a, n))

                   If any project needs that syntax, they can implement
                   their  own  trivial  wrapper  macro, as demonstrated
                   above.

            Existing prior art in C seems to favour a design that  fol‐
            lows the syntax of other operators like sizeof.

> I think that this argument goes too short. E. g. implementation that
> already have compound expressions (or lambdas ;-) may provide a
> quality implementation using `static_assert` and `typeof` alone, and
> don't have to touch their compiler at all.
> 
> We should not impose an implementation in the language where doing it
> in a header can be completely sufficient.

I have concerns about a libc (or a predefined macro) implementation:
the sizeof division causes double evaluation with any VLAs, while my
implementation for GCC has less cases of evaluation, and when it needs
to evaluate, it only does it once.  It would be hard to find a good
wording that would allow an implementation to implement this as a macro.

   constexpr
     The  usual  sizeof division evaluates the operand and results in a
     run‐time value in cases where it wouldn’t be  necessary.   If  the
     top‐level  array  number  of  elements is determined by an integer
     constant expression, but an internal array is a VLA,  sizeof  must
     evaluate:

            int  a[7][n];
            int  (*p)[7][n];

            p = &a;
            nitems(*p++);

     With  a  elementsof operator, this would result in an integer con‐
     stant expression of value 7.

   Double evaluation
     With the sizeof‐based implementation from above, the example  from
     above causes double evaluation of *p++.

> Plus, implementing as a macro in a header (probably <stddef.h>) makes
> also a feature test, for those applications that already have
> something similar. 

This is interesting.  But I think an implementation could just

	#define lengthof lengthof

to provide a feature-test macro.

> this was basically what we did for `unreachable` and I think it worked
> out fine.
> 
> Jens

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] 318+ messages in thread

* Re: v2.1 Draft for a lengthof paper
  2024-08-14 12:40                   ` Ballman, Aaron
@ 2024-08-14 13:13                     ` Alejandro Colomar
  2024-08-14 13:24                     ` Jens Gustedt
  2024-08-14 13:50                     ` Martin Uecker
  2 siblings, 0 replies; 318+ messages in thread
From: Alejandro Colomar @ 2024-08-14 13:13 UTC (permalink / raw)
  To: Ballman, Aaron
  Cc: Jens Gustedt, Xavier Del Campo Romero, Gcc Patches,
	Daniel Plakosh, Martin Uecker, Joseph Myers, Gabriel Ravier,
	Jakub Jelinek, Kees Cook, Qing Zhao, David Brown, Florian Weimer,
	Andreas Schwab, Timm Baeder, A. Jiang, Eugene Zelenko

[-- Attachment #1: Type: text/plain, Size: 4330 bytes --]

Hi Aaron,

On Wed, Aug 14, 2024 at 12:40:41PM GMT, Ballman, Aaron wrote:
> > We should not impose an implementation in the language where doing
> > it in a header can be completely sufficient.
> 
> But can doing this in a header be completely sufficient in practice?
> e.g., the user who passes a pointer rather than an array is in for
> quite a surprise, or passing a struct, or passing a FAM, etc. If we
> want to put constraints on the interface, that may be more challenging
> to do from a header file than from the compiler.

I've provided a C23-portable and safe implementation of lengthof() as a
macro:

   Portability
     Prior  to C23 it was impossible to do this portably, but since C23
     it is possible to portably write a macro that determines the  num‐
     ber  of  elements  of an array, that is, the number of elements in
     the array.

            #define must_be(e)                                      \
            (                                                       \
                0 * (int) sizeof(                                   \
                    struct {                                        \
                        static_assert(e);                           \
                        int ISO_C_forbids_a_struct_with_no_members; \
                    }                                               \
                )                                                   \
            )
            #define is_array(a)                                     \
            (                                                       \
                _Generic(&(a),                                      \
                    typeof((a)[0]) **:  0,                          \
                    default:            1                           \
                )                                                   \
            )
            #define sizeof_array(a)  (sizeof(a) + must_be(is_array(a)))
            #define nitems(a)        (sizeof_array(a) / sizeof((a)[0]))

     While diagnostics could be better, with good  helper‐macro  names,
     they are decent.

The issues with this implementation are also listed in the paper.
Here's a TL;DR:

-  It doesn't accept type names.

-  In results unnecessarily in run-time values where a keyword could
   result in an integer constant expression:

            int  a[7][n];
            int  (*p)[7][n];

            p = &a;
            nitems(*p++);

-  Double evaluation: not only the macro evaluates in more cases than a
   keyword, it evaluates twice (due to the two sizeof calls).

-  Less diagnostics.  Since there are less constant expressions, there
   are less opportunities to catch UB.

So far, we've lived with all of those issues (plus the lack of
portability, since this could only be implemented via compiler
extensions until C23).

But ideally, I'd like to avoid the wording juggling that would be
required to allow such an implementation.  Here's an example of the
difference in wording that would be required:

     The elementsof operator yields the number of elements
     of its operand.
     The number of elements is determined from the type of the operand.
     The result is an integer.
     If the number of elements of the array type is variable,
     the operand is evaluated;
    +otherwise,
    +if the operand is a variable-length array,
    +it is unspecified whether the operand is evaluated;
     otherwise,
     the operand is not evaluated and the result is an integer constant.
    +If the operand is evaluated,
    +it is unspecified the number of times it is evaluated.

Which sounds very suspicious.

> I'm still thinking on how important rank + extent is vs overall array
> length. If C had constexpr functions, then I'd almost certainly want
> array rank and extent to be the building blocks and then lengthof can
> be a constexpr function looping over rank and summing extents. But we
> don't have that yet, and "bird hand" vs "bird in bush"... :-D

Or you can build it the other way around: define extent() as a macro
that wraps lengthof().

About rank, I suspect you could also develop something with _Generic(3),
but I didn't try.

Cheers,
Alex

-- 
<https://www.alejandro-colomar.es/>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 318+ messages in thread

* RE: v2.1 Draft for a lengthof paper
  2024-08-14 12:58                   ` Alejandro Colomar
@ 2024-08-14 13:21                     ` Ballman, Aaron
  2024-08-14 14:00                       ` Alejandro Colomar
  2024-08-14 13:50                     ` Jens Gustedt
  1 sibling, 1 reply; 318+ messages in thread
From: Ballman, Aaron @ 2024-08-14 13:21 UTC (permalink / raw)
  To: Alejandro Colomar, Jens Gustedt
  Cc: Xavier Del Campo Romero, Gcc Patches, Daniel Plakosh,
	Martin Uecker, Joseph Myers, Gabriel Ravier, Jakub Jelinek,
	Kees Cook, Qing Zhao, David Brown, Florian Weimer,
	Andreas Schwab, Timm Baeder, A. Jiang, Eugene Zelenko

> What regex did you use for searching?

I went cheap and easy rather than trying to narrow down:
https://sourcegraph.com/search?q=context:global+lang:C+lengthof&patternType=regexp&sm=0

> I was thinking of renaming the proposal to elementsof(), to avoid confusion between length of an array and length of a string.  Would you mind checking if elementsof() is ok?

From what I was seeing, it looks to be used more uniformly as a function-like macro accepting a single argument.

~Aaron

-----Original Message-----
From: Alejandro Colomar <alx@kernel.org> 
Sent: Wednesday, August 14, 2024 8:58 AM
To: Jens Gustedt <jens.gustedt@inria.fr>; Ballman, Aaron <aaron.ballman@intel.com>
Cc: Xavier Del Campo Romero <xavi.dcr@tutanota.com>; Gcc Patches <gcc-patches@gcc.gnu.org>; Daniel Plakosh <dplakosh@cert.org>; Martin Uecker <uecker@tugraz.at>; 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>; David Brown <david.brown@hesbynett.no>; Florian Weimer <fweimer@redhat.com>; Andreas Schwab <schwab@linux-m68k.org>; Timm Baeder <tbaeder@redhat.com>; A. Jiang <de34@live.cn>; Eugene Zelenko <eugene.zelenko@gmail.com>
Subject: Re: v2.1 Draft for a lengthof paper

Hi Aaron, Jens,

On Wed, Aug 14, 2024 at 02:17:52PM GMT, Jens Gustedt wrote:
> Am 14. August 2024 13:31:19 MESZ schrieb "Ballman, Aaron" <aaron.ballman@intel.com>:
> > Sorry for top-posting, my work account is stuck on Outlook. :-/
> > 
> > > For a WG14 paper you should add these findings to support that choice.
> > > Another option would be for WG14 to standardize the then existing implementation with the double underscores.
> > 
> > +1, it's always good to explain prior art and existing uses as part
> > of the paper. However, please also point out that C++ has a prior 
> > art as well which is slightly different and very much worth
> > considering: they have one API for getting the array's rank, and 
> > another for getting a specific rank's extent. This is a general 
> > solution that doesn't require the programmer to have deep knowledge 
> > of C's declarator syntax and how it relates to multidimensional 
> > arrays.

I have added that to my draft.  I'll publish it soon as a reply to the GCC mailing list.  See below for details of what I have added for now.

> > 
> > That said, I suspect WG14 would not be keen on standardizing 
> > `lengthof` without an ugly keyword given that there are plenty of other uses of it that would break:
> > 
> > https://sourcegraph.com/github.com/illumos/illumos-gate/-/blob/usr/s
> > rc/cmd/mailx/names.c?L53-55
> > https://sourcegraph.com/github.com/Rockbox/rockbox/-/blob/tools/ipod
> > _fw.c?L292-294
> > https://sourcegraph.com/github.com/OpenSmalltalk/opensmalltalk-vm/-/
> > blob/src/spur64.stack/validImage.c?L7014-7018
> > (and many, many others)

What regex did you use for searching?

I was thinking of renaming the proposal to elementsof(), to avoid confusion between length of an array and length of a string.  Would you mind checking if elementsof() is ok?

> > >> > As for the parentheses, I personally think lengthof should 
> > >> > follow similar rules compared to sizeof.
> > >> 
> > >> I think most people agree with this.
> > >
> > > I still don't, in particular not for standardisation.
> > > 
> > > We have to remember that there are many small C compilers out there.
> > 
> > Those compilers already have to handle parsing this for sizeof, so 
> > that's not particularly compelling

Agree.  I suspect it will be simpler for existing compilers to follow sizeof than to have new syntax.  However, it's easy to keep it as a QoI detail, so I've temporarily changed the wording to require parentheses, and let implementations lift that restriction.

> > (even if we wanted to design C
> > for the lowest common denominator of implementation effort, which 
> > I'm not convinced is a good approach these days).

Off-topic, but I wish that had been the approach when a few implementations (I suspect proprietary vendors; this was never
disclosed) rejected redefining NULL as the right thing: (void *) 0.

I fixed one of the last free-software implementations of NULL that expanded to 0, and nullptr would probably never have been added if WG14 had not accepted the pressure from such horrible implementations.

<https://github.com/cc65/cc65/issues/1823>

> > That said, if we went with a rank/extent design, I think we'd *have* 
> > to use parens because the extent interface would take two operands 
> > (the array and the rank you're interested in getting the extent of) 
> > and it would be inconsistent for the rank interface to then not 
> > require parens.

   Prior art
     C
            It is common in C programs to get the number of elements of
            an array via the usual sizeof division and  wrap  it  in  a
            macro.  Common names include:

            •  ARRAY_SIZE()
            •  NELEM()
            •  NELEMS()
            •  NITEMS()
            •  NELTS()
            •  elementsof()
            •  lengthof()

     C++
            In  C++,  there  are several standard features to determine
            the number of elements of an array:

            std::size()   (since C++17)
            std::ssize()  (since C++20)
                   The syntax of these is  identical  to  the  usual  C
                   macros named above.

                   It’s  a  bit different, since it’s a general purpose
                   sizing template, which works on non‐array types too,
                   with different semantics.

                   But when applied to an array, it has the same seman‐
                   tics as the macros above.

            std::extent  (since C++23)
                   The syntax of this is quite different.   It  uses  a
                   numeric index as a second parameter to determine the
                   dimension  in which the number of elements should be
                   counted.

                   C arrays are much simpler than C++’s many array‐like
                   types, and I don’t see a reason why  we  would  need
                   something  as  complex  as  std::extent  in C.  Cer‐
                   tainly, existing projects have not developed such  a
                   macro, even if it is technically possible:

                       #define DEREFERENCE(a, n) DEREFERENCE_ ## n (a, c)
                       #define DEREFERENCE_9(a)  (*********(a))
                       #define DEREFERENCE_8(a)  (********(a))
                       #define DEREFERENCE_7(a)  (*******(a))
                       #define DEREFERENCE_6(a)  (******(a))
                       #define DEREFERENCE_5(a)  (*****(a))
                       #define DEREFERENCE_4(a)  (****(a))
                       #define DEREFERENCE_3(a)  (***(a))
                       #define DEREFERENCE_2(a)  (**(a))
                       #define DEREFERENCE_1(a)  (*(a))
                       #define DEREFERENCE_0(a)  ((a))
                       #define extent(a, n)      nitems(DEREFERENCE(a, n))

                   If any project needs that syntax, they can implement
                   their  own  trivial  wrapper  macro, as demonstrated
                   above.

            Existing prior art in C seems to favour a design that  fol‐
            lows the syntax of other operators like sizeof.

> I think that this argument goes too short. E. g. implementation that 
> already have compound expressions (or lambdas ;-) may provide a 
> quality implementation using `static_assert` and `typeof` alone, and 
> don't have to touch their compiler at all.
> 
> We should not impose an implementation in the language where doing it 
> in a header can be completely sufficient.

I have concerns about a libc (or a predefined macro) implementation:
the sizeof division causes double evaluation with any VLAs, while my implementation for GCC has less cases of evaluation, and when it needs to evaluate, it only does it once.  It would be hard to find a good wording that would allow an implementation to implement this as a macro.

   constexpr
     The  usual  sizeof division evaluates the operand and results in a
     run‐time value in cases where it wouldn’t be  necessary.   If  the
     top‐level  array  number  of  elements is determined by an integer
     constant expression, but an internal array is a VLA,  sizeof  must
     evaluate:

            int  a[7][n];
            int  (*p)[7][n];

            p = &a;
            nitems(*p++);

     With  a  elementsof operator, this would result in an integer con‐
     stant expression of value 7.

   Double evaluation
     With the sizeof‐based implementation from above, the example  from
     above causes double evaluation of *p++.

> Plus, implementing as a macro in a header (probably <stddef.h>) makes 
> also a feature test, for those applications that already have 
> something similar.

This is interesting.  But I think an implementation could just

	#define lengthof lengthof

to provide a feature-test macro.

> this was basically what we did for `unreachable` and I think it worked 
> out fine.
> 
> Jens

Have a lovely day!
Alex

--
<https://www.alejandro-colomar.es/>

^ permalink raw reply	[flat|nested] 318+ messages in thread

* RE: v2.1 Draft for a lengthof paper
  2024-08-14 12:40                   ` Ballman, Aaron
  2024-08-14 13:13                     ` Alejandro Colomar
@ 2024-08-14 13:24                     ` Jens Gustedt
  2024-08-14 13:59                       ` Ballman, Aaron
  2024-08-14 13:50                     ` Martin Uecker
  2 siblings, 1 reply; 318+ messages in thread
From: Jens Gustedt @ 2024-08-14 13:24 UTC (permalink / raw)
  To: Ballman, Aaron, Alejandro Colomar, Xavier Del Campo Romero
  Cc: Gcc Patches, Daniel Plakosh, Martin Uecker, Joseph Myers,
	Gabriel Ravier, Jakub Jelinek, Kees Cook, Qing Zhao, David Brown,
	Florian Weimer, Andreas Schwab, Timm Baeder, A. Jiang,
	Eugene Zelenko

Am 14. August 2024 14:40:41 MESZ schrieb "Ballman, Aaron" <aaron.ballman@intel.com>:
> > I think that this argument goes too short. E. g. implementation that already have compound expressions (or lambdas ;-) may provide a > quality implementation using `static_assert` and `typeof` alone, and don't have to touch their compiler at all.
> >
> > We should not impose an implementation in the language where doing it in a header can be completely sufficient.
> 
> But can doing this in a header be completely sufficient in practice? 

Ithindso.

> e.g., the user who passes a pointer rather than an array is in for quite a surprise, or passing a struct, or passing a FAM, etc. If we want to put constraints on the interface, that may be more challenging to do from a header file than from the compiler. offsetof is a cautionary tale in that compilers that want a reasonable QoI basically all implement this as a builtin rather than the header-only version.

Yes,  with the tools that I listed and the ideas that are already in the
paper you can basically do all that, including given valuable feedback
in case of failure. 

I am currently on a summer bike trip, so not able to provide
a full reference implantation. But could do so, once I am back. 


> > Plus, implementing as a macro in a header (probably <stddef.h>) makes also a feature test, for those applications that already have something similar. 
> > this was basically what we did for `unreachable` and I think it worked out fine.
> 
> True!
> 
> I'm still thinking on how important rank + extent is vs overall array length. If C had constexpr functions, then I'd almost certainly want array rank and extent to be the building blocks and then lengthof can be a constexpr function looping over rank and summing extents. But we don't have that yet, and "bird hand" vs "bird in bush"... :-D

Why would you be looping? lengthof only addresses the outer dimension
sizeof would need a loop, no ?

Generally I would be opposed to imposing a complicated solution for a simple
feature

Jens

> 
> ~Aaron
> 
> -----Original Message-----
> From: Jens Gustedt <jens.gustedt@inria.fr> 
> Sent: Wednesday, August 14, 2024 8:18 AM
> To: Ballman, Aaron <aaron.ballman@intel.com>; Alejandro Colomar <alx@kernel.org>; Xavier Del Campo Romero <xavi.dcr@tutanota.com>
> Cc: Gcc Patches <gcc-patches@gcc.gnu.org>; Daniel Plakosh <dplakosh@cert.org>; Martin Uecker <uecker@tugraz.at>; 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>; David Brown <david.brown@hesbynett.no>; Florian Weimer <fweimer@redhat.com>; Andreas Schwab <schwab@linux-m68k.org>; Timm Baeder <tbaeder@redhat.com>; A. Jiang <de34@live.cn>; Eugene Zelenko <eugene.zelenko@gmail.com>
> Subject: RE: v2.1 Draft for a lengthof paper
> 
> Hi Aaron,
> 
> Am 14. August 2024 13:31:19 MESZ schrieb "Ballman, Aaron" <aaron.ballman@intel.com>:
> > Sorry for top-posting, my work account is stuck on Outlook. :-/
> > 
> > > For a WG14 paper you should add these findings to support that choice.
> > > Another option would be for WG14 to standardize the then existing implementation with the double underscores.
> > 
> > +1, it's always good to explain prior art and existing uses as part of the paper. However, please also point out that C++ has a prior art as well which is slightly different and very much worth considering: they have one API for getting the array's rank, and another for getting a specific rank's extent. This is a general solution that doesn't require the programmer to have deep knowledge of C's declarator syntax and how it relates to multidimensional arrays.
> > 
> > That said, I suspect WG14 would not be keen on standardizing `lengthof` without an ugly keyword given that there are plenty of other uses of it that would break: 
> > 
> > https://sourcegraph.com/github.com/illumos/illumos-gate/-/blob/usr/src
> > /cmd/mailx/names.c?L53-55
> > https://sourcegraph.com/github.com/Rockbox/rockbox/-/blob/tools/ipod_f
> > w.c?L292-294
> > https://sourcegraph.com/github.com/OpenSmalltalk/opensmalltalk-vm/-/bl
> > ob/src/spur64.stack/validImage.c?L7014-7018
> > (and many, many others)
> > 
> > >> > As for the parentheses, I personally think lengthof should follow 
> > >> > similar rules compared to sizeof.
> > >> 
> > >> I think most people agree with this.
> > >
> > > I still don't, in particular not for standardisation.
> > > 
> > > We have to remember that there are many small C compilers out there.
> > 
> > Those compilers already have to handle parsing this for sizeof, so that's not particularly compelling (even if we wanted to design C for the lowest common denominator of implementation effort, which I'm not convinced is a good approach these days). That said, if we went with a rank/extent design, I think we'd *have* to use parens because the extent interface would take two operands (the array and the rank you're interested in getting the extent of) and it would be inconsistent for the rank interface to then not require parens.
> 
> I think that this argument goes too short. E. g. implementation that already have compound expressions (or lambdas ;-) may provide a quality implementation using `static_assert` and `typeof` alone, and don't have to touch their compiler at all.
> 
> We should not impose an implementation in the language where doing it in a header can be completely sufficient.
> 
> Plus, implementing as a macro in a header (probably <stddef.h>) makes also a feature test, for those applications that already have something similar. 
> this was basically what we did for `unreachable` and I think it worked out fine.
> 
> Jens
> 
> > ~Aaron
> > 
> > -----Original Message-----
> > From: Jens Gustedt <jens.gustedt@inria.fr>
> > Sent: Wednesday, August 14, 2024 2:11 AM
> > To: Alejandro Colomar <alx@kernel.org>; Xavier Del Campo Romero 
> > <xavi.dcr@tutanota.com>
> > Cc: Gcc Patches <gcc-patches@gcc.gnu.org>; Daniel Plakosh 
> > <dplakosh@cert.org>; Martin Uecker <uecker@tugraz.at>; 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>; David Brown <david.brown@hesbynett.no>; 
> > Florian Weimer <fweimer@redhat.com>; Andreas Schwab 
> > <schwab@linux-m68k.org>; Timm Baeder <tbaeder@redhat.com>; A. Jiang 
> > <de34@live.cn>; Eugene Zelenko <eugene.zelenko@gmail.com>; Ballman, 
> > Aaron <aaron.ballman@intel.com>
> > Subject: Re: v2.1 Draft for a lengthof paper
> > 
> > Am 14. August 2024 01:27:33 MESZ schrieb Alejandro Colomar <alx@kernel.org>:
> > > Hi Xavier,
> > > 
> > > On Wed, Aug 14, 2024 at 12:38:53AM GMT, Xavier Del Campo Romero wrote:
> > > > I have been overseeing these last emails -
> > > 
> > > Ahhh, good to know; thanks!  :)
> > > 
> > > > thank you very much for your
> > > > efforts, Alex!
> > > 
> > > :-)
> > > 
> > > > I did not reply until now because I do not have prior experience 
> > > > with gcc internals, so my feedback would probably have not been 
> > > > that useful.
> > > 
> > > Ok.
> > > 
> > > > Those emails from 2020 were in fact discussing two completely 
> > > > different proposals at once:
> > > > 
> > > > 1. Add _Lengthof + #include <stdlengthof.h> 2. Allow static 
> > > > qualifier on compound literals
> > > 
> > > Yup.
> > > 
> > > > Whereas proposal #2 made it into C23 (kudos to Jens Gustedt!), and 
> > > > as you already know by now, proposal #1 received some negative 
> > > > feedback, suggesting _Typeof/typeof + some macro magic as a 
> > > > pragmatic workaround instead.
> > > 
> > > The original author of that negative feedback talked to me in 
> > > private a week ago, and said he likes my proposal.  We have no 
> > > negative feedback anymore.  :)
> > > 
> > > > Since the proposal did not get much traction and I would had been 
> > > > unable to contribute to gcc myself, I just gave up on it. IIRC the 
> > > > deadline for new proposals closed soon after, anyway.
> > > 
> > > Ok.
> > > 
> > > > But I am glad that someone with proper experience took the initiative.
> > > 
> > > Fun fact: this is my second non-trivial patch to GCC.  I wouldn't 
> > > say I had the proper experience with GCC internals when I started 
> > > this patch set.  But I'm unemployed at the moment, which gives me 
> > > all the time I need for learning those.  :)
> > > 
> > > > I still think the proposal is relevant and has interesting use cases.
> > > > 
> > > > > I have only added lengthof for now, not _Lengthof, as suggested by Jens.
> > > > > Depending on feedback, I'll propose the uglified version.
> > > > 
> > > > Probably, all of us know why the uglified version is the usual 
> > > > approach preferred by the C standard: we do not know how many 
> > > > applications would break otherwise.
> > > 
> > > Yup.
> > > 
> > > > However, we see that this trend is now changing with C23, so 
> > > > probably it makes sense to define lengthof directly.
> > > 
> > > Yeah, since Jens is in WG14 and he suggested to follow this trend, 
> > > maybe we can.  If not, it's trivial to change the proposal to use 
> > > the uglified name plus a macro.
> > > 
> > > Checking <https://codesearch.debian.net>, I see that while several 
> > > projects have a lengthof() macro, all of them use it with semantics 
> > > compatible with this keyword, so it shouldn't break too much.  Maybe 
> > > those projects will start receiving diagnostics that they're 
> > > redefining a standard keyword, but that's not too bad.
> > 
> > For a WG14 paper you should add these findings to support that choice.
> > Another option would be for WG14 to standardize the then existing implementation with the double underscores.
> > 
> > > > As for the parentheses, I personally think lengthof should follow 
> > > > similar rules compared to sizeof.
> > > 
> > > I think most people agree with this.
> > 
> > I still don't, in particular not for standardisation.
> > 
> > We have to remember that there are many small C compilers out there. 
> > I would not want unnecessary burden on them. So my preferred choice would be a standardisation as a macro, similar to offsetof.
> > gcc (and clang) could then just map that to their builtin, other compilers could use whatever they have at the moment, even just the macros that you have in the paper as a starting point. 
> > 
> > The rest would be "quality of implementation"
> > 
> > What time horizon do you see to add the feature for array parameters?
> > 
> > Thanks
> > Jens
> > 
> > 
> > > > Best regards,
> > > 
> > > Have a lovely night!
> > > Alex
> > > 
> > 
> > 
> > --
> > Jens Gustedt - INRIA & ICube, Strasbourg, France
> 
> 


-- 
Jens Gustedt - INRIA & ICube, Strasbourg, France

^ permalink raw reply	[flat|nested] 318+ messages in thread

* Re: v2.1 Draft for a lengthof paper
  2024-08-14 12:40                   ` Ballman, Aaron
  2024-08-14 13:13                     ` Alejandro Colomar
  2024-08-14 13:24                     ` Jens Gustedt
@ 2024-08-14 13:50                     ` Martin Uecker
  2024-08-14 14:12                       ` Alejandro Colomar
  2 siblings, 1 reply; 318+ messages in thread
From: Martin Uecker @ 2024-08-14 13:50 UTC (permalink / raw)
  To: Ballman, Aaron, Jens Gustedt, Alejandro Colomar, Xavier Del Campo Romero
  Cc: Gcc Patches, Daniel Plakosh, Joseph Myers, Gabriel Ravier,
	Jakub Jelinek, Kees Cook, Qing Zhao, David Brown, Florian Weimer,
	Andreas Schwab, Timm Baeder, A. Jiang, Eugene Zelenko

Am Mittwoch, dem 14.08.2024 um 12:40 +0000 schrieb Ballman, Aaron:
> > I think that this argument goes too short. E. g. implementation that already have compound expressions (or lambdas
> > ;-) may provide a > quality implementation using `static_assert` and `typeof` alone, and don't have to touch their
> > compiler at all.
> > 
> > We should not impose an implementation in the language where doing it in a header can be completely sufficient.
> 
> But can doing this in a header be completely sufficient in practice? e.g., the user who passes a pointer rather than
> an array is in for quite a surprise, or passing a struct, or passing a FAM, etc. If we want to put constraints on the
> interface, that may be more challenging to do from a header file than from the compiler. offsetof is a cautionary tale
> in that compilers that want a reasonable QoI basically all implement this as a builtin rather than the header-only
> version.
> 
> > Plus, implementing as a macro in a header (probably <stddef.h>) makes also a feature test, for those applications
> > that already have something similar. 
> > this was basically what we did for `unreachable` and I think it worked out fine.
> 
> True!
> 
> I'm still thinking on how important rank + extent is vs overall array length. If C had constexpr functions, then I'd
> almost certainly want array rank and extent to be the building blocks and then lengthof can be a constexpr function
> looping over rank and summing extents. But we don't have that yet, and "bird hand" vs "bird in bush"... :-D

An operator that returns an array with all dimensions of a multi-dimensional
array would make a a lot of sense to me. 


double array[4][3][2];

// array_dims(array) = (constexpr size_t[3]){ 4, 3, 2 }

int dim1 = (array_dims(array))[0]
int dim2 = (array_dims(array))[1]
int dim3 = (array_dims(array))[2]
 
You can then implement lengthof in terms of this operator:

#define lengthof(x) (array_dims(array)[0])

and you can obtain the rank by applying lengthof to the array:

#define rank(x) lengthof(array_dims(x))


If the array is constexpr for regular arrays and array
indexing returns a constant again for constexpr arrays, this
would all work out.

Martin


> 
> ~Aaron
> 
> -----Original Message-----
> From: Jens Gustedt <jens.gustedt@inria.fr> 
> Sent: Wednesday, August 14, 2024 8:18 AM
> To: Ballman, Aaron <aaron.ballman@intel.com>; Alejandro Colomar <alx@kernel.org>; Xavier Del Campo Romero
> <xavi.dcr@tutanota.com>
> Cc: Gcc Patches <gcc-patches@gcc.gnu.org>; Daniel Plakosh <dplakosh@cert.org>; Martin Uecker <uecker@tugraz.at>;
> 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>; David Brown <david.brown@hesbynett.no>; Florian Weimer
> <fweimer@redhat.com>; Andreas Schwab <schwab@linux-m68k.org>; Timm Baeder <tbaeder@redhat.com>; A. Jiang
> <de34@live.cn>; Eugene Zelenko <eugene.zelenko@gmail.com>
> Subject: RE: v2.1 Draft for a lengthof paper
> 
> Hi Aaron,
> 
> Am 14. August 2024 13:31:19 MESZ schrieb "Ballman, Aaron" <aaron.ballman@intel.com>:
> > Sorry for top-posting, my work account is stuck on Outlook. :-/
> > 
> > > For a WG14 paper you should add these findings to support that choice.
> > > Another option would be for WG14 to standardize the then existing implementation with the double underscores.
> > 
> > +1, it's always good to explain prior art and existing uses as part of the paper. However, please also point out
> > that C++ has a prior art as well which is slightly different and very much worth considering: they have one API for
> > getting the array's rank, and another for getting a specific rank's extent. This is a general solution that doesn't
> > require the programmer to have deep knowledge of C's declarator syntax and how it relates to multidimensional
> > arrays.
> > 
> > That said, I suspect WG14 would not be keen on standardizing `lengthof` without an ugly keyword given that there are
> > plenty of other uses of it that would break: 
> > 
> > https://sourcegraph.com/github.com/illumos/illumos-gate/-/blob/usr/src
> > /cmd/mailx/names.c?L53-55
> > https://sourcegraph.com/github.com/Rockbox/rockbox/-/blob/tools/ipod_f
> > w.c?L292-294
> > https://sourcegraph.com/github.com/OpenSmalltalk/opensmalltalk-vm/-/bl
> > ob/src/spur64.stack/validImage.c?L7014-7018
> > (and many, many others)
> > 
> > > > > As for the parentheses, I personally think lengthof should follow 
> > > > > similar rules compared to sizeof.
> > > > 
> > > > I think most people agree with this.
> > > 
> > > I still don't, in particular not for standardisation.
> > > 
> > > We have to remember that there are many small C compilers out there.
> > 
> > Those compilers already have to handle parsing this for sizeof, so that's not particularly compelling (even if we
> > wanted to design C for the lowest common denominator of implementation effort, which I'm not convinced is a good
> > approach these days). That said, if we went with a rank/extent design, I think we'd *have* to use parens because the
> > extent interface would take two operands (the array and the rank you're interested in getting the extent of) and it
> > would be inconsistent for the rank interface to then not require parens.
> 
> I think that this argument goes too short. E. g. implementation that already have compound expressions (or lambdas ;-)
> may provide a quality implementation using `static_assert` and `typeof` alone, and don't have to touch their compiler
> at all.
> 
> We should not impose an implementation in the language where doing it in a header can be completely sufficient.
> 
> Plus, implementing as a macro in a header (probably <stddef.h>) makes also a feature test, for those applications that
> already have something similar. 
> this was basically what we did for `unreachable` and I think it worked out fine.
> 
> Jens
> 
> > ~Aaron
> > 
> > -----Original Message-----
> > From: Jens Gustedt <jens.gustedt@inria.fr>
> > Sent: Wednesday, August 14, 2024 2:11 AM
> > To: Alejandro Colomar <alx@kernel.org>; Xavier Del Campo Romero 
> > <xavi.dcr@tutanota.com>
> > Cc: Gcc Patches <gcc-patches@gcc.gnu.org>; Daniel Plakosh 
> > <dplakosh@cert.org>; Martin Uecker <uecker@tugraz.at>; 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>; David Brown <david.brown@hesbynett.no>; 
> > Florian Weimer <fweimer@redhat.com>; Andreas Schwab 
> > <schwab@linux-m68k.org>; Timm Baeder <tbaeder@redhat.com>; A. Jiang 
> > <de34@live.cn>; Eugene Zelenko <eugene.zelenko@gmail.com>; Ballman, 
> > Aaron <aaron.ballman@intel.com>
> > Subject: Re: v2.1 Draft for a lengthof paper
> > 
> > Am 14. August 2024 01:27:33 MESZ schrieb Alejandro Colomar <alx@kernel.org>:
> > > Hi Xavier,
> > > 
> > > On Wed, Aug 14, 2024 at 12:38:53AM GMT, Xavier Del Campo Romero wrote:
> > > > I have been overseeing these last emails -
> > > 
> > > Ahhh, good to know; thanks!  :)
> > > 
> > > > thank you very much for your
> > > > efforts, Alex!
> > > 
> > > :-)
> > > 
> > > > I did not reply until now because I do not have prior experience 
> > > > with gcc internals, so my feedback would probably have not been 
> > > > that useful.
> > > 
> > > Ok.
> > > 
> > > > Those emails from 2020 were in fact discussing two completely 
> > > > different proposals at once:
> > > > 
> > > > 1. Add _Lengthof + #include <stdlengthof.h> 2. Allow static 
> > > > qualifier on compound literals
> > > 
> > > Yup.
> > > 
> > > > Whereas proposal #2 made it into C23 (kudos to Jens Gustedt!), and 
> > > > as you already know by now, proposal #1 received some negative 
> > > > feedback, suggesting _Typeof/typeof + some macro magic as a 
> > > > pragmatic workaround instead.
> > > 
> > > The original author of that negative feedback talked to me in 
> > > private a week ago, and said he likes my proposal.  We have no 
> > > negative feedback anymore.  :)
> > > 
> > > > Since the proposal did not get much traction and I would had been 
> > > > unable to contribute to gcc myself, I just gave up on it. IIRC the 
> > > > deadline for new proposals closed soon after, anyway.
> > > 
> > > Ok.
> > > 
> > > > But I am glad that someone with proper experience took the initiative.
> > > 
> > > Fun fact: this is my second non-trivial patch to GCC.  I wouldn't 
> > > say I had the proper experience with GCC internals when I started 
> > > this patch set.  But I'm unemployed at the moment, which gives me 
> > > all the time I need for learning those.  :)
> > > 
> > > > I still think the proposal is relevant and has interesting use cases.
> > > > 
> > > > > I have only added lengthof for now, not _Lengthof, as suggested by Jens.
> > > > > Depending on feedback, I'll propose the uglified version.
> > > > 
> > > > Probably, all of us know why the uglified version is the usual 
> > > > approach preferred by the C standard: we do not know how many 
> > > > applications would break otherwise.
> > > 
> > > Yup.
> > > 
> > > > However, we see that this trend is now changing with C23, so 
> > > > probably it makes sense to define lengthof directly.
> > > 
> > > Yeah, since Jens is in WG14 and he suggested to follow this trend, 
> > > maybe we can.  If not, it's trivial to change the proposal to use 
> > > the uglified name plus a macro.
> > > 
> > > Checking <https://codesearch.debian.net>, I see that while several 
> > > projects have a lengthof() macro, all of them use it with semantics 
> > > compatible with this keyword, so it shouldn't break too much.  Maybe 
> > > those projects will start receiving diagnostics that they're 
> > > redefining a standard keyword, but that's not too bad.
> > 
> > For a WG14 paper you should add these findings to support that choice.
> > Another option would be for WG14 to standardize the then existing implementation with the double underscores.
> > 
> > > > As for the parentheses, I personally think lengthof should follow 
> > > > similar rules compared to sizeof.
> > > 
> > > I think most people agree with this.
> > 
> > I still don't, in particular not for standardisation.
> > 
> > We have to remember that there are many small C compilers out there. 
> > I would not want unnecessary burden on them. So my preferred choice would be a standardisation as a macro, similar
> > to offsetof.
> > gcc (and clang) could then just map that to their builtin, other compilers could use whatever they have at the
> > moment, even just the macros that you have in the paper as a starting point. 
> > 
> > The rest would be "quality of implementation"
> > 
> > What time horizon do you see to add the feature for array parameters?
> > 
> > Thanks
> > Jens
> > 
> > 
> > > > Best regards,
> > > 
> > > Have a lovely night!
> > > Alex
> > > 
> > 
> > 
> > --
> > Jens Gustedt - INRIA & ICube, Strasbourg, France
> 
> 
> -- 
> Jens Gustedt - INRIA & ICube, Strasbourg, France 

-- 
Univ.-Prof. Dr. rer. nat. Martin Uecker
Graz University of Technology
Institute of Biomedical Imaging



^ permalink raw reply	[flat|nested] 318+ messages in thread

* Re: v2.1 Draft for a lengthof paper
  2024-08-14 12:58                   ` Alejandro Colomar
  2024-08-14 13:21                     ` Ballman, Aaron
@ 2024-08-14 13:50                     ` Jens Gustedt
  2024-08-14 14:47                       ` Alejandro Colomar
  1 sibling, 1 reply; 318+ messages in thread
From: Jens Gustedt @ 2024-08-14 13:50 UTC (permalink / raw)
  To: Alejandro Colomar, Ballman, Aaron
  Cc: Xavier Del Campo Romero, Gcc Patches, Daniel Plakosh,
	Martin Uecker, Joseph Myers, Gabriel Ravier, Jakub Jelinek,
	Kees Cook, Qing Zhao, David Brown, Florian Weimer,
	Andreas Schwab, Timm Baeder, A. Jiang, Eugene Zelenko

Am 14. August 2024 14:58:16 MESZ schrieb Alejandro Colomar <alx@kernel.org>:
> Hi Aaron, Jens,
> 
> On Wed, Aug 14, 2024 at 02:17:52PM GMT, Jens Gustedt wrote:
> > Am 14. August 2024 13:31:19 MESZ schrieb "Ballman, Aaron" <aaron.ballman@intel.com>:
> > > Sorry for top-posting, my work account is stuck on Outlook. :-/
> > > 
> > > > For a WG14 paper you should add these findings to support that choice.
> > > > Another option would be for WG14 to standardize the then existing implementation with the double underscores.
> > > 
> > > +1, it's always good to explain prior art and existing uses as part
> > > of the paper. However, please also point out that C++ has a prior
> > > art as well which is slightly different and very much worth
> > > considering: they have one API for getting the array's rank,
> > > and another for getting a specific rank's extent. This is a general
> > > solution that doesn't require the programmer to have deep knowledge
> > > of C's declarator syntax and how it relates to multidimensional
> > > arrays.
> 
> I have added that to my draft.  I'll publish it soon as a reply to the
> GCC mailing list.  See below for details of what I have added for now.
> 
> > > 
> > > That said, I suspect WG14 would not be keen on standardizing
> > > `lengthof` without an ugly keyword given that there are plenty of other uses of it that would break: 
> > > 
> > > https://sourcegraph.com/github.com/illumos/illumos-gate/-/blob/usr/src/cmd/mailx/names.c?L53-55
> > > https://sourcegraph.com/github.com/Rockbox/rockbox/-/blob/tools/ipod_fw.c?L292-294
> > > https://sourcegraph.com/github.com/OpenSmalltalk/opensmalltalk-vm/-/blob/src/spur64.stack/validImage.c?L7014-7018
> > > (and many, many others)
> 
> What regex did you use for searching?
> 
> I was thinking of renaming the proposal to elementsof(), to avoid
> confusion between length of an array and length of a string.  Would you
> mind checking if elementsof() is ok?

No, not for me. I really want as to go consistently to talk about
array length for this. Consistent terminology is important.


> > > >> > As for the parentheses, I personally think lengthof should follow 
> > > >> > similar rules compared to sizeof.
> > > >> 
> > > >> I think most people agree with this.
> > > >
> > > > I still don't, in particular not for standardisation.
> > > > 
> > > > We have to remember that there are many small C compilers out there.
> > > 
> > > Those compilers already have to handle parsing this for sizeof, so
> > > that's not particularly compelling
> 
> Agree.  I suspect it will be simpler for existing compilers to follow
> sizeof than to have new syntax.  However, it's easy to keep it as a QoI
> detail, so I've temporarily changed the wording to require parentheses,
> and let implementations lift that restriction.

great ! that is a reasonable approach, I think.

> > > (even if we wanted to design C
> > > for the lowest common denominator of implementation effort, which
> > > I'm not convinced is a good approach these days).
> 
> Off-topic, but I wish that had been the approach when a few
> implementations (I suspect proprietary vendors; this was never
> disclosed) rejected redefining NULL as the right thing: (void *) 0.
> 
> I fixed one of the last free-software implementations of NULL that
> expanded to 0, and nullptr would probably never have been added if WG14
> had not accepted the pressure from such horrible implementations.
> 
> <https://github.com/cc65/cc65/issues/1823>
> 
> > > That said, if we went with a rank/extent design, I think we'd *have*
> > > to use parens because the extent interface would take two operands
> > > (the array and the rank you're interested in getting the extent of)
> > > and it would be inconsistent for the rank interface to then not
> > > require parens.
> 
>    Prior art
>      C
>             It is common in C programs to get the number of elements of
>             an array via the usual sizeof division and  wrap  it  in  a
>             macro.  Common names include:
> 
>             •  ARRAY_SIZE()
>             •  NELEM()
>             •  NELEMS()
>             •  NITEMS()
>             •  NELTS()
>             •  elementsof()
>             •  lengthof()
> 
>      C++
>             In  C++,  there  are several standard features to determine
>             the number of elements of an array:
> 
>             std::size()   (since C++17)
>             std::ssize()  (since C++20)
>                    The syntax of these is  identical  to  the  usual  C
>                    macros named above.
> 
>                    It’s  a  bit different, since it’s a general purpose
>                    sizing template, which works on non‐array types too,
>                    with different semantics.
> 
>                    But when applied to an array, it has the same seman‐
>                    tics as the macros above.
> 
>             std::extent  (since C++23)
>                    The syntax of this is quite different.   It  uses  a
>                    numeric index as a second parameter to determine the
>                    dimension  in which the number of elements should be
>                    counted.
> 
>                    C arrays are much simpler than C++’s many array‐like
>                    types, and I don’t see a reason why  we  would  need
>                    something  as  complex  as  std::extent  in C.  Cer‐
>                    tainly, existing projects have not developed such  a
>                    macro, even if it is technically possible:
> 
>                        #define DEREFERENCE(a, n) DEREFERENCE_ ## n (a, c)
>                        #define DEREFERENCE_9(a)  (*********(a))
>                        #define DEREFERENCE_8(a)  (********(a))
>                        #define DEREFERENCE_7(a)  (*******(a))
>                        #define DEREFERENCE_6(a)  (******(a))
>                        #define DEREFERENCE_5(a)  (*****(a))
>                        #define DEREFERENCE_4(a)  (****(a))
>                        #define DEREFERENCE_3(a)  (***(a))
>                        #define DEREFERENCE_2(a)  (**(a))
>                        #define DEREFERENCE_1(a)  (*(a))
>                        #define DEREFERENCE_0(a)  ((a))
>                        #define extent(a, n)      nitems(DEREFERENCE(a, n))
> 
>                    If any project needs that syntax, they can implement
>                    their  own  trivial  wrapper  macro, as demonstrated
>                    above.
> 
>             Existing prior art in C seems to favour a design that  fol‐
>             lows the syntax of other operators like sizeof.
> 
> > I think that this argument goes too short. E. g. implementation that
> > already have compound expressions (or lambdas ;-) may provide a
> > quality implementation using `static_assert` and `typeof` alone, and
> > don't have to touch their compiler at all.
> > 
> > We should not impose an implementation in the language where doing it
> > in a header can be completely sufficient.
> 
> I have concerns about a libc (or a predefined macro) implementation:
> the sizeof division causes double evaluation with any VLAs, while my
> implementation for GCC has less cases of evaluation, and when it needs
> to evaluate, it only does it once.  It would be hard to find a good
> wording that would allow an implementation to implement this as a macro.

No, we should not allow double evaluation.

putting this in a `({    })` and doing a `typedef typeof(X) _my_type;` with the macro parameter `X` at the beginning completely avoids double evaluation. So quality implantations are
possible, but perhaps differently and with other builtins than we are
imagining. Don't impose the view of one particular implementation onto others.

Somewhere was brought in an argument with `offsetof`. 
This is exactly what we need. Implementations being able to start
with a simple solution (as everybody did in the beginning of `offsetof` ), and improve that implementation at their pace when they are ready for it. 

> 
>    constexpr
>      The  usual  sizeof division evaluates the operand and results in a
>      run‐time value in cases where it wouldn’t be  necessary.   If  the
>      top‐level  array  number  of  elements is determined by an integer
>      constant expression, but an internal array is a VLA,  sizeof  must
>      evaluate:
> 
>             int  a[7][n];
>             int  (*p)[7][n];
> 
>             p = &a;
>             nitems(*p++);
> 
>      With  a  elementsof operator, this would result in an integer con‐
>      stant expression of value 7.
> 
>    Double evaluation
>      With the sizeof‐based implementation from above, the example  from
>      above causes double evaluation of *p++.
> 
> > Plus, implementing as a macro in a header (probably <stddef.h>) makes
> > also a feature test, for those applications that already have
> > something similar. 
> 
> This is interesting.  But I think an implementation could just
> 
> 	#define lengthof lengthof
> 
> to provide a feature-test macro.

Sure, but leave some slack to implementations to do this in a way that's best for them

> > this was basically what we did for `unreachable` and I think it worked
> > out fine.

I still think that the different options that we had there can be used to ask the right questions for WG14. 

Jens


-- 
Jens Gustedt - INRIA & ICube, Strasbourg, France

^ permalink raw reply	[flat|nested] 318+ messages in thread

* RE: v2.1 Draft for a lengthof paper
  2024-08-14 13:24                     ` Jens Gustedt
@ 2024-08-14 13:59                       ` Ballman, Aaron
  2024-08-14 14:31                         ` Alejandro Colomar
  0 siblings, 1 reply; 318+ messages in thread
From: Ballman, Aaron @ 2024-08-14 13:59 UTC (permalink / raw)
  To: Jens Gustedt, Alejandro Colomar, Xavier Del Campo Romero
  Cc: Gcc Patches, Daniel Plakosh, Martin Uecker, Joseph Myers,
	Gabriel Ravier, Jakub Jelinek, Kees Cook, Qing Zhao, David Brown,
	Florian Weimer, Andreas Schwab, Timm Baeder, A. Jiang,
	Eugene Zelenko

> I am currently on a summer bike trip, so not able to provide a full reference implantation. But could do so, once I am back.

No need (after thinking on this a bit more, I believe you're right that this can be done in a macro-only implementation; we might not go that route in Clang because of AST matching needs and whatnot, but that's not an issue), but thank you for the offer. Please enjoy your summer bike trip! 😊

> Why would you be looping? lengthof only addresses the outer dimension sizeof would need a loop, no ?

Due to poor reading comprehension, I missed in the paper that lengthof works on the outer dimension. 😉 I think having a way to get the flattened size of a multidimensional array is a useful feature.

~Aaron

-----Original Message-----
From: Jens Gustedt <jens.gustedt@inria.fr> 
Sent: Wednesday, August 14, 2024 9:25 AM
To: Ballman, Aaron <aaron.ballman@intel.com>; Alejandro Colomar <alx@kernel.org>; Xavier Del Campo Romero <xavi.dcr@tutanota.com>
Cc: Gcc Patches <gcc-patches@gcc.gnu.org>; Daniel Plakosh <dplakosh@cert.org>; Martin Uecker <uecker@tugraz.at>; 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>; David Brown <david.brown@hesbynett.no>; Florian Weimer <fweimer@redhat.com>; Andreas Schwab <schwab@linux-m68k.org>; Timm Baeder <tbaeder@redhat.com>; A. Jiang <de34@live.cn>; Eugene Zelenko <eugene.zelenko@gmail.com>
Subject: RE: v2.1 Draft for a lengthof paper

Am 14. August 2024 14:40:41 MESZ schrieb "Ballman, Aaron" <aaron.ballman@intel.com>:
> > I think that this argument goes too short. E. g. implementation that already have compound expressions (or lambdas ;-) may provide a > quality implementation using `static_assert` and `typeof` alone, and don't have to touch their compiler at all.
> >
> > We should not impose an implementation in the language where doing it in a header can be completely sufficient.
> 
> But can doing this in a header be completely sufficient in practice? 

Ithindso.

> e.g., the user who passes a pointer rather than an array is in for quite a surprise, or passing a struct, or passing a FAM, etc. If we want to put constraints on the interface, that may be more challenging to do from a header file than from the compiler. offsetof is a cautionary tale in that compilers that want a reasonable QoI basically all implement this as a builtin rather than the header-only version.

Yes,  with the tools that I listed and the ideas that are already in the paper you can basically do all that, including given valuable feedback in case of failure. 

I am currently on a summer bike trip, so not able to provide a full reference implantation. But could do so, once I am back. 


> > Plus, implementing as a macro in a header (probably <stddef.h>) makes also a feature test, for those applications that already have something similar. 
> > this was basically what we did for `unreachable` and I think it worked out fine.
> 
> True!
> 
> I'm still thinking on how important rank + extent is vs overall array 
> length. If C had constexpr functions, then I'd almost certainly want 
> array rank and extent to be the building blocks and then lengthof can 
> be a constexpr function looping over rank and summing extents. But we 
> don't have that yet, and "bird hand" vs "bird in bush"... :-D

Why would you be looping? lengthof only addresses the outer dimension sizeof would need a loop, no ?

Generally I would be opposed to imposing a complicated solution for a simple feature

Jens

> 
> ~Aaron
> 
> -----Original Message-----
> From: Jens Gustedt <jens.gustedt@inria.fr>
> Sent: Wednesday, August 14, 2024 8:18 AM
> To: Ballman, Aaron <aaron.ballman@intel.com>; Alejandro Colomar 
> <alx@kernel.org>; Xavier Del Campo Romero <xavi.dcr@tutanota.com>
> Cc: Gcc Patches <gcc-patches@gcc.gnu.org>; Daniel Plakosh 
> <dplakosh@cert.org>; Martin Uecker <uecker@tugraz.at>; 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>; David Brown <david.brown@hesbynett.no>; 
> Florian Weimer <fweimer@redhat.com>; Andreas Schwab 
> <schwab@linux-m68k.org>; Timm Baeder <tbaeder@redhat.com>; A. Jiang 
> <de34@live.cn>; Eugene Zelenko <eugene.zelenko@gmail.com>
> Subject: RE: v2.1 Draft for a lengthof paper
> 
> Hi Aaron,
> 
> Am 14. August 2024 13:31:19 MESZ schrieb "Ballman, Aaron" <aaron.ballman@intel.com>:
> > Sorry for top-posting, my work account is stuck on Outlook. :-/
> > 
> > > For a WG14 paper you should add these findings to support that choice.
> > > Another option would be for WG14 to standardize the then existing implementation with the double underscores.
> > 
> > +1, it's always good to explain prior art and existing uses as part of the paper. However, please also point out that C++ has a prior art as well which is slightly different and very much worth considering: they have one API for getting the array's rank, and another for getting a specific rank's extent. This is a general solution that doesn't require the programmer to have deep knowledge of C's declarator syntax and how it relates to multidimensional arrays.
> > 
> > That said, I suspect WG14 would not be keen on standardizing `lengthof` without an ugly keyword given that there are plenty of other uses of it that would break: 
> > 
> > https://sourcegraph.com/github.com/illumos/illumos-gate/-/blob/usr/s
> > rc
> > /cmd/mailx/names.c?L53-55
> > https://sourcegraph.com/github.com/Rockbox/rockbox/-/blob/tools/ipod
> > _f
> > w.c?L292-294
> > https://sourcegraph.com/github.com/OpenSmalltalk/opensmalltalk-vm/-/
> > bl
> > ob/src/spur64.stack/validImage.c?L7014-7018
> > (and many, many others)
> > 
> > >> > As for the parentheses, I personally think lengthof should 
> > >> > follow similar rules compared to sizeof.
> > >> 
> > >> I think most people agree with this.
> > >
> > > I still don't, in particular not for standardisation.
> > > 
> > > We have to remember that there are many small C compilers out there.
> > 
> > Those compilers already have to handle parsing this for sizeof, so that's not particularly compelling (even if we wanted to design C for the lowest common denominator of implementation effort, which I'm not convinced is a good approach these days). That said, if we went with a rank/extent design, I think we'd *have* to use parens because the extent interface would take two operands (the array and the rank you're interested in getting the extent of) and it would be inconsistent for the rank interface to then not require parens.
> 
> I think that this argument goes too short. E. g. implementation that already have compound expressions (or lambdas ;-) may provide a quality implementation using `static_assert` and `typeof` alone, and don't have to touch their compiler at all.
> 
> We should not impose an implementation in the language where doing it in a header can be completely sufficient.
> 
> Plus, implementing as a macro in a header (probably <stddef.h>) makes also a feature test, for those applications that already have something similar. 
> this was basically what we did for `unreachable` and I think it worked out fine.
> 
> Jens
> 
> > ~Aaron
> > 
> > -----Original Message-----
> > From: Jens Gustedt <jens.gustedt@inria.fr>
> > Sent: Wednesday, August 14, 2024 2:11 AM
> > To: Alejandro Colomar <alx@kernel.org>; Xavier Del Campo Romero 
> > <xavi.dcr@tutanota.com>
> > Cc: Gcc Patches <gcc-patches@gcc.gnu.org>; Daniel Plakosh 
> > <dplakosh@cert.org>; Martin Uecker <uecker@tugraz.at>; 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>; David Brown <david.brown@hesbynett.no>; 
> > Florian Weimer <fweimer@redhat.com>; Andreas Schwab 
> > <schwab@linux-m68k.org>; Timm Baeder <tbaeder@redhat.com>; A. Jiang 
> > <de34@live.cn>; Eugene Zelenko <eugene.zelenko@gmail.com>; Ballman, 
> > Aaron <aaron.ballman@intel.com>
> > Subject: Re: v2.1 Draft for a lengthof paper
> > 
> > Am 14. August 2024 01:27:33 MESZ schrieb Alejandro Colomar <alx@kernel.org>:
> > > Hi Xavier,
> > > 
> > > On Wed, Aug 14, 2024 at 12:38:53AM GMT, Xavier Del Campo Romero wrote:
> > > > I have been overseeing these last emails -
> > > 
> > > Ahhh, good to know; thanks!  :)
> > > 
> > > > thank you very much for your
> > > > efforts, Alex!
> > > 
> > > :-)
> > > 
> > > > I did not reply until now because I do not have prior experience 
> > > > with gcc internals, so my feedback would probably have not been 
> > > > that useful.
> > > 
> > > Ok.
> > > 
> > > > Those emails from 2020 were in fact discussing two completely 
> > > > different proposals at once:
> > > > 
> > > > 1. Add _Lengthof + #include <stdlengthof.h> 2. Allow static 
> > > > qualifier on compound literals
> > > 
> > > Yup.
> > > 
> > > > Whereas proposal #2 made it into C23 (kudos to Jens Gustedt!), 
> > > > and as you already know by now, proposal #1 received some 
> > > > negative feedback, suggesting _Typeof/typeof + some macro magic 
> > > > as a pragmatic workaround instead.
> > > 
> > > The original author of that negative feedback talked to me in 
> > > private a week ago, and said he likes my proposal.  We have no 
> > > negative feedback anymore.  :)
> > > 
> > > > Since the proposal did not get much traction and I would had 
> > > > been unable to contribute to gcc myself, I just gave up on it. 
> > > > IIRC the deadline for new proposals closed soon after, anyway.
> > > 
> > > Ok.
> > > 
> > > > But I am glad that someone with proper experience took the initiative.
> > > 
> > > Fun fact: this is my second non-trivial patch to GCC.  I wouldn't 
> > > say I had the proper experience with GCC internals when I started 
> > > this patch set.  But I'm unemployed at the moment, which gives me 
> > > all the time I need for learning those.  :)
> > > 
> > > > I still think the proposal is relevant and has interesting use cases.
> > > > 
> > > > > I have only added lengthof for now, not _Lengthof, as suggested by Jens.
> > > > > Depending on feedback, I'll propose the uglified version.
> > > > 
> > > > Probably, all of us know why the uglified version is the usual 
> > > > approach preferred by the C standard: we do not know how many 
> > > > applications would break otherwise.
> > > 
> > > Yup.
> > > 
> > > > However, we see that this trend is now changing with C23, so 
> > > > probably it makes sense to define lengthof directly.
> > > 
> > > Yeah, since Jens is in WG14 and he suggested to follow this trend, 
> > > maybe we can.  If not, it's trivial to change the proposal to use 
> > > the uglified name plus a macro.
> > > 
> > > Checking <https://codesearch.debian.net>, I see that while several 
> > > projects have a lengthof() macro, all of them use it with 
> > > semantics compatible with this keyword, so it shouldn't break too 
> > > much.  Maybe those projects will start receiving diagnostics that 
> > > they're redefining a standard keyword, but that's not too bad.
> > 
> > For a WG14 paper you should add these findings to support that choice.
> > Another option would be for WG14 to standardize the then existing implementation with the double underscores.
> > 
> > > > As for the parentheses, I personally think lengthof should 
> > > > follow similar rules compared to sizeof.
> > > 
> > > I think most people agree with this.
> > 
> > I still don't, in particular not for standardisation.
> > 
> > We have to remember that there are many small C compilers out there. 
> > I would not want unnecessary burden on them. So my preferred choice would be a standardisation as a macro, similar to offsetof.
> > gcc (and clang) could then just map that to their builtin, other compilers could use whatever they have at the moment, even just the macros that you have in the paper as a starting point. 
> > 
> > The rest would be "quality of implementation"
> > 
> > What time horizon do you see to add the feature for array parameters?
> > 
> > Thanks
> > Jens
> > 
> > 
> > > > Best regards,
> > > 
> > > Have a lovely night!
> > > Alex
> > > 
> > 
> > 
> > --
> > Jens Gustedt - INRIA & ICube, Strasbourg, France
> 
> 


--
Jens Gustedt - INRIA & ICube, Strasbourg, France 

^ permalink raw reply	[flat|nested] 318+ messages in thread

* Re: v2.1 Draft for a lengthof paper
  2024-08-14 13:21                     ` Ballman, Aaron
@ 2024-08-14 14:00                       ` Alejandro Colomar
  2024-08-14 14:07                         ` Ballman, Aaron
  0 siblings, 1 reply; 318+ messages in thread
From: Alejandro Colomar @ 2024-08-14 14:00 UTC (permalink / raw)
  To: Ballman, Aaron
  Cc: Jens Gustedt, Xavier Del Campo Romero, Gcc Patches,
	Daniel Plakosh, Martin Uecker, Joseph Myers, Gabriel Ravier,
	Jakub Jelinek, Kees Cook, Qing Zhao, David Brown, Florian Weimer,
	Andreas Schwab, Timm Baeder, A. Jiang, Eugene Zelenko

[-- Attachment #1: Type: text/plain, Size: 774 bytes --]

Hi Aaron,

On Wed, Aug 14, 2024 at 01:21:18PM GMT, Ballman, Aaron wrote:
> > What regex did you use for searching?
> 
> I went cheap and easy rather than trying to narrow down:
> https://sourcegraph.com/search?q=context:global+lang:C+lengthof&patternType=regexp&sm=0

Ahh, context:global seems to be what I wanted.  Where is that
documented?

> > I was thinking of renaming the proposal to elementsof(), to avoid confusion between length of an array and length of a string.  Would you mind checking if elementsof() is ok?
> 
> From what I was seeing, it looks to be used more uniformly as a
> function-like macro accepting a single argument.

Thanks!  I'll rename it to elementsof().

Cheers,
Alex

> ~Aaron

-- 
<https://www.alejandro-colomar.es/>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 318+ messages in thread

* RE: v2.1 Draft for a lengthof paper
  2024-08-14 14:00                       ` Alejandro Colomar
@ 2024-08-14 14:07                         ` Ballman, Aaron
  2024-08-14 15:01                           ` Alejandro Colomar
  0 siblings, 1 reply; 318+ messages in thread
From: Ballman, Aaron @ 2024-08-14 14:07 UTC (permalink / raw)
  To: Alejandro Colomar
  Cc: Jens Gustedt, Xavier Del Campo Romero, Gcc Patches,
	Daniel Plakosh, Martin Uecker, Joseph Myers, Gabriel Ravier,
	Jakub Jelinek, Kees Cook, Qing Zhao, David Brown, Florian Weimer,
	Andreas Schwab, Timm Baeder, A. Jiang, Eugene Zelenko

> Ahh, context:global seems to be what I wanted.  Where is that documented?

For me it is the default when I go to https://sourcegraph.com/search but there's documentation at https://sourcegraph.com/docs/code-search/working/search_contexts

> Thanks!  I'll rename it to elementsof().

Rather than renaming it, I'd say that the name chosen in the proposed text is a placeholder, and have a section in the prose that describes different naming choices, pros and cons, suggests a name from you as the author, but asks WG14 to pick the final name. I know Jens mentioned he doesn’t like the name `elementsof` and I suspect if we ask five more people we'll get about seven more opinions on what the name could/should be. 😝

~Aaron

-----Original Message-----
From: Alejandro Colomar <alx@kernel.org> 
Sent: Wednesday, August 14, 2024 10:00 AM
To: Ballman, Aaron <aaron.ballman@intel.com>
Cc: Jens Gustedt <jens.gustedt@inria.fr>; Xavier Del Campo Romero <xavi.dcr@tutanota.com>; Gcc Patches <gcc-patches@gcc.gnu.org>; Daniel Plakosh <dplakosh@cert.org>; Martin Uecker <uecker@tugraz.at>; 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>; David Brown <david.brown@hesbynett.no>; Florian Weimer <fweimer@redhat.com>; Andreas Schwab <schwab@linux-m68k.org>; Timm Baeder <tbaeder@redhat.com>; A. Jiang <de34@live.cn>; Eugene Zelenko <eugene.zelenko@gmail.com>
Subject: Re: v2.1 Draft for a lengthof paper

Hi Aaron,

On Wed, Aug 14, 2024 at 01:21:18PM GMT, Ballman, Aaron wrote:
> > What regex did you use for searching?
> 
> I went cheap and easy rather than trying to narrow down:
> https://sourcegraph.com/search?q=context:global+lang:C+lengthof&patter
> nType=regexp&sm=0

Ahh, context:global seems to be what I wanted.  Where is that documented?

> > I was thinking of renaming the proposal to elementsof(), to avoid confusion between length of an array and length of a string.  Would you mind checking if elementsof() is ok?
> 
> From what I was seeing, it looks to be used more uniformly as a 
> function-like macro accepting a single argument.

Thanks!  I'll rename it to elementsof().

Cheers,
Alex

> ~Aaron

--
<https://www.alejandro-colomar.es/>

^ permalink raw reply	[flat|nested] 318+ messages in thread

* Re: v2.1 Draft for a lengthof paper
  2024-08-14 13:50                     ` Martin Uecker
@ 2024-08-14 14:12                       ` Alejandro Colomar
  2024-08-14 14:37                         ` Martin Uecker
  0 siblings, 1 reply; 318+ messages in thread
From: Alejandro Colomar @ 2024-08-14 14:12 UTC (permalink / raw)
  To: Martin Uecker
  Cc: Ballman, Aaron, Jens Gustedt, Xavier Del Campo Romero,
	Gcc Patches, Daniel Plakosh, Joseph Myers, Gabriel Ravier,
	Jakub Jelinek, Kees Cook, Qing Zhao, David Brown, Florian Weimer,
	Andreas Schwab, Timm Baeder, A. Jiang, Eugene Zelenko

[-- Attachment #1: Type: text/plain, Size: 1746 bytes --]

Hi Martin,

On Wed, Aug 14, 2024 at 03:50:00PM GMT, Martin Uecker wrote:
> An operator that returns an array with all dimensions of a multi-dimensional
> array would make a a lot of sense to me. 
> 
> 
> double array[4][3][2];
> 
> // array_dims(array) = (constexpr size_t[3]){ 4, 3, 2 }

And what if array[4][n][2]?  No constexpr anymore, which is bad.

> 
> int dim1 = (array_dims(array))[0]
> int dim2 = (array_dims(array))[1]
> int dim3 = (array_dims(array))[2]
>  
> You can then implement lengthof in terms of this operator:
> 
> #define lengthof(x) (array_dims(array)[0])

Not really.  This implementation would result in less constant
expressions that my proposal.  That's detrimental for diagnostics and
usability.

And the fundamental operator would be very complex, to allow users
implementing simpler wrappers.  I think the fundamental operators should
be as simple as possible, in the spirit of C, and let users build on top
of those basic tools.

This reminds me of the 'static' specifier for array parameters, which is
conflated with two meanings: nonnull and length.  I'd rather have a way
to specify nullness, and another one to specify length, and let users
compose them.

At first glance I oppose this array_dims operator.

> and you can obtain the rank by applying lengthof to the array:
> 
> #define rank(x) lengthof(array_dims(x))

I'm curious to see what kind of code would be enabled by a rank()
operator in C that we can't write at the moment.

> If the array is constexpr for regular arrays and array
> indexing returns a constant again for constexpr arrays, this
> would all work out.
> 
> 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] 318+ messages in thread

* Re: v2.1 Draft for a lengthof paper
  2024-08-14 13:59                       ` Ballman, Aaron
@ 2024-08-14 14:31                         ` Alejandro Colomar
  0 siblings, 0 replies; 318+ messages in thread
From: Alejandro Colomar @ 2024-08-14 14:31 UTC (permalink / raw)
  To: Ballman, Aaron
  Cc: Jens Gustedt, Xavier Del Campo Romero, Gcc Patches,
	Daniel Plakosh, Martin Uecker, Joseph Myers, Gabriel Ravier,
	Jakub Jelinek, Kees Cook, Qing Zhao, David Brown, Florian Weimer,
	Andreas Schwab, Timm Baeder, A. Jiang, Eugene Zelenko

[-- Attachment #1: Type: text/plain, Size: 717 bytes --]

Hi Aaron,

On Wed, Aug 14, 2024 at 01:59:58PM GMT, Ballman, Aaron wrote:
> > Why would you be looping? lengthof only addresses the outer dimension sizeof would need a loop, no ?
> 
> Due to poor reading comprehension, I missed in the paper that lengthof
> works on the outer dimension. 😉 I think having a way to get the
> flattened size of a multidimensional array is a useful feature.

As long as you know the type of the inner-most element, you can do it.
This excludes auto, but I think you usually know this.

double x[4][5][6][7];
size_t n = sizeof(x) / sizeof(double);

This hard-codes 'double', but should be good enough usually.

Cheers,
Alex

-- 
<https://www.alejandro-colomar.es/>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 318+ messages in thread

* Re: v2.1 Draft for a lengthof paper
  2024-08-14 14:12                       ` Alejandro Colomar
@ 2024-08-14 14:37                         ` Martin Uecker
  0 siblings, 0 replies; 318+ messages in thread
From: Martin Uecker @ 2024-08-14 14:37 UTC (permalink / raw)
  To: Alejandro Colomar
  Cc: Ballman, Aaron, Jens Gustedt, Xavier Del Campo Romero,
	Gcc Patches, Daniel Plakosh, Joseph Myers, Gabriel Ravier,
	Jakub Jelinek, Kees Cook, Qing Zhao, David Brown, Florian Weimer,
	Andreas Schwab, Timm Baeder, A. Jiang, Eugene Zelenko

Am Mittwoch, dem 14.08.2024 um 16:12 +0200 schrieb Alejandro Colomar:
> Hi Martin,
> 
> On Wed, Aug 14, 2024 at 03:50:00PM GMT, Martin Uecker wrote:
> > An operator that returns an array with all dimensions of a multi-dimensional
> > array would make a a lot of sense to me. 
> > 
> > 
> > double array[4][3][2];
> > 
> > // array_dims(array) = (constexpr size_t[3]){ 4, 3, 2 }
> 
> And what if array[4][n][2]?  No constexpr anymore, which is bad.

> > 
> > int dim1 = (array_dims(array))[0]
> > int dim2 = (array_dims(array))[1]
> > int dim3 = (array_dims(array))[2]
> >  
> > You can then implement lengthof in terms of this operator:
> > 
> > #define lengthof(x) (array_dims(array)[0])
> 
> Not really.  This implementation would result in less constant
> expressions that my proposal.  That's detrimental for diagnostics and
> usability.

Yes, this would be a downside when implementing lengthof
in this way.

> 
> And the fundamental operator would be very complex, to allow users
> implementing simpler wrappers.  I think the fundamental operators should
> be as simple as possible, in the spirit of C, and let users build on top
> of those basic tools.
> 
> This reminds me of the 'static' specifier for array parameters, which is
> conflated with two meanings: nonnull and length.  I'd rather have a way
> to specify nullness, and another one to specify length, and let users
> compose them.
> 
> At first glance I oppose this array_dims operator.

Opinionated as usual ;-)

> > and you can obtain the rank by applying lengthof to the array:
> > 
> > #define rank(x) lengthof(array_dims(x))
> 
> I'm curious to see what kind of code would be enabled by a rank()
> operator in C that we can't write at the moment.

There seems to be no generic way to get all dimensions from
a multi-dimensional array of arbitrary rank.


Martin

> 
> > If the array is constexpr for regular arrays and array
> > indexing returns a constant again for constexpr arrays, this
> > would all work out.
> > 
> > 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] 318+ messages in thread

* Re: v2.1 Draft for a lengthof paper
  2024-08-14 13:50                     ` Jens Gustedt
@ 2024-08-14 14:47                       ` Alejandro Colomar
  2024-08-14 14:52                         ` Ballman, Aaron
  2024-08-14 15:44                         ` Jens Gustedt
  0 siblings, 2 replies; 318+ messages in thread
From: Alejandro Colomar @ 2024-08-14 14:47 UTC (permalink / raw)
  To: Jens Gustedt
  Cc: Ballman, Aaron, Xavier Del Campo Romero, Gcc Patches,
	Daniel Plakosh, Martin Uecker, Joseph Myers, Gabriel Ravier,
	Jakub Jelinek, Kees Cook, Qing Zhao, David Brown, Florian Weimer,
	Andreas Schwab, Timm Baeder, A. Jiang, Eugene Zelenko

[-- Attachment #1: Type: text/plain, Size: 3895 bytes --]

On Wed, Aug 14, 2024 at 03:50:21PM GMT, Jens Gustedt wrote:
> > > > 
> > > > That said, I suspect WG14 would not be keen on standardizing
> > > > `lengthof` without an ugly keyword given that there are plenty of other uses of it that would break: 
> > > > 
> > > > https://sourcegraph.com/github.com/illumos/illumos-gate/-/blob/usr/src/cmd/mailx/names.c?L53-55
> > > > https://sourcegraph.com/github.com/Rockbox/rockbox/-/blob/tools/ipod_fw.c?L292-294
> > > > https://sourcegraph.com/github.com/OpenSmalltalk/opensmalltalk-vm/-/blob/src/spur64.stack/validImage.c?L7014-7018
> > > > (and many, many others)
> > 
> > What regex did you use for searching?
> > 
> > I was thinking of renaming the proposal to elementsof(), to avoid
> > confusion between length of an array and length of a string.  Would you
> > mind checking if elementsof() is ok?
> 
> No, not for me. I really want as to go consistently to talk about
> array length for this. Consistent terminology is important.

I understand your desire for consistency.  I think your paper is a net
improvement over the status quo (which is a mix of length, size, and
number of elements).  After your proposal, there will be only length and
number of elements.  That's great.

However, strlen(3) came first, and we must respect it.

Since you haven't proposed eliminating "number of elements" from the
standard, and it would still be used alongside length, I think
elementsof() would be consistent with your view (consistent with "number
of elements").

Alternatively, you could use a new term, for example extent, for
referring to the number of elements of an array.  That would be more
respectful to strlen(3), keeping a strong distinction between string
length and array ******.

Or how about always referring to it as "number of elements"?  It's
longer to type, but would be the most consistent approach.

Also, elementsof() is free to use, while lengthof() has a several
existing incompatible cases (as Aaron has shown), so we can't use that
name so freely.

> > I have concerns about a libc (or a predefined macro) implementation:
> > the sizeof division causes double evaluation with any VLAs, while my
> > implementation for GCC has less cases of evaluation, and when it needs
> > to evaluate, it only does it once.  It would be hard to find a good
> > wording that would allow an implementation to implement this as a macro.
> 
> No, we should not allow double evaluation.
> 
> putting this in a `({    })`

I would love to see a proposal for adding this GNU extension to ISO C.
Did nobody do it yet?  I could try to, if I find some time.  (But I'll
take a longish time for that; if anyone else does it, it would be
great.)

> and doing a `typedef typeof(X) _my_type;` with the macro parameter `X` at the beginning completely avoids double evaluation. So quality implantations are
> possible, but perhaps differently and with other builtins than we are
> imagining. Don't impose the view of one particular implementation onto others.

Ahhh, good.  I haven't thought of that possibility.  Sure, that makes
sense now.  It gives more strength to your proposal of allowing libc
implementations, and thus require parens in the standard.

> Somewhere was brought in an argument with `offsetof`. 
> This is exactly what we need. Implementations being able to start
> with a simple solution (as everybody did in the beginning of
> `offsetof`), and improve that implementation at their pace when they
> are ready for it. 

Agree.

> > > this was basically what we did for `unreachable` and I think it worked
> > > out fine.
> 
> I still think that the different options that we had there can be used
> to ask the right questions for WG14. 

I'm looking at it.  I've already taken some parts of it.  :)

Cheers,
Alex

-- 
<https://www.alejandro-colomar.es/>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 318+ messages in thread

* RE: v2.1 Draft for a lengthof paper
  2024-08-14 14:47                       ` Alejandro Colomar
@ 2024-08-14 14:52                         ` Ballman, Aaron
  2024-08-14 15:01                           ` Martin Uecker
  2024-08-14 15:44                         ` Jens Gustedt
  1 sibling, 1 reply; 318+ messages in thread
From: Ballman, Aaron @ 2024-08-14 14:52 UTC (permalink / raw)
  To: Alejandro Colomar, Jens Gustedt
  Cc: Xavier Del Campo Romero, Gcc Patches, Daniel Plakosh,
	Martin Uecker, Joseph Myers, Gabriel Ravier, Jakub Jelinek,
	Kees Cook, Qing Zhao, David Brown, Florian Weimer,
	Andreas Schwab, Timm Baeder, A. Jiang, Eugene Zelenko

> I would love to see a proposal for adding this GNU extension to ISO C.
> Did nobody do it yet?  I could try to, if I find some time.  (But I'll take a longish time for that; if anyone else does it, it would be
great.)

It's been discussed but hasn't moved forward because there are design issues with it (the odd way in which it produces a resulting value, sometimes surprising behavior with how it interacts with flow control, the fact that it can't be used in all contexts, etc). The committee was leaning more towards lambdas despite those being a bit orthogonal.

~Aaron

-----Original Message-----
From: Alejandro Colomar <alx@kernel.org> 
Sent: Wednesday, August 14, 2024 10:48 AM
To: Jens Gustedt <jens.gustedt@inria.fr>
Cc: Ballman, Aaron <aaron.ballman@intel.com>; Xavier Del Campo Romero <xavi.dcr@tutanota.com>; Gcc Patches <gcc-patches@gcc.gnu.org>; Daniel Plakosh <dplakosh@cert.org>; Martin Uecker <uecker@tugraz.at>; 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>; David Brown <david.brown@hesbynett.no>; Florian Weimer <fweimer@redhat.com>; Andreas Schwab <schwab@linux-m68k.org>; Timm Baeder <tbaeder@redhat.com>; A. Jiang <de34@live.cn>; Eugene Zelenko <eugene.zelenko@gmail.com>
Subject: Re: v2.1 Draft for a lengthof paper

On Wed, Aug 14, 2024 at 03:50:21PM GMT, Jens Gustedt wrote:
> > > > 
> > > > That said, I suspect WG14 would not be keen on standardizing 
> > > > `lengthof` without an ugly keyword given that there are plenty of other uses of it that would break:
> > > > 
> > > > https://sourcegraph.com/github.com/illumos/illumos-gate/-/blob/u
> > > > sr/src/cmd/mailx/names.c?L53-55
> > > > https://sourcegraph.com/github.com/Rockbox/rockbox/-/blob/tools/
> > > > ipod_fw.c?L292-294
> > > > https://sourcegraph.com/github.com/OpenSmalltalk/opensmalltalk-v
> > > > m/-/blob/src/spur64.stack/validImage.c?L7014-7018
> > > > (and many, many others)
> > 
> > What regex did you use for searching?
> > 
> > I was thinking of renaming the proposal to elementsof(), to avoid 
> > confusion between length of an array and length of a string.  Would 
> > you mind checking if elementsof() is ok?
> 
> No, not for me. I really want as to go consistently to talk about 
> array length for this. Consistent terminology is important.

I understand your desire for consistency.  I think your paper is a net improvement over the status quo (which is a mix of length, size, and number of elements).  After your proposal, there will be only length and number of elements.  That's great.

However, strlen(3) came first, and we must respect it.

Since you haven't proposed eliminating "number of elements" from the standard, and it would still be used alongside length, I think
elementsof() would be consistent with your view (consistent with "number of elements").

Alternatively, you could use a new term, for example extent, for referring to the number of elements of an array.  That would be more respectful to strlen(3), keeping a strong distinction between string length and array ******.

Or how about always referring to it as "number of elements"?  It's longer to type, but would be the most consistent approach.

Also, elementsof() is free to use, while lengthof() has a several existing incompatible cases (as Aaron has shown), so we can't use that name so freely.

> > I have concerns about a libc (or a predefined macro) implementation:
> > the sizeof division causes double evaluation with any VLAs, while my 
> > implementation for GCC has less cases of evaluation, and when it 
> > needs to evaluate, it only does it once.  It would be hard to find a 
> > good wording that would allow an implementation to implement this as a macro.
> 
> No, we should not allow double evaluation.
> 
> putting this in a `({    })`

I would love to see a proposal for adding this GNU extension to ISO C.
Did nobody do it yet?  I could try to, if I find some time.  (But I'll take a longish time for that; if anyone else does it, it would be
great.)

> and doing a `typedef typeof(X) _my_type;` with the macro parameter `X` 
> at the beginning completely avoids double evaluation. So quality 
> implantations are possible, but perhaps differently and with other builtins than we are imagining. Don't impose the view of one particular implementation onto others.

Ahhh, good.  I haven't thought of that possibility.  Sure, that makes sense now.  It gives more strength to your proposal of allowing libc implementations, and thus require parens in the standard.

> Somewhere was brought in an argument with `offsetof`. 
> This is exactly what we need. Implementations being able to start with 
> a simple solution (as everybody did in the beginning of `offsetof`), 
> and improve that implementation at their pace when they are ready for 
> it.

Agree.

> > > this was basically what we did for `unreachable` and I think it 
> > > worked out fine.
> 
> I still think that the different options that we had there can be used 
> to ask the right questions for WG14.

I'm looking at it.  I've already taken some parts of it.  :)

Cheers,
Alex

--
<https://www.alejandro-colomar.es/>

^ permalink raw reply	[flat|nested] 318+ messages in thread

* Re: v2.1 Draft for a lengthof paper
  2024-08-14 14:07                         ` Ballman, Aaron
@ 2024-08-14 15:01                           ` Alejandro Colomar
  0 siblings, 0 replies; 318+ messages in thread
From: Alejandro Colomar @ 2024-08-14 15:01 UTC (permalink / raw)
  To: Ballman, Aaron
  Cc: Jens Gustedt, Xavier Del Campo Romero, Gcc Patches,
	Daniel Plakosh, Martin Uecker, Joseph Myers, Gabriel Ravier,
	Jakub Jelinek, Kees Cook, Qing Zhao, David Brown, Florian Weimer,
	Andreas Schwab, Timm Baeder, A. Jiang, Eugene Zelenko

[-- Attachment #1: Type: text/plain, Size: 1410 bytes --]

Hi Aaron,

On Wed, Aug 14, 2024 at 02:07:16PM GMT, Ballman, Aaron wrote:
> > Ahh, context:global seems to be what I wanted.  Where is that documented?
> 
> For me it is the default when I go to https://sourcegraph.com/search but there's documentation at https://sourcegraph.com/docs/code-search/working/search_contexts

Ahh, no, it was a red herring.  I though that was restricting the search
to global definitions.  There's no way to restrict to definitions,
right?  I'd like a way to discard uses, since that doesn't give much
info.

But for lengthof() it seems to quickly find incomatible cases, so we
were lucky that we don't need to restrict it.

> 
> > Thanks!  I'll rename it to elementsof().
> 
> Rather than renaming it, I'd say that the name chosen in the proposed
> text is a placeholder, and have a section in the prose that describes
> different naming choices, pros and cons, suggests a name from you as
> the author, but asks WG14 to pick the final name.
> I know Jens mentioned he doesn’t like the name `elementsof` and I
> suspect if we ask five more people we'll get about seven more opinions
> on what the name could/should be. 😝

Yup, but I want to have a placeholder that would be a name that I would
like, and a defendible one.  :-)

I'll add questions at the bottom, proposing alternatives.

Cheers,
Alex

-- 
<https://www.alejandro-colomar.es/>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 318+ messages in thread

* Re: v2.1 Draft for a lengthof paper
  2024-08-14 14:52                         ` Ballman, Aaron
@ 2024-08-14 15:01                           ` Martin Uecker
  0 siblings, 0 replies; 318+ messages in thread
From: Martin Uecker @ 2024-08-14 15:01 UTC (permalink / raw)
  To: Ballman, Aaron, Alejandro Colomar, Jens Gustedt
  Cc: Xavier Del Campo Romero, Gcc Patches, Daniel Plakosh,
	Joseph Myers, Gabriel Ravier, Jakub Jelinek, Kees Cook,
	Qing Zhao, David Brown, Florian Weimer, Andreas Schwab,
	Timm Baeder, A. Jiang, Eugene Zelenko

Am Mittwoch, dem 14.08.2024 um 14:52 +0000 schrieb Ballman, Aaron:
> > I would love to see a proposal for adding this GNU extension to ISO C.
> > Did nobody do it yet?  I could try to, if I find some time.  (But I'll take a longish time for that; if anyone else
> > does it, it would be
> great.)
> 
> It's been discussed but hasn't moved forward because there are design issues with it (the odd way in which it produces
> a resulting value, sometimes surprising behavior with how it interacts with flow control, the fact that it can't be
> used in all contexts, etc). The committee was leaning more towards lambdas despite those being a bit orthogonal.

I do not think this is a fair characterization. We did not see any proposal
for ({ }) so it is not clear where the committee is leaning more towards.

Lambdas ultimately failed because they were too complex for not 
having any implementation and user experience in C.

I agree though that lambdas could be nicer, but I still have issues
with the last type-generic version and I do not have similar objections
against ({ }).

Martin

^ permalink raw reply	[flat|nested] 318+ messages in thread

* Re: v2.1 Draft for a lengthof paper
  2024-08-14 14:47                       ` Alejandro Colomar
  2024-08-14 14:52                         ` Ballman, Aaron
@ 2024-08-14 15:44                         ` Jens Gustedt
  2024-09-01  9:10                           ` VLA is a misnomer (rebuttal to n3187) Alejandro Colomar
  1 sibling, 1 reply; 318+ messages in thread
From: Jens Gustedt @ 2024-08-14 15:44 UTC (permalink / raw)
  To: Alejandro Colomar
  Cc: Ballman, Aaron, Xavier Del Campo Romero, Gcc Patches,
	Daniel Plakosh, Martin Uecker, Joseph Myers, Gabriel Ravier,
	Jakub Jelinek, Kees Cook, Qing Zhao, David Brown, Florian Weimer,
	Andreas Schwab, Timm Baeder, A. Jiang, Eugene Zelenko

Am 14. August 2024 16:47:32 MESZ schrieb Alejandro Colomar <alx@kernel.org>:
> On Wed, Aug 14, 2024 at 03:50:21PM GMT, Jens Gustedt wrote:
> > > > > 
> > > > > That said, I suspect WG14 would not be keen on standardizing
> > > > > `lengthof` without an ugly keyword given that there are plenty of other uses of it that would break: 
> > > > > 
> > > > > https://sourcegraph.com/github.com/illumos/illumos-gate/-/blob/usr/src/cmd/mailx/names.c?L53-55
> > > > > https://sourcegraph.com/github.com/Rockbox/rockbox/-/blob/tools/ipod_fw.c?L292-294
> > > > > https://sourcegraph.com/github.com/OpenSmalltalk/opensmalltalk-vm/-/blob/src/spur64.stack/validImage.c?L7014-7018
> > > > > (and many, many others)
> > > 
> > > What regex did you use for searching?
> > > 
> > > I was thinking of renaming the proposal to elementsof(), to avoid
> > > confusion between length of an array and length of a string.  Would you
> > > mind checking if elementsof() is ok?
> > 
> > No, not for me. I really want as to go consistently to talk about
> > array length for this. Consistent terminology is important.
> 
> I understand your desire for consistency.  I think your paper is a net
> improvement over the status quo (which is a mix of length, size, and
> number of elements).  After your proposal, there will be only length and
> number of elements.  That's great.
> 
> However, strlen(3) came first, and we must respect it.

Sure,  string length, a dynamic feature, and array length are two features.

But we also have VLA and not VNEA in the standard, So we should respect this ;-)

> Since you haven't proposed eliminating "number of elements" from the
> standard, and it would still be used alongside length, I think
> elementsof() would be consistent with your view (consistent with "number
> of elements").

didn't we ? Then this is actually a good idea to do so, thanks for the idea !

"elements of" is a stretch, linguistically, because you don't mean  the
elements themselves, you are referring to their number. "elementsof" for
me would refer to a list of these elements.

> Alternatively, you could use a new term, for example extent, for
> referring to the number of elements of an array.  That would be more
> respectful to strlen(3), keeping a strong distinction between string
> length and array ******.

Only that this separation doesn't exist, even now, as said, it is called
"variable length array"

> Or how about always referring to it as "number of elements"?  It's
> longer to type, but would be the most consistent approach.
> 
> Also, elementsof() is free to use, while lengthof() has a several
> existing incompatible cases (as Aaron has shown), so we can't use that
> name so freely.
> 
> > > I have concerns about a libc (or a predefined macro) implementation:
> > > the sizeof division causes double evaluation with any VLAs, while my
> > > implementation for GCC has less cases of evaluation, and when it needs
> > > to evaluate, it only does it once.  It would be hard to find a good
> > > wording that would allow an implementation to implement this as a macro.
> > 
> > No, we should not allow double evaluation.
> >  
> > putting this in a `({    })`
> 
> I would love to see a proposal for adding this GNU extension to ISO C.
> Did nobody do it yet?  I could try to, if I find some time.  (But I'll
> take a longish time for that; if anyone else does it, it would be
> great.)
> 
> > and doing a `typedef typeof(X) _my_type;` with the macro parameter `X` at the beginning completely avoids double evaluation. So quality implantations are
> > possible, but perhaps differently and with other builtins than we are
> > imagining. Don't impose the view of one particular implementation onto others.
> 
> Ahhh, good.  I haven't thought of that possibility.  Sure, that makes
> sense now.  It gives more strength to your proposal of allowing libc
> implementations, and thus require parens in the standard.
> 
> > Somewhere was brought in an argument with `offsetof`. 
> > This is exactly what we need. Implementations being able to start
> > with a simple solution (as everybody did in the beginning of
> > `offsetof`), and improve that implementation at their pace when they
> > are ready for it. 
> 
> Agree.
> 
> > > > this was basically what we did for `unreachable` and I think it worked
> > > > out fine.
> > 
> > I still think that the different options that we had there can be used
> > to ask the right questions for WG14. 
> 
> I'm looking at it.  I've already taken some parts of it.  :)
> 
> Cheers,
> Alex
> 


-- 
Jens Gustedt - INRIA & ICube, Strasbourg, France

^ permalink raw reply	[flat|nested] 318+ messages in thread

* [PATCH v9 0/3] c: Add __elementsof__ operator
  2024-07-28 14:15 ` [RFC v1 0/2] c: Add _Lengthof operator Alejandro Colomar
                     ` (13 preceding siblings ...)
  2024-08-11 23:46   ` [PATCH v8 0/3] " Alejandro Colomar
@ 2024-08-14 20:58   ` Alejandro Colomar
  2024-08-14 20:58     ` [PATCH v9 1/3] gcc/: Rename array_type_nelts() => array_type_nelts_minus_one() Alejandro Colomar
                       ` (2 more replies)
  2024-08-19 10:58   ` [PATCH v10 0/3] c: Add __nelementsof__ operator Alejandro Colomar
                     ` (13 subsequent siblings)
  28 siblings, 3 replies; 318+ messages in thread
From: Alejandro Colomar @ 2024-08-14 20:58 UTC (permalink / raw)
  To: gcc-patches
  Cc: Alejandro Colomar, Xavier Del Campo Romero, Martin Uecker,
	Joseph Myers, Gabriel Ravier, Jakub Jelinek, Kees Cook,
	Qing Zhao, Jens Gustedt, David Brown, Florian Weimer,
	Andreas Schwab, Timm Baeder, Daniel Plakosh, A. Jiang,
	Eugene Zelenko, Aaron Ballman, Paul Koning

[-- Attachment #1: Type: text/plain, Size: 39283 bytes --]

Hi!

v9:

-  Rename s/lengthof/elementsof/

   There are existing lengthof() functions in the wild, which are
   incompatible with (completely unrelated to) this operator.

   In the case of elementsof(), we only found macros that expand to the
   usual sizeof division (plus safety checks in some cases), so this one
   would be compatible.  [Aaron]

   ISO C uses "number of elements" and "length" indistinctly for
   referring to the number of elements of an array, so this name should
   also be obvious.

   Also, lengthof() might induce to ambiguity in contexts where string
   lengths are used, due to the overload of the term length.
   elementsof() is free of that ambiguity.

   I guess elementsof() has slightly more chances of being later
   accepted into ISO C than lengthof(), due to backwards compatibility
   with those existing functions named lengthof().

-  Cc: += Daniel, A., Eugene, Aaron, Paul

I'll send as a reply the updated draft for a WG14 C2y proposal
incorporating these changes.

As usual, below is a range diff against v8.

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 __elementsof__ 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                           |  31 +++--
 gcc/c/c-fold.cc                           |   7 +-
 gcc/c/c-parser.cc                         |  62 +++++++--
 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                       |  30 +++++
 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/elementsof-compile.c | 115 +++++++++++++++++
 gcc/testsuite/gcc.dg/elementsof-vla.c     |  46 +++++++
 gcc/testsuite/gcc.dg/elementsof.c         | 150 ++++++++++++++++++++++
 gcc/tree.cc                               |  17 ++-
 gcc/tree.h                                |   3 +-
 28 files changed, 599 insertions(+), 79 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/elementsof-compile.c
 create mode 100644 gcc/testsuite/gcc.dg/elementsof-vla.c
 create mode 100644 gcc/testsuite/gcc.dg/elementsof.c

Range-diff against v8:
1:  a6aa38c9013 = 1:  a6aa38c9013 gcc/: Rename array_type_nelts() => array_type_nelts_minus_one()
2:  43300a17e4a ! 2:  4ce16ee4dfe 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 __elementsof__.  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.
    +    for __elementsof__, which will be added in the following commit.
     
         gcc/ChangeLog:
     
3:  e6af87d54af ! 3:  caae5dbecb3 c: Add __lengthof__ operator
    @@ Metadata
     Author: Alejandro Colomar <alx@kernel.org>
     
      ## Commit message ##
    -    c: Add __lengthof__ operator
    +    c: Add __elementsof__ operator
     
         This operator is similar to sizeof but can only be applied to an array,
    -    and returns its length (number of elements).
    +    and returns its 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,
    +       and somehow magically return the number of elements of the array,
            regardless of it being really a pointer.
     
         -  Fix support for [0].
    @@ Commit message
         Cc: Florian Weimer <fweimer@redhat.com>
         Cc: Andreas Schwab <schwab@linux-m68k.org>
         Cc: Timm Baeder <tbaeder@redhat.com>
    +    Cc: Daniel Plakosh <dplakosh@cert.org>
    +    Cc: "A. Jiang" <de34@live.cn>
    +    Cc: Eugene Zelenko <eugene.zelenko@gmail.com>
    +    Cc: Aaron Ballman <aaron.ballman@intel.com>
    +    Cc: Paul Koning <paulkoning@comcast.net>
     
         gcc/ChangeLog:
     
    -            * doc/extend.texi: Document __lengthof__ operator.
    -            * target.h (enum type_context_kind): Add __lengthof__ operator.
    +            * doc/extend.texi: Document __elementsof__ operator.
    +            * target.h (enum type_context_kind): Add __elementsof__ operator.
     
         gcc/c-family/ChangeLog:
     
                 * c-common.h:
                 * c-common.def:
    -            * c-common.cc (c_lengthof_type): Add __lengthof__ operator.
    +            * c-common.cc (c_elementsof_type): Add __elementsof__ operator.
     
         gcc/c/ChangeLog:
     
                 * c-tree.h
    -            (c_expr_lengthof_expr, c_expr_lengthof_type):
    +            (c_expr_elementsof_expr, c_expr_elementsof_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_elementsof_expression):
    +            (c_parser_sizeof_or_elementsof_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.
    +            (c_expr_elementsof_expr, c_expr_elementsof_type):
    +            Add __elementsof__operator.
     
         gcc/cp/ChangeLog:
     
    -            * operators.def: Add __lengthof__ operator.
    +            * operators.def: Add __elementsof__ operator.
     
         gcc/testsuite/ChangeLog:
     
    -            * gcc.dg/lengthof-compile.c:
    -            * gcc.dg/lengthof-vla.c:
    -            * gcc.dg/lengthof.c: Add tests for __lengthof__ operator.
    +            * gcc.dg/elementsof-compile.c:
    +            * gcc.dg/elementsof-vla.c:
    +            * gcc.dg/elementsof.c: Add tests for __elementsof__ 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/
    @@ gcc/c-family/c-common.cc: const struct c_common_resword c_common_reswords[] =
        { "__inline",		RID_INLINE,	0 },
        { "__inline__",	RID_INLINE,	0 },
        { "__label__",	RID_LABEL,	0 },
    -+  { "__lengthof__",	RID_LENGTHOF, 0 },
    ++  { "__elementsof__",	RID_ELEMENTSOF, 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,
    -+   that is, the number of elements in the array.  */
    ++/* Implement the lementsof keyword:
    ++   Return the number of elements of an array.  */
     +
     +tree
    -+c_lengthof_type (location_t loc, tree type)
    ++c_elementsof_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);
    ++      error_at (loc, "invalid application of %<elementsof%> to type %qT", type);
     +      return error_mark_node;
     +    }
     +  if (!COMPLETE_TYPE_P (type))
     +    {
     +      error_at (loc,
    -+		"invalid application of %<lengthof%> to incomplete type %qT",
    ++		"invalid application of %<elementsof%> to incomplete 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 'lengthof' expression.  */
    -+DEFTREECODE (LENGTHOF_EXPR, "lengthof_expr", tcc_expression, 1)
    ++/* Represents a 'elementsof' expression.  */
    ++DEFTREECODE (ELEMENTSOF_EXPR, "elementsof_expr", tcc_expression, 1)
     +
      /* Represents a 'sizeof' expression during C++ template expansion,
         or for the purpose of -Wsizeof-pointer-memaccess warning.  */
    @@ gcc/c-family/c-common.h: enum rid
      
        /* C extensions */
        RID_ASM,       RID_TYPEOF,   RID_TYPEOF_UNQUAL, RID_ALIGNOF,  RID_ATTRIBUTE,
    -+  RID_LENGTHOF,
    ++  RID_ELEMENTSOF,
        RID_VA_ARG,
        RID_EXTENSION, RID_IMAGPART, RID_REALPART, RID_LABEL,    RID_CHOOSE_EXPR,
        RID_TYPES_COMPATIBLE_P,      RID_BUILTIN_COMPLEX,	   RID_BUILTIN_SHUFFLE,
    @@ gcc/c-family/c-common.h: extern tree c_common_truthvalue_conversion (location_t,
      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);
    ++extern tree c_elementsof_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);
    @@ gcc/c/c-decl.cc: start_struct (location_t loc, enum tree_code code, tree name,
           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))
    ++  if (warn_cxx_compat
    ++      && (in_sizeof || in_typeof || in_alignof || in_elementsof))
          warning_at (loc, OPT_Wc___compat,
      		"defining type in %qs expression is invalid in C++",
      		(in_sizeof
    @@ gcc/c/c-decl.cc: start_struct (location_t loc, enum tree_code code, tree name,
     +		    ? "typeof"
     +		    : (in_alignof
     +		       ? "alignof"
    -+		       : "lengthof"))));
    ++		       : "elementsof"))));
      
        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 att
            if (warn_cxx_compat
      	  && struct_parse_info != NULL
     -	  && !in_sizeof && !in_typeof && !in_alignof)
    -+	  && !in_sizeof && !in_typeof && !in_alignof && !in_lengthof)
    ++	  && !in_sizeof && !in_typeof && !in_alignof && !in_elementsof)
      	struct_parse_info->struct_types.safe_push (t);
           }
      
    @@ gcc/c/c-decl.cc: start_enum (location_t loc, struct c_enum_contents *the_enum, t
           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))
    ++  if (warn_cxx_compat && (in_sizeof || in_typeof || in_alignof || in_elementsof))
          warning_at (loc, OPT_Wc___compat,
      		"defining type in %qs expression is invalid in C++",
      		(in_sizeof
    @@ gcc/c/c-decl.cc: start_enum (location_t loc, struct c_enum_contents *the_enum, t
     +		    ? "typeof"
     +		    : (in_alignof
     +		       ? "alignof"
    -+		       : "lengthof"))));
    ++		       : "elementsof"))));
      
        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)
        if (warn_cxx_compat
            && struct_parse_info != NULL
     -      && !in_sizeof && !in_typeof && !in_alignof)
    -+      && !in_sizeof && !in_typeof && !in_alignof && !in_lengthof)
    ++      && !in_sizeof && !in_typeof && !in_alignof && !in_elementsof)
          struct_parse_info->struct_types.safe_push (enumtype);
      
        /* Check for consistency with previous definition */
    @@ gcc/c/c-parser.cc: along with GCC; see the file COPYING3.  If not see
     +\f
     +#define c_parser_sizeof_expression(parser)                                    \
     +(                                                                             \
    -+  c_parser_sizeof_or_lengthof_expression (parser, RID_SIZEOF)                 \
    ++  c_parser_sizeof_or_elementsof_expression (parser, RID_SIZEOF)               \
     +)
      
    -+#define c_parser_lengthof_expression(parser)                                  \
    ++#define c_parser_elementsof_expression(parser)                                \
     +(                                                                             \
    -+  c_parser_sizeof_or_lengthof_expression (parser, RID_LENGTHOF)               \
    ++  c_parser_sizeof_or_elementsof_expression (parser, RID_ELEMENTSOF)           \
     +)
     +\f
      /* We need to walk over decls with incomplete struct/union/enum types
    @@ gcc/c/c-parser.cc: static struct c_expr c_parser_binary_expression (c_parser *,
      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_sizeof_or_elementsof_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 *,
    @@ gcc/c/c-parser.cc: 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_ELEMENTSOF:
    ++	  return c_parser_elementsof_expression (parser);
      	case RID_SIZEOF:
      	  return c_parser_sizeof_expression (parser);
      	case RID_ALIGNOF:
    @@ gcc/c/c-parser.cc: c_parser_unary_expression (c_parser *parser)
      
      static struct c_expr
     -c_parser_sizeof_expression (c_parser *parser)
    -+c_parser_sizeof_or_lengthof_expression (c_parser *parser, enum rid rid)
    ++c_parser_sizeof_or_elementsof_expression (c_parser *parser, enum rid rid)
      {
    -+  const char *op_name = (rid == RID_LENGTHOF) ? "lengthof" : "sizeof";
    ++  const char *op_name = (rid == RID_ELEMENTSOF) ? "elementsof" : "sizeof";
        struct c_expr expr;
        struct c_expr result;
        location_t expr_loc;
    @@ 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++;
    ++  if (rid == RID_ELEMENTSOF)
    ++    in_elementsof++;
     +  else
     +    in_sizeof++;
        if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)
    @@ 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--;
    ++	  if (rid == RID_ELEMENTSOF)
    ++	    in_elementsof--;
     +	  else
     +	    in_sizeof--;
      	  ret.set_error ();
    @@ gcc/c/c-parser.cc: c_parser_sizeof_expression (c_parser *parser)
            c_inhibit_evaluation_warnings--;
     -      in_sizeof--;
     -      result = c_expr_sizeof_type (expr_loc, type_name);
    -+      if (rid == RID_LENGTHOF)
    ++      if (rid == RID_ELEMENTSOF)
     +	{
    -+	  in_lengthof--;
    -+	  result = c_expr_lengthof_type (expr_loc, type_name);
    ++	  in_elementsof--;
    ++	  result = c_expr_elementsof_type (expr_loc, type_name);
     +	}
     +      else
     +	{
    @@ gcc/c/c-parser.cc: c_parser_sizeof_expression (c_parser *parser)
     +    Xof_expr:
            c_inhibit_evaluation_warnings--;
     -      in_sizeof--;
    -+      if (rid == RID_LENGTHOF)
    -+	in_lengthof--;
    ++      if (rid == RID_ELEMENTSOF)
    ++	in_elementsof--;
     +      else
     +	in_sizeof--;
            mark_exp_read (expr.value);
    @@ gcc/c/c-parser.cc: c_parser_sizeof_expression (c_parser *parser)
     -	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);
    ++      if (rid == RID_ELEMENTSOF)
    ++	result = c_expr_elementsof_expr (expr_loc, expr);
     +      else
     +	result = c_expr_sizeof_expr (expr_loc, expr);
          }
    @@ gcc/c/c-tree.h: 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_elementsof;
      extern int in_typeof;
      extern bool c_in_omp_for;
      extern bool c_omp_array_section_p;
    @@ gcc/c/c-tree.h: 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 c_expr_elementsof_expr (location_t, struct c_expr);
    ++extern struct c_expr c_expr_elementsof_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,
    @@ gcc/c/c-typeck.cc: 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 "elementsof".  */
    ++int in_elementsof;
     +
      /* 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 *
        if (TREE_CODE (ref) == FUNCTION_DECL && !in_alignof)
          {
     -      if (!in_sizeof && !in_typeof)
    -+      if (!in_sizeof && !in_typeof && !in_lengthof)
    ++      if (!in_sizeof && !in_typeof && !in_elementsof)
      	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).  */
    ++  /* The level seen at (in_sizeof + in_typeof + in_elementsof).  */
        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->level = in_sizeof + in_typeof + in_elementsof;
        t->next = maybe_used_decls;
        maybe_used_decls = t;
      }
    @@ gcc/c/c-typeck.cc: void
      {
        struct maybe_used_decl *p = maybe_used_decls;
     -  int cur_level = in_sizeof + in_typeof;
    -+  int cur_level = in_sizeof + in_typeof + in_lengthof;
    ++  int cur_level = in_sizeof + in_typeof + in_elementsof;
        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 var;
     +}
     +
    -+/* Return the result of lengthof applied to EXPR.  */
    ++/* Return the result of elementsof applied to EXPR.  */
     +
     +struct c_expr
    -+c_expr_lengthof_expr (location_t loc, struct c_expr expr)
    ++c_expr_elementsof_expr (location_t loc, struct c_expr expr)
     +{
     +  struct c_expr ret;
     +  if (expr.value == error_mark_node)
    @@ gcc/c/c-typeck.cc: c_expr_sizeof_type (location_t loc, struct c_type_name *t)
     +
     +      tree folded_expr = c_fully_fold (expr.value, require_constant_value,
     +				       &expr_const_operands);
    -+      ret.value = c_lengthof_type (loc, TREE_TYPE (folded_expr));
    ++      ret.value = c_elementsof_type (loc, TREE_TYPE (folded_expr));
     +      c_last_sizeof_arg = expr.value;
     +      c_last_sizeof_loc = loc;
    -+      ret.original_code = LENGTHOF_EXPR;
    ++      ret.original_code = ELEMENTSOF_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.  */
    ++	  /* elementsof 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
    -+   name passed to _lengthof (rather than the type itself).  LOC is the
    ++/* Return the result of elementsof applied to T, a structure for the type
    ++   name passed to elementsof (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)
    ++c_expr_elementsof_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);
    ++  ret.value = c_elementsof_type (loc, type);
     +  c_last_sizeof_arg = type;
     +  c_last_sizeof_loc = loc;
    -+  ret.original_code = LENGTHOF_EXPR;
    ++  ret.original_code = ELEMENTSOF_EXPR;
     +  ret.original_type = NULL;
     +  ret.m_decimal = 0;
     +  if (type == error_mark_node)
    @@ 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 elementsof 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 elementsof 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 ("__elementsof__", ELEMENTSOF_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/doc/extend.texi: If the operand of the @code{__alignof__} expression is a fu
      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
    ++@node elementsof
    ++@section Determining the Number of Elements of Arrays
    ++@cindex elementsof
    ++@cindex number of elements
     +
    -+The keyword @code{__lengthof__} determines the length of an array operand,
    ++The keyword @code{__elemetsf__} 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
    @@ gcc/doc/extend.texi: If the operand of the @code{__alignof__} expression is a fu
     +
     +@smallexample
     +int a[n];
    -+__lengthof__ (a);  // returns n
    -+__lengthof__ (int [7][3]);  // returns 7
    ++__elemetsf__ (a);  // returns n
    ++__elemetsf__ (int [7][3]);  // returns 7
     +@end smallexample
     +
     +The result of this operator is an integer constant expression,
    @@ gcc/doc/extend.texi: If the operand of the @code{__alignof__} expression is a fu
     +For example:
     +
     +@smallexample
    -+__lengthof__ (int [7][n++]);  // integer constant expression
    -+__lengthof__ (int [n++][7]);  // run-time value; n++ is evaluated
    ++__elemetsf__ (int [7][n++]);  // integer constant expression
    ++__elemetsf__ (int [n++][7]);  // run-time value; n++ is evaluated
     +@end smallexample
     +
      @node Inline
    @@ gcc/target.h: enum type_context_kind {
        /* Directly measuring the alignment of T.  */
        TCTX_ALIGNOF,
      
    -+  /* Directly measuring the length of array T.  */
    -+  TCTX_LENGTHOF,
    ++  /* Directly measuring the number of elements of array T.  */
    ++  TCTX_ELEMENTSOF,
     +
        /* Creating objects of type T with static storage duration.  */
        TCTX_STATIC_STORAGE,
      
     
    - ## gcc/testsuite/gcc.dg/lengthof-compile.c (new) ##
    + ## gcc/testsuite/gcc.dg/elementsof-compile.c (new) ##
     @@
     +/* { dg-do compile } */
     +/* { dg-options "-Wno-declaration-after-statement -Wno-pedantic -Wno-vla" } */
    @@ gcc/testsuite/gcc.dg/lengthof-compile.c (new)
     +static int w[] = {1, 2, 3};
     +
     +static int z[0];
    -+static int y[__lengthof__(z)];
    ++static int y[__elementsof__(z)];
     +
     +void
     +automatic(void)
     +{
    -+  __lengthof__ (w);
    ++  __elementsof__ (w);
     +}
     +
     +void
     +incomplete (int p[])
     +{
    -+  __lengthof__ (x);  /* { dg-error "incomplete" } */
    ++  __elementsof__ (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" } */
    ++  __elementsof__ (p);  /* { dg-error "invalid" } */
     +}
     +
     +void
    @@ gcc/testsuite/gcc.dg/lengthof-compile.c (new)
     +    int fam[];
     +  } s;
     +
    -+  __lengthof__ (s.fam); /* { dg-error "incomplete" } */
    ++  __elementsof__ (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 fix_fix (int i, char (*a)[3][5], int (*x)[__elementsof__ (*a)]);
    ++void fix_var (int i, char (*a)[3][i], int (*x)[__elementsof__ (*a)]);
    ++void fix_uns (int i, char (*a)[3][*], int (*x)[__elementsof__ (*a)]);
     +
     +void
     +func (void)
    @@ gcc/testsuite/gcc.dg/lengthof-compile.c (new)
     +    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" } */
    ++  __elementsof__ (x); /* { dg-error "invalid" } */
    ++  __elementsof__ (int); /* { dg-error "invalid" } */
    ++  __elementsof__ (s); /* { dg-error "invalid" } */
    ++  __elementsof__ (struct s); /* { dg-error "invalid" } */
    ++  __elementsof__ (&x); /* { dg-error "invalid" } */
    ++  __elementsof__ (p); /* { dg-error "invalid" } */
    ++  __elementsof__ (int *); /* { dg-error "invalid" } */
    ++  __elementsof__ (&s.x); /* { dg-error "invalid" } */
    ++  __elementsof__ (int (*)[3]); /* { dg-error "invalid" } */
     +}
     +
     +static int f1();
    @@ gcc/testsuite/gcc.dg/lengthof-compile.c (new)
     +{
     +  int b[n][n];
     +
    -+  __lengthof__ (a[f1()]);
    -+  __lengthof__ (b[f2()]);
    ++  __elementsof__ (a[f1()]);
    ++  __elementsof__ (b[f2()]);
     +}
     +
     +void
     +no_parens(void)
     +{
    -+  __lengthof__ a;
    -+  __lengthof__ *a;
    -+  __lengthof__ (int [3]) {};
    ++  __elementsof__ a;
    ++  __elementsof__ *a;
    ++  __elementsof__ (int [3]) {};
     +
    -+  __lengthof__ int [3]; /* { dg-error "expected expression before" } */
    ++  __elementsof__ int [3]; /* { dg-error "expected expression before" } */
     +}
     +
     +void
    @@ gcc/testsuite/gcc.dg/lengthof-compile.c (new)
     +{
     +  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);
    ++  _Static_assert (__elementsof__ (int [3][n]) == 3);
    ++  _Static_assert (__elementsof__ (int [n][3]) == 7); /* { dg-error "not constant" } */
    ++  _Static_assert (__elementsof__ (int [0][3]) == 0);
    ++  _Static_assert (__elementsof__ (int [0]) == 0);
     +
    -+  /* FIXME: lengthof(int [0][n]) should result in a constant expression.  */
    -+  _Static_assert (__lengthof__ (int [0][n]) == 0); /* { dg-error "not constant" } */
    ++  /* FIXME: elementsof(int [0][n]) should result in a constant expression.  */
    ++  _Static_assert (__elementsof__ (int [0][n]) == 0); /* { dg-error "not constant" } */
     +}
     
    - ## gcc/testsuite/gcc.dg/lengthof-vla.c (new) ##
    + ## gcc/testsuite/gcc.dg/elementsof-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)]);
    ++	      int (*x)[__elementsof__ (*a)]);
     +void fix_var (int i,
     +	      char (*a)[3][i], /* dg-warn "variable" */
    -+	      int (*x)[__lengthof__ (*a)]);
    ++	      int (*x)[__elementsof__ (*a)]);
     +void fix_uns (int i,
     +	      char (*a)[3][*],
    -+	      int (*x)[__lengthof__ (*a)]);
    ++	      int (*x)[__elementsof__ (*a)]);
     +
     +void zro_fix (int i,
     +	      char (*a)[0][5],
    -+	      int (*x)[__lengthof__ (*a)]);
    ++	      int (*x)[__elementsof__ (*a)]);
     +void zro_var (int i,
     +	      char (*a)[0][i], /* dg-warn "variable" */
    -+	      int (*x)[__lengthof__ (*a)]);
    ++	      int (*x)[__elementsof__ (*a)]);
     +void zro_uns (int i,
     +	      char (*a)[0][*],
    -+	      int (*x)[__lengthof__ (*a)]);
    ++	      int (*x)[__elementsof__ (*a)]);
     +
     +void var_fix (int i,
     +	      char (*a)[i][5], /* dg-warn "variable" */
    -+	      int (*x)[__lengthof__ (*a)]); /* dg-warn "variable" */
    ++	      int (*x)[__elementsof__ (*a)]); /* dg-warn "variable" */
     +void var_var (int i,
     +	      char (*a)[i][i], /* dg-warn "variable" */
    -+	      int (*x)[__lengthof__ (*a)]); /* dg-warn "variable" */
    ++	      int (*x)[__elementsof__ (*a)]); /* dg-warn "variable" */
     +void var_uns (int i,
     +	      char (*a)[i][*], /* dg-warn "variable" */
    -+	      int (*x)[__lengthof__ (*a)]); /* dg-warn "variable" */
    ++	      int (*x)[__elementsof__ (*a)]); /* dg-warn "variable" */
     +
     +void uns_fix (int i,
     +	      char (*a)[*][5],
    -+	      int (*x)[__lengthof__ (*a)]);
    ++	      int (*x)[__elementsof__ (*a)]);
     +void uns_var (int i,
     +	      char (*a)[*][i], /* dg-warn "variable" */
    -+	      int (*x)[__lengthof__ (*a)]);
    ++	      int (*x)[__elementsof__ (*a)]);
     +void uns_uns (int i,
     +	      char (*a)[*][*],
    -+	      int (*x)[__lengthof__ (*a)]);
    ++	      int (*x)[__elementsof__ (*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)];
    ++//static int y2[__elementsof__(z2)];
     
    - ## gcc/testsuite/gcc.dg/lengthof.c (new) ##
    + ## gcc/testsuite/gcc.dg/elementsof.c (new) ##
     @@
     +/* { dg-do run } */
     +/* { dg-options "-Wno-declaration-after-statement -Wno-pedantic -Wno-vla" } */
    @@ gcc/testsuite/gcc.dg/lengthof.c (new)
     +{
     +  short a[7];
     +
    -+  static_assert (__lengthof__ (a) == 7);
    -+  static_assert (__lengthof__ (long [0]) == 0);
    -+  static_assert (__lengthof__ (unsigned [99]) == 99);
    ++  static_assert (__elementsof__ (a) == 7);
    ++  static_assert (__elementsof__ (long [0]) == 0);
    ++  static_assert (__elementsof__ (unsigned [99]) == 99);
     +}
     +
     +void
    @@ gcc/testsuite/gcc.dg/lengthof.c (new)
     +  int a[] = {1, 2, 3};
     +  int z[] = {};
     +
    -+  static_assert (__lengthof__ (a) == 3);
    -+  static_assert (__lengthof__ (z) == 0);
    ++  static_assert (__elementsof__ (a) == 3);
    ++  static_assert (__elementsof__ (z) == 0);
     +}
     +
     +void
    @@ gcc/testsuite/gcc.dg/lengthof.c (new)
     +  unsigned n;
     +
     +  n = 99;
    -+  assert (__lengthof__ (short [n - 10]) == 99 - 10);
    ++  assert (__elementsof__ (short [n - 10]) == 99 - 10);
     +
     +  int v[n / 2];
    -+  assert (__lengthof__ (v) == 99 / 2);
    ++  assert (__elementsof__ (v) == 99 / 2);
     +
     +  n = 0;
     +  int z[n];
    -+  assert (__lengthof__ (z) == 0);
    ++  assert (__elementsof__ (z) == 0);
     +}
     +
     +void
    @@ gcc/testsuite/gcc.dg/lengthof.c (new)
     +    int a[8];
     +  } s;
     +
    -+  static_assert (__lengthof__ (s.a) == 8);
    ++  static_assert (__elementsof__ (s.a) == 8);
     +}
     +
     +void
    @@ gcc/testsuite/gcc.dg/lengthof.c (new)
     +  int i;
     +
     +  i = 7;
    -+  assert (__lengthof__ (struct {int x;}[i++]) == 7);
    ++  assert (__elementsof__ (struct {int x;}[i++]) == 7);
     +  assert (i == 7 + 1);
     +
     +  int v[i];
     +  int (*p)[i];
     +  p = &v;
    -+  assert (__lengthof__ (*p++) == i);
    ++  assert (__elementsof__ (*p++) == i);
     +  assert (p - 1 == &v);
     +}
     +
    @@ gcc/testsuite/gcc.dg/lengthof.c (new)
     +  int i;
     +
     +  i = 3;
    -+  static_assert (__lengthof__ (struct {int x[i++];}[3]) == 3);
    ++  static_assert (__elementsof__ (struct {int x[i++];}[3]) == 3);
     +  assert (i == 3);
     +}
     +
    @@ gcc/testsuite/gcc.dg/lengthof.c (new)
     +array_noeval (void)
     +{
     +  long a[5];
    -+  long (*p)[__lengthof__ (a)];
    ++  long (*p)[__elementsof__ (a)];
     +
     +  p = &a;
    -+  static_assert (__lengthof__ (*p++) == 5);
    ++  static_assert (__elementsof__ (*p++) == 5);
     +  assert (p == &a);
     +}
     +
    @@ gcc/testsuite/gcc.dg/lengthof.c (new)
     +{
     +  int i;
     +
    -+  static_assert (__lengthof__ (int [0][4]) == 0);
    ++  static_assert (__elementsof__ (int [0][4]) == 0);
     +  i = 3;
    -+  assert (__lengthof__ (int [0][i]) == 0);
    ++  assert (__elementsof__ (int [0][i]) == 0);
     +}
     +
     +void
    @@ gcc/testsuite/gcc.dg/lengthof.c (new)
     +{
     +  int i;
     +
    -+  static_assert (__lengthof__ (int [7][4]) == 7);
    ++  static_assert (__elementsof__ (int [7][4]) == 7);
     +  i = 3;
    -+  static_assert (__lengthof__ (int [7][i]) == 7);
    ++  static_assert (__elementsof__ (int [7][i]) == 7);
     +}
     +
     +void
    @@ gcc/testsuite/gcc.dg/lengthof.c (new)
     +  int i, j;
     +
     +  i = 7;
    -+  assert (__lengthof__ (int [i++][4]) == 7);
    ++  assert (__elementsof__ (int [i++][4]) == 7);
     +  assert (i == 7 + 1);
     +
     +  i = 9;
     +  j = 3;
    -+  assert (__lengthof__ (int [i++][j]) == 9);
    ++  assert (__elementsof__ (int [i++][j]) == 9);
     +  assert (i == 9 + 1);
     +}
     +
    @@ gcc/testsuite/gcc.dg/lengthof.c (new)
     +  int a[7];
     +  int v[n];
     +
    -+  static_assert (__lengthof__ a == 7); 
    -+  assert (__lengthof__ v == 3); 
    ++  static_assert (__elementsof__ a == 7); 
    ++  assert (__elementsof__ v == 3); 
     +}
     +
     +int
-- 
2.45.2


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 318+ messages in thread

* [PATCH v9 1/3] gcc/: Rename array_type_nelts() => array_type_nelts_minus_one()
  2024-08-14 20:58   ` [PATCH v9 0/3] c: Add __elementsof__ operator Alejandro Colomar
@ 2024-08-14 20:58     ` Alejandro Colomar
  2024-08-14 20:58     ` [PATCH v9 2/3] Merge definitions of array_type_nelts_top() Alejandro Colomar
  2024-08-14 20:58     ` [PATCH v9 3/3] c: Add __elementsof__ operator Alejandro Colomar
  2 siblings, 0 replies; 318+ messages in thread
From: Alejandro Colomar @ 2024-08-14 20:58 UTC (permalink / raw)
  To: gcc-patches
  Cc: Alejandro Colomar, Xavier Del Campo Romero, Martin Uecker,
	Joseph Myers, Gabriel Ravier, Jakub Jelinek, Kees Cook,
	Qing Zhao, Jens Gustedt, David Brown, Florian Weimer,
	Andreas Schwab, Timm Baeder, Daniel Plakosh, A. Jiang,
	Eugene Zelenko, Aaron Ballman, Paul Koning, Richard Biener

[-- Attachment #1: Type: text/plain, Size: 12760 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, array_type_nelts_minus_one):
	* tree.h (array_type_nelts, array_type_nelts_minus_one):
	* expr.cc (count_type_elements):
	* config/aarch64/aarch64.cc
	(pure_scalable_type_info::analyze_array):
	* config/i386/i386.cc (ix86_canonical_va_list_type):
	Rename array_type_nelts() => array_type_nelts_minus_one()
	The old name was misleading.

gcc/c/ChangeLog:

	* c-decl.cc (one_element_array_type_p, get_parm_array_spec):
	* c-fold.cc (c_fold_array_ref):
	Rename array_type_nelts() => array_type_nelts_minus_one()

gcc/cp/ChangeLog:

	* decl.cc (reshape_init_array):
	* init.cc
	(build_zero_init_1):
	(build_value_init_noctor):
	(build_vec_init):
	(build_delete):
	* lambda.cc (add_capture):
	* tree.cc (array_type_nelts_top):
	Rename array_type_nelts() => array_type_nelts_minus_one()

gcc/fortran/ChangeLog:

	* trans-array.cc (structure_alloc_comps):
	* trans-openmp.cc
	(gfc_walk_alloc_comps):
	(gfc_omp_clause_linear_ctor):
	Rename array_type_nelts() => array_type_nelts_minus_one()

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] 318+ messages in thread

* [PATCH v9 2/3] Merge definitions of array_type_nelts_top()
  2024-08-14 20:58   ` [PATCH v9 0/3] c: Add __elementsof__ operator Alejandro Colomar
  2024-08-14 20:58     ` [PATCH v9 1/3] gcc/: Rename array_type_nelts() => array_type_nelts_minus_one() Alejandro Colomar
@ 2024-08-14 20:58     ` Alejandro Colomar
  2024-08-14 20:58     ` [PATCH v9 3/3] c: Add __elementsof__ operator Alejandro Colomar
  2 siblings, 0 replies; 318+ messages in thread
From: Alejandro Colomar @ 2024-08-14 20:58 UTC (permalink / raw)
  To: gcc-patches
  Cc: Alejandro Colomar, Xavier Del Campo Romero, Martin Uecker,
	Joseph Myers, Gabriel Ravier, Jakub Jelinek, Kees Cook,
	Qing Zhao, Jens Gustedt, David Brown, Florian Weimer,
	Andreas Schwab, Timm Baeder, Daniel Plakosh, A. Jiang,
	Eugene Zelenko, Aaron Ballman, Paul Koning

[-- Attachment #1: Type: text/plain, Size: 4881 bytes --]

There were two identical definitions, and none of them are available
where they are needed for implementing __elementsof__.  Merge them, and
provide the single definition in gcc/tree.{h,cc}, where it's available
for __elementsof__, 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] 318+ messages in thread

* [PATCH v9 3/3] c: Add __elementsof__ operator
  2024-08-14 20:58   ` [PATCH v9 0/3] c: Add __elementsof__ operator Alejandro Colomar
  2024-08-14 20:58     ` [PATCH v9 1/3] gcc/: Rename array_type_nelts() => array_type_nelts_minus_one() Alejandro Colomar
  2024-08-14 20:58     ` [PATCH v9 2/3] Merge definitions of array_type_nelts_top() Alejandro Colomar
@ 2024-08-14 20:58     ` Alejandro Colomar
  2 siblings, 0 replies; 318+ messages in thread
From: Alejandro Colomar @ 2024-08-14 20:58 UTC (permalink / raw)
  To: gcc-patches
  Cc: Alejandro Colomar, Xavier Del Campo Romero, Martin Uecker,
	Joseph Myers, Gabriel Ravier, Jakub Jelinek, Kees Cook,
	Qing Zhao, Jens Gustedt, David Brown, Florian Weimer,
	Andreas Schwab, Timm Baeder, Daniel Plakosh, A. Jiang,
	Eugene Zelenko, Aaron Ballman, Paul Koning

[-- Attachment #1: Type: text/plain, Size: 30280 bytes --]

This operator is similar to sizeof but can only be applied to an array,
and returns its number of elements.

FUTURE DIRECTIONS:

-  We should make it work with array parameters to functions,
   and somehow magically return the number of elements 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>
Cc: Daniel Plakosh <dplakosh@cert.org>
Cc: "A. Jiang" <de34@live.cn>
Cc: Eugene Zelenko <eugene.zelenko@gmail.com>
Cc: Aaron Ballman <aaron.ballman@intel.com>
Cc: Paul Koning <paulkoning@comcast.net>

gcc/ChangeLog:

	* doc/extend.texi: Document __elementsof__ operator.
	* target.h (enum type_context_kind): Add __elementsof__ operator.

gcc/c-family/ChangeLog:

	* c-common.h:
	* c-common.def:
	* c-common.cc (c_elementsof_type): Add __elementsof__ operator.

gcc/c/ChangeLog:

	* c-tree.h
	(c_expr_elementsof_expr, c_expr_elementsof_type):
	* c-decl.cc
	(start_struct, finish_struct):
	(start_enum, finish_enum):
	* c-parser.cc
	(c_parser_sizeof_expression):
	(c_parser_elementsof_expression):
	(c_parser_sizeof_or_elementsof_expression):
	(c_parser_unary_expression):
	* c-typeck.cc
	(build_external_ref):
	(record_maybe_used_decl, pop_maybe_used):
	(is_top_array_vla):
	(c_expr_elementsof_expr, c_expr_elementsof_type):
	Add __elementsof__operator.

gcc/cp/ChangeLog:

	* operators.def: Add __elementsof__ operator.

gcc/testsuite/ChangeLog:

	* gcc.dg/elementsof-compile.c:
	* gcc.dg/elementsof-vla.c:
	* gcc.dg/elementsof.c: Add tests for __elementsof__ 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/
Link: https://github.com/llvm/llvm-project/issues/102836
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                           |  21 ++-
 gcc/c/c-parser.cc                         |  62 +++++++--
 gcc/c/c-tree.h                            |   4 +
 gcc/c/c-typeck.cc                         | 118 ++++++++++++++++-
 gcc/cp/operators.def                      |   1 +
 gcc/doc/extend.texi                       |  30 +++++
 gcc/target.h                              |   3 +
 gcc/testsuite/gcc.dg/elementsof-compile.c | 115 +++++++++++++++++
 gcc/testsuite/gcc.dg/elementsof-vla.c     |  46 +++++++
 gcc/testsuite/gcc.dg/elementsof.c         | 150 ++++++++++++++++++++++
 13 files changed, 557 insertions(+), 24 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/elementsof-compile.c
 create mode 100644 gcc/testsuite/gcc.dg/elementsof-vla.c
 create mode 100644 gcc/testsuite/gcc.dg/elementsof.c

diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
index e7e371fd26f..7e6ef179413 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 },
+  { "__elementsof__",	RID_ELEMENTSOF, 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 lementsof keyword:
+   Return the number of elements of an array.  */
+
+tree
+c_elementsof_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 %<elementsof%> to type %qT", type);
+      return error_mark_node;
+    }
+  if (!COMPLETE_TYPE_P (type))
+    {
+      error_at (loc,
+		"invalid application of %<elementsof%> 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..c43a1e4ab08 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 'elementsof' expression.  */
+DEFTREECODE (ELEMENTSOF_EXPR, "elementsof_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..475f315f38b 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_ELEMENTSOF,
   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_elementsof_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..4fd1bc5bdb8 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -8943,12 +8943,17 @@ 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_elementsof))
     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"
+		       : "elementsof"))));
 
   if (in_underspecified_init)
     error_at (loc, "%qT defined in underspecified object initializer", ref);
@@ -9908,7 +9913,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_elementsof)
 	struct_parse_info->struct_types.safe_push (t);
      }
 
@@ -10082,12 +10087,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_elementsof))
     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"
+		       : "elementsof"))));
 
   if (in_underspecified_init)
     error_at (loc, "%qT defined in underspecified object initializer",
@@ -10281,7 +10290,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_elementsof)
     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..5b0238cfddf 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_elementsof_expression (parser, RID_SIZEOF)               \
+)
 
+#define c_parser_elementsof_expression(parser)                                \
+(                                                                             \
+  c_parser_sizeof_or_elementsof_expression (parser, RID_ELEMENTSOF)           \
+)
+\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,8 @@ 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_elementsof_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 +9920,8 @@ c_parser_unary_expression (c_parser *parser)
     case CPP_KEYWORD:
       switch (c_parser_peek_token (parser)->keyword)
 	{
+	case RID_ELEMENTSOF:
+	  return c_parser_elementsof_expression (parser);
 	case RID_SIZEOF:
 	  return c_parser_sizeof_expression (parser);
 	case RID_ALIGNOF:
@@ -9948,12 +9961,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_elementsof_expression (c_parser *parser, enum rid rid)
 {
+  const char *op_name = (rid == RID_ELEMENTSOF) ? "elementsof" : "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 +9976,10 @@ c_parser_sizeof_expression (c_parser *parser)
 
   c_parser_consume_token (parser);
   c_inhibit_evaluation_warnings++;
-  in_sizeof++;
+  if (rid == RID_ELEMENTSOF)
+    in_elementsof++;
+  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 +9998,10 @@ c_parser_sizeof_expression (c_parser *parser)
 	{
 	  struct c_expr ret;
 	  c_inhibit_evaluation_warnings--;
-	  in_sizeof--;
+	  if (rid == RID_ELEMENTSOF)
+	    in_elementsof--;
+	  else
+	    in_sizeof--;
 	  ret.set_error ();
 	  ret.original_code = ERROR_MARK;
 	  ret.original_type = NULL;
@@ -9993,31 +10013,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_ELEMENTSOF)
+	{
+	  in_elementsof--;
+	  result = c_expr_elementsof_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_ELEMENTSOF)
+	in_elementsof--;
+      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_ELEMENTSOF)
+	result = c_expr_elementsof_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..b75833d020c 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_elementsof;
 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_elementsof_expr (location_t, struct c_expr);
+extern struct c_expr c_expr_elementsof_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..2b5450222df 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 "elementsof".  */
+int in_elementsof;
+
 /* 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_elementsof)
 	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_elementsof).  */
   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_elementsof;
   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_elementsof;
   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 elementsof applied to EXPR.  */
+
+struct c_expr
+c_expr_elementsof_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_elementsof_type (loc, TREE_TYPE (folded_expr));
+      c_last_sizeof_arg = expr.value;
+      c_last_sizeof_loc = loc;
+      ret.original_code = ELEMENTSOF_EXPR;
+      ret.original_type = NULL;
+      ret.m_decimal = 0;
+      if (is_top_array_vla (TREE_TYPE (folded_expr)))
+	{
+	  /* elementsof 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 elementsof applied to T, a structure for the type
+   name passed to elementsof (rather than the type itself).  LOC is the
+   location of the original expression.  */
+
+struct c_expr
+c_expr_elementsof_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_elementsof_type (loc, type);
+  c_last_sizeof_arg = type;
+  c_last_sizeof_loc = loc;
+  ret.original_code = ELEMENTSOF_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 elementsof 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 elementsof 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..21634f0754d 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 ("__elementsof__", ELEMENTSOF_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..626cbb9b167 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -10466,6 +10466,36 @@ 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 elementsof
+@section Determining the Number of Elements of Arrays
+@cindex elementsof
+@cindex number of elements
+
+The keyword @code{__elemetsf__} 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 parenthesized complete array type name
+or an expression of such a type.
+For example:
+
+@smallexample
+int a[n];
+__elemetsf__ (a);  // returns n
+__elemetsf__ (int [7][3]);  // returns 7
+@end smallexample
+
+The result of this operator is an integer constant expression,
+unless the top-level array is a variable-length array.
+The operand is only evaluated
+if the top-level array is a variable-length array.
+For example:
+
+@smallexample
+__elemetsf__ (int [7][n++]);  // integer constant expression
+__elemetsf__ (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..aa6c8b7ace1 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 number of elements of array T.  */
+  TCTX_ELEMENTSOF,
+
   /* Creating objects of type T with static storage duration.  */
   TCTX_STATIC_STORAGE,
 
diff --git a/gcc/testsuite/gcc.dg/elementsof-compile.c b/gcc/testsuite/gcc.dg/elementsof-compile.c
new file mode 100644
index 00000000000..5ee7e991e0d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/elementsof-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[__elementsof__(z)];
+
+void
+automatic(void)
+{
+  __elementsof__ (w);
+}
+
+void
+incomplete (int p[])
+{
+  __elementsof__ (x);  /* { dg-error "incomplete" } */
+
+  /* We want to support the following one in the future,
+     but for now it should fail.  */
+  __elementsof__ (p);  /* { dg-error "invalid" } */
+}
+
+void
+fam (void)
+{
+  struct {
+    int x;
+    int fam[];
+  } s;
+
+  __elementsof__ (s.fam); /* { dg-error "incomplete" } */
+}
+
+void fix_fix (int i, char (*a)[3][5], int (*x)[__elementsof__ (*a)]);
+void fix_var (int i, char (*a)[3][i], int (*x)[__elementsof__ (*a)]);
+void fix_uns (int i, char (*a)[3][*], int (*x)[__elementsof__ (*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;
+
+  __elementsof__ (x); /* { dg-error "invalid" } */
+  __elementsof__ (int); /* { dg-error "invalid" } */
+  __elementsof__ (s); /* { dg-error "invalid" } */
+  __elementsof__ (struct s); /* { dg-error "invalid" } */
+  __elementsof__ (&x); /* { dg-error "invalid" } */
+  __elementsof__ (p); /* { dg-error "invalid" } */
+  __elementsof__ (int *); /* { dg-error "invalid" } */
+  __elementsof__ (&s.x); /* { dg-error "invalid" } */
+  __elementsof__ (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];
+
+  __elementsof__ (a[f1()]);
+  __elementsof__ (b[f2()]);
+}
+
+void
+no_parens(void)
+{
+  __elementsof__ a;
+  __elementsof__ *a;
+  __elementsof__ (int [3]) {};
+
+  __elementsof__ int [3]; /* { dg-error "expected expression before" } */
+}
+
+void
+const_expr(void)
+{
+  int n = 7;
+
+  _Static_assert (__elementsof__ (int [3][n]) == 3);
+  _Static_assert (__elementsof__ (int [n][3]) == 7); /* { dg-error "not constant" } */
+  _Static_assert (__elementsof__ (int [0][3]) == 0);
+  _Static_assert (__elementsof__ (int [0]) == 0);
+
+  /* FIXME: elementsof(int [0][n]) should result in a constant expression.  */
+  _Static_assert (__elementsof__ (int [0][n]) == 0); /* { dg-error "not constant" } */
+}
diff --git a/gcc/testsuite/gcc.dg/elementsof-vla.c b/gcc/testsuite/gcc.dg/elementsof-vla.c
new file mode 100644
index 00000000000..10d1baae336
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/elementsof-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)[__elementsof__ (*a)]);
+void fix_var (int i,
+	      char (*a)[3][i], /* dg-warn "variable" */
+	      int (*x)[__elementsof__ (*a)]);
+void fix_uns (int i,
+	      char (*a)[3][*],
+	      int (*x)[__elementsof__ (*a)]);
+
+void zro_fix (int i,
+	      char (*a)[0][5],
+	      int (*x)[__elementsof__ (*a)]);
+void zro_var (int i,
+	      char (*a)[0][i], /* dg-warn "variable" */
+	      int (*x)[__elementsof__ (*a)]);
+void zro_uns (int i,
+	      char (*a)[0][*],
+	      int (*x)[__elementsof__ (*a)]);
+
+void var_fix (int i,
+	      char (*a)[i][5], /* dg-warn "variable" */
+	      int (*x)[__elementsof__ (*a)]); /* dg-warn "variable" */
+void var_var (int i,
+	      char (*a)[i][i], /* dg-warn "variable" */
+	      int (*x)[__elementsof__ (*a)]); /* dg-warn "variable" */
+void var_uns (int i,
+	      char (*a)[i][*], /* dg-warn "variable" */
+	      int (*x)[__elementsof__ (*a)]); /* dg-warn "variable" */
+
+void uns_fix (int i,
+	      char (*a)[*][5],
+	      int (*x)[__elementsof__ (*a)]);
+void uns_var (int i,
+	      char (*a)[*][i], /* dg-warn "variable" */
+	      int (*x)[__elementsof__ (*a)]);
+void uns_uns (int i,
+	      char (*a)[*][*],
+	      int (*x)[__elementsof__ (*a)]);
+
+// Can't test due to bug: <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=116284>
+//static int z2[0];
+//static int y2[__elementsof__(z2)];
diff --git a/gcc/testsuite/gcc.dg/elementsof.c b/gcc/testsuite/gcc.dg/elementsof.c
new file mode 100644
index 00000000000..de0e45e5c9e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/elementsof.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 (__elementsof__ (a) == 7);
+  static_assert (__elementsof__ (long [0]) == 0);
+  static_assert (__elementsof__ (unsigned [99]) == 99);
+}
+
+void
+automatic(void)
+{
+  int a[] = {1, 2, 3};
+  int z[] = {};
+
+  static_assert (__elementsof__ (a) == 3);
+  static_assert (__elementsof__ (z) == 0);
+}
+
+void
+vla (void)
+{
+  unsigned n;
+
+  n = 99;
+  assert (__elementsof__ (short [n - 10]) == 99 - 10);
+
+  int v[n / 2];
+  assert (__elementsof__ (v) == 99 / 2);
+
+  n = 0;
+  int z[n];
+  assert (__elementsof__ (z) == 0);
+}
+
+void
+member (void)
+{
+  struct {
+    int a[8];
+  } s;
+
+  static_assert (__elementsof__ (s.a) == 8);
+}
+
+void
+vla_eval (void)
+{
+  int i;
+
+  i = 7;
+  assert (__elementsof__ (struct {int x;}[i++]) == 7);
+  assert (i == 7 + 1);
+
+  int v[i];
+  int (*p)[i];
+  p = &v;
+  assert (__elementsof__ (*p++) == i);
+  assert (p - 1 == &v);
+}
+
+void
+inner_vla_noeval (void)
+{
+  int i;
+
+  i = 3;
+  static_assert (__elementsof__ (struct {int x[i++];}[3]) == 3);
+  assert (i == 3);
+}
+
+void
+array_noeval (void)
+{
+  long a[5];
+  long (*p)[__elementsof__ (a)];
+
+  p = &a;
+  static_assert (__elementsof__ (*p++) == 5);
+  assert (p == &a);
+}
+
+void
+matrix_zero (void)
+{
+  int i;
+
+  static_assert (__elementsof__ (int [0][4]) == 0);
+  i = 3;
+  assert (__elementsof__ (int [0][i]) == 0);
+}
+
+void
+matrix_fixed (void)
+{
+  int i;
+
+  static_assert (__elementsof__ (int [7][4]) == 7);
+  i = 3;
+  static_assert (__elementsof__ (int [7][i]) == 7);
+}
+
+void
+matrix_vla (void)
+{
+  int i, j;
+
+  i = 7;
+  assert (__elementsof__ (int [i++][4]) == 7);
+  assert (i == 7 + 1);
+
+  i = 9;
+  j = 3;
+  assert (__elementsof__ (int [i++][j]) == 9);
+  assert (i == 9 + 1);
+}
+
+void
+no_parens(void)
+{
+  int n = 3;
+  int a[7];
+  int v[n];
+
+  static_assert (__elementsof__ a == 7); 
+  assert (__elementsof__ 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] 318+ messages in thread

* [PATCH v10 0/3] c: Add __nelementsof__ operator
  2024-07-28 14:15 ` [RFC v1 0/2] c: Add _Lengthof operator Alejandro Colomar
                     ` (14 preceding siblings ...)
  2024-08-14 20:58   ` [PATCH v9 0/3] c: Add __elementsof__ operator Alejandro Colomar
@ 2024-08-19 10:58   ` Alejandro Colomar
  2024-08-19 10:58     ` [PATCH v10 1/3] gcc/: Rename array_type_nelts() => array_type_nelts_minus_one() Alejandro Colomar
                       ` (2 more replies)
  2024-08-20 18:41   ` [PATCH v11 0/4] " Alejandro Colomar
                     ` (12 subsequent siblings)
  28 siblings, 3 replies; 318+ messages in thread
From: Alejandro Colomar @ 2024-08-19 10:58 UTC (permalink / raw)
  To: gcc-patches
  Cc: Alejandro Colomar, gcc, Xavier Del Campo Romero, Martin Uecker,
	Joseph Myers, Gabriel Ravier, Jakub Jelinek, Kees Cook,
	Qing Zhao, Jens Gustedt, David Brown, Florian Weimer,
	Andreas Schwab, Timm Baeder, Daniel Plakosh, A. Jiang,
	Eugene Zelenko, Aaron Ballman, Paul Koning, Daniel Lundin,
	Nikolaos Strimpas, JeanHeyd Meneide, Fernando Borretti,
	Jonathan Protzenko, Chris Bazley, Ville Voutilainen,
	Alex Celeste, Jakub Łukasiewicz

[-- Attachment #1: Type: text/plain, Size: 39308 bytes --]

Hi!

This is v10 of this patch set; hopefully, we're close to an end.

I've already submitted a proposal for C2y to WG14, as n3313:
<https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3313.pdf>

For those who haven't been following since the start, the entire thread
of patch set revisions and their discussions can be found here:
<https://inbox.sourceware.org/gcc-patches/20240728141547.302478-1-alx@kernel.org/T/#t>
It also contains drafts of the n3313 proposal.

Changes since v9:

-  Rename s/__elementsof__/__nelementsof__/

   elementsof() doesn't mean in English something compatible with its
   programming semantics.  While there's existing uses of it in
   programming, that's an abuse of English, which could cause confusion,
   or maybe preclude a more appropriate use of that name in the future.

   nelementsof() is just one more byte, and is much more appropriate, by
   being a contraction of "_n_umber (of) elements of".

   Also, there's only one use of nelementsof() in the wild, which makes
   backwards compatibility much less of a concern.  That use is
   semantically compatible with this proposed operator.  And we could
   just notify that project the existence of a new standard operator
   with that name, if we finally settle on this name.

-  Rebase on top of git HEAD.

-  CC +=
	Daniel Lundin, Nikolaos, JeanHeyd, Fernando, Jonathan, Chris,
	Ville, Alex Celeste, Jakub Łukasiewicz

I have a draft for an updated proposal to WG14 (more recent than n3313).
It has some changes to the documentation of prior art, some typo fixes,
etc., and renames elementsof()=>nelementsof(), but the meat of the
proposal is the same.  I've also rebased it on top of the latest draft
for C2y, which is n3301.  I'll send it as a reply to this subthread.

This cover letter is sent to both gcc-patches@ and gcc@.  The patches
are only sent to gcc-patches@, and the draft for WG14 is only sent to
gcc@.

If anyone wants to add an `Acked-by:` (or `Reviewed-by:`), please do it
explicitly.  There've been some informal ones, but I prefer to pick them
from explicit ones.


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 __nelementsof__ 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                            |  32 +++--
 gcc/c/c-fold.cc                            |   7 +-
 gcc/c/c-parser.cc                          |  62 +++++++--
 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                        |  30 +++++
 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/nelementsof-compile.c | 115 ++++++++++++++++
 gcc/testsuite/gcc.dg/nelementsof-vla.c     |  46 +++++++
 gcc/testsuite/gcc.dg/nelementsof.c         | 150 +++++++++++++++++++++
 gcc/tree.cc                                |  17 ++-
 gcc/tree.h                                 |   3 +-
 28 files changed, 600 insertions(+), 79 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/nelementsof-compile.c
 create mode 100644 gcc/testsuite/gcc.dg/nelementsof-vla.c
 create mode 100644 gcc/testsuite/gcc.dg/nelementsof.c

Range-diff against v9:
1:  a6aa38c9013 = 1:  ab72c4cee8f gcc/: Rename array_type_nelts() => array_type_nelts_minus_one()
2:  4ce16ee4dfe ! 2:  27852be4ac0 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 __elementsof__.  Merge them, and
    +    where they are needed for implementing __nelementsof__.  Merge them, and
         provide the single definition in gcc/tree.{h,cc}, where it's available
    -    for __elementsof__, which will be added in the following commit.
    +    for __nelementsof__, which will be added in the following commit.
     
         gcc/ChangeLog:
     
3:  caae5dbecb3 ! 3:  9c78ce1f66d c: Add __elementsof__ operator
    @@ Metadata
     Author: Alejandro Colomar <alx@kernel.org>
     
      ## Commit message ##
    -    c: Add __elementsof__ operator
    +    c: Add __nelementsof__ operator
     
         This operator is similar to sizeof but can only be applied to an array,
         and returns its number of elements.
    @@ Commit message
         Cc: Eugene Zelenko <eugene.zelenko@gmail.com>
         Cc: Aaron Ballman <aaron.ballman@intel.com>
         Cc: Paul Koning <paulkoning@comcast.net>
    +    Cc: Daniel Lundin <daniel.lundin.mail@gmail.com>
    +    Cc: Nikolaos Strimpas <Strnik86@protonmail.com>
    +    Cc: JeanHeyd Meneide <phdofthehouse@gmail.com>
    +    Cc: Fernando Borretti <fernando@borretti.me>
    +    Cc: Jonathan Protzenko <jonathan.protzenko@ens-lyon.org>
    +    Cc: Chris Bazley <Chris.Bazley@arm.com>
    +    Cc: Ville Voutilainen <ville.voutilainen@gmail.com>
    +    Cc: Alex Celeste <alexg.nvfp@gmail.com>
    +    Cc: Jakub Łukasiewicz <jakublukasiewicz@outlook.com>
     
         gcc/ChangeLog:
     
    -            * doc/extend.texi: Document __elementsof__ operator.
    -            * target.h (enum type_context_kind): Add __elementsof__ operator.
    +            * doc/extend.texi: Document __nelementsof__ operator.
    +            * target.h (enum type_context_kind): Add __nelementsof__ operator.
     
         gcc/c-family/ChangeLog:
     
                 * c-common.h:
                 * c-common.def:
    -            * c-common.cc (c_elementsof_type): Add __elementsof__ operator.
    +            * c-common.cc (c_nelementsof_type): Add __nelementsof__ operator.
     
         gcc/c/ChangeLog:
     
                 * c-tree.h
    -            (c_expr_elementsof_expr, c_expr_elementsof_type):
    +            (c_expr_nelementsof_expr, c_expr_nelementsof_type):
                 * c-decl.cc
                 (start_struct, finish_struct):
                 (start_enum, finish_enum):
                 * c-parser.cc
                 (c_parser_sizeof_expression):
    -            (c_parser_elementsof_expression):
    -            (c_parser_sizeof_or_elementsof_expression):
    +            (c_parser_nelementsof_expression):
    +            (c_parser_sizeof_or_nelementsof_expression):
                 (c_parser_unary_expression):
                 * c-typeck.cc
                 (build_external_ref):
                 (record_maybe_used_decl, pop_maybe_used):
                 (is_top_array_vla):
    -            (c_expr_elementsof_expr, c_expr_elementsof_type):
    -            Add __elementsof__operator.
    +            (c_expr_nelementsof_expr, c_expr_nelementsof_type):
    +            Add __nelementsof__operator.
     
         gcc/cp/ChangeLog:
     
    -            * operators.def: Add __elementsof__ operator.
    +            * operators.def: Add __nelementsof__ operator.
     
         gcc/testsuite/ChangeLog:
     
    -            * gcc.dg/elementsof-compile.c:
    -            * gcc.dg/elementsof-vla.c:
    -            * gcc.dg/elementsof.c: Add tests for __elementsof__ operator.
    +            * gcc.dg/nelementsof-compile.c:
    +            * gcc.dg/nelementsof-vla.c:
    +            * gcc.dg/nelementsof.c: Add tests for __nelementsof__ operator.
     
    -    Link: https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2529.pdf
    +    Link: https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3313.pdf
         Link: https://inbox.sourceware.org/gcc/M8S4oQy--3-2@tutanota.com/T/
         Link: https://github.com/llvm/llvm-project/issues/102836
         Suggested-by: Xavier Del Campo Romero <xavi.dcr@tutanota.com>
    @@ gcc/c-family/c-common.cc: const struct c_common_resword c_common_reswords[] =
        { "__inline",		RID_INLINE,	0 },
        { "__inline__",	RID_INLINE,	0 },
        { "__label__",	RID_LABEL,	0 },
    -+  { "__elementsof__",	RID_ELEMENTSOF, 0 },
    ++  { "__nelementsof__",	RID_NELEMENTSOF, 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 the number of elements of an array.  */
     +
     +tree
    -+c_elementsof_type (location_t loc, tree type)
    ++c_nelementsof_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 %<elementsof%> to type %qT", type);
    ++      error_at (loc, "invalid application of %<nelementsof%> to type %qT", type);
     +      return error_mark_node;
     +    }
     +  if (!COMPLETE_TYPE_P (type))
     +    {
     +      error_at (loc,
    -+		"invalid application of %<elementsof%> to incomplete type %qT",
    ++		"invalid application of %<nelementsof%> to incomplete 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 'elementsof' expression.  */
    -+DEFTREECODE (ELEMENTSOF_EXPR, "elementsof_expr", tcc_expression, 1)
    ++/* Represents a 'nelementsof' expression.  */
    ++DEFTREECODE (NELEMENTSOF_EXPR, "nelementsof_expr", tcc_expression, 1)
     +
      /* Represents a 'sizeof' expression during C++ template expansion,
         or for the purpose of -Wsizeof-pointer-memaccess warning.  */
    @@ gcc/c-family/c-common.h: enum rid
      
        /* C extensions */
        RID_ASM,       RID_TYPEOF,   RID_TYPEOF_UNQUAL, RID_ALIGNOF,  RID_ATTRIBUTE,
    -+  RID_ELEMENTSOF,
    ++  RID_NELEMENTSOF,
        RID_VA_ARG,
        RID_EXTENSION, RID_IMAGPART, RID_REALPART, RID_LABEL,    RID_CHOOSE_EXPR,
        RID_TYPES_COMPATIBLE_P,      RID_BUILTIN_COMPLEX,	   RID_BUILTIN_SHUFFLE,
    @@ gcc/c-family/c-common.h: extern tree c_common_truthvalue_conversion (location_t,
      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_elementsof_type (location_t, tree);
    ++extern tree c_nelementsof_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);
    @@ gcc/c/c-decl.cc: start_struct (location_t loc, enum tree_code code, tree name,
           sizeof anyhow.  */
     -  if (warn_cxx_compat && (in_sizeof || in_typeof || in_alignof))
     +  if (warn_cxx_compat
    -+      && (in_sizeof || in_typeof || in_alignof || in_elementsof))
    ++      && (in_sizeof || in_typeof || in_alignof || in_nelementsof))
          warning_at (loc, OPT_Wc___compat,
      		"defining type in %qs expression is invalid in C++",
      		(in_sizeof
    @@ gcc/c/c-decl.cc: start_struct (location_t loc, enum tree_code code, tree name,
     +		    ? "typeof"
     +		    : (in_alignof
     +		       ? "alignof"
    -+		       : "elementsof"))));
    ++		       : "nelementsof"))));
      
        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 att
            if (warn_cxx_compat
      	  && struct_parse_info != NULL
     -	  && !in_sizeof && !in_typeof && !in_alignof)
    -+	  && !in_sizeof && !in_typeof && !in_alignof && !in_elementsof)
    ++	  && !in_sizeof && !in_typeof && !in_alignof && !in_nelementsof)
      	struct_parse_info->struct_types.safe_push (t);
           }
      
    @@ gcc/c/c-decl.cc: start_enum (location_t loc, struct c_enum_contents *the_enum, t
           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_elementsof))
    ++  if (warn_cxx_compat
    ++      && (in_sizeof || in_typeof || in_alignof || in_nelementsof))
          warning_at (loc, OPT_Wc___compat,
      		"defining type in %qs expression is invalid in C++",
      		(in_sizeof
    @@ gcc/c/c-decl.cc: start_enum (location_t loc, struct c_enum_contents *the_enum, t
     +		    ? "typeof"
     +		    : (in_alignof
     +		       ? "alignof"
    -+		       : "elementsof"))));
    ++		       : "nelementsof"))));
      
        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)
        if (warn_cxx_compat
            && struct_parse_info != NULL
     -      && !in_sizeof && !in_typeof && !in_alignof)
    -+      && !in_sizeof && !in_typeof && !in_alignof && !in_elementsof)
    ++      && !in_sizeof && !in_typeof && !in_alignof && !in_nelementsof)
          struct_parse_info->struct_types.safe_push (enumtype);
      
        /* Check for consistency with previous definition */
    @@ gcc/c/c-parser.cc: along with GCC; see the file COPYING3.  If not see
     +\f
     +#define c_parser_sizeof_expression(parser)                                    \
     +(                                                                             \
    -+  c_parser_sizeof_or_elementsof_expression (parser, RID_SIZEOF)               \
    ++  c_parser_sizeof_or_nelementsof_expression (parser, RID_SIZEOF)              \
     +)
      
    -+#define c_parser_elementsof_expression(parser)                                \
    ++#define c_parser_nelementsof_expression(parser)                               \
     +(                                                                             \
    -+  c_parser_sizeof_or_elementsof_expression (parser, RID_ELEMENTSOF)           \
    ++  c_parser_sizeof_or_nelementsof_expression (parser, RID_NELEMENTSOF)         \
     +)
     +\f
      /* We need to walk over decls with incomplete struct/union/enum types
    @@ gcc/c/c-parser.cc: static struct c_expr c_parser_binary_expression (c_parser *,
      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_elementsof_expression (c_parser *,
    -+							       enum rid);
    ++static struct c_expr c_parser_sizeof_or_nelementsof_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 *,
    @@ gcc/c/c-parser.cc: c_parser_unary_expression (c_parser *parser)
          case CPP_KEYWORD:
            switch (c_parser_peek_token (parser)->keyword)
      	{
    -+	case RID_ELEMENTSOF:
    -+	  return c_parser_elementsof_expression (parser);
    ++	case RID_NELEMENTSOF:
    ++	  return c_parser_nelementsof_expression (parser);
      	case RID_SIZEOF:
      	  return c_parser_sizeof_expression (parser);
      	case RID_ALIGNOF:
    @@ gcc/c/c-parser.cc: c_parser_unary_expression (c_parser *parser)
      
      static struct c_expr
     -c_parser_sizeof_expression (c_parser *parser)
    -+c_parser_sizeof_or_elementsof_expression (c_parser *parser, enum rid rid)
    ++c_parser_sizeof_or_nelementsof_expression (c_parser *parser, enum rid rid)
      {
    -+  const char *op_name = (rid == RID_ELEMENTSOF) ? "elementsof" : "sizeof";
    ++  const char *op_name = (rid == RID_NELEMENTSOF) ? "nelementsof" : "sizeof";
        struct c_expr expr;
        struct c_expr result;
        location_t expr_loc;
    @@ 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_ELEMENTSOF)
    -+    in_elementsof++;
    ++  if (rid == RID_NELEMENTSOF)
    ++    in_nelementsof++;
     +  else
     +    in_sizeof++;
        if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)
    @@ 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_ELEMENTSOF)
    -+	    in_elementsof--;
    ++	  if (rid == RID_NELEMENTSOF)
    ++	    in_nelementsof--;
     +	  else
     +	    in_sizeof--;
      	  ret.set_error ();
    @@ gcc/c/c-parser.cc: c_parser_sizeof_expression (c_parser *parser)
            c_inhibit_evaluation_warnings--;
     -      in_sizeof--;
     -      result = c_expr_sizeof_type (expr_loc, type_name);
    -+      if (rid == RID_ELEMENTSOF)
    ++      if (rid == RID_NELEMENTSOF)
     +	{
    -+	  in_elementsof--;
    -+	  result = c_expr_elementsof_type (expr_loc, type_name);
    ++	  in_nelementsof--;
    ++	  result = c_expr_nelementsof_type (expr_loc, type_name);
     +	}
     +      else
     +	{
    @@ gcc/c/c-parser.cc: c_parser_sizeof_expression (c_parser *parser)
     +    Xof_expr:
            c_inhibit_evaluation_warnings--;
     -      in_sizeof--;
    -+      if (rid == RID_ELEMENTSOF)
    -+	in_elementsof--;
    ++      if (rid == RID_NELEMENTSOF)
    ++	in_nelementsof--;
     +      else
     +	in_sizeof--;
            mark_exp_read (expr.value);
    @@ gcc/c/c-parser.cc: c_parser_sizeof_expression (c_parser *parser)
     -	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_ELEMENTSOF)
    -+	result = c_expr_elementsof_expr (expr_loc, expr);
    ++      if (rid == RID_NELEMENTSOF)
    ++	result = c_expr_nelementsof_expr (expr_loc, expr);
     +      else
     +	result = c_expr_sizeof_expr (expr_loc, expr);
          }
    @@ gcc/c/c-tree.h: extern int c_type_dwarf_attribute (const_tree, int);
      /* in c-typeck.cc */
      extern int in_alignof;
      extern int in_sizeof;
    -+extern int in_elementsof;
    ++extern int in_nelementsof;
      extern int in_typeof;
      extern bool c_in_omp_for;
      extern bool c_omp_array_section_p;
    @@ gcc/c/c-tree.h: 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_elementsof_expr (location_t, struct c_expr);
    -+extern struct c_expr c_expr_elementsof_type (location_t loc,
    -+					     struct c_type_name *);
    ++extern struct c_expr c_expr_nelementsof_expr (location_t, struct c_expr);
    ++extern struct c_expr c_expr_nelementsof_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,
    @@ gcc/c/c-typeck.cc: int in_alignof;
      /* The level of nesting inside "sizeof".  */
      int in_sizeof;
      
    -+/* The level of nesting inside "elementsof".  */
    -+int in_elementsof;
    ++/* The level of nesting inside "nelementsof".  */
    ++int in_nelementsof;
     +
      /* 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 *
        if (TREE_CODE (ref) == FUNCTION_DECL && !in_alignof)
          {
     -      if (!in_sizeof && !in_typeof)
    -+      if (!in_sizeof && !in_typeof && !in_elementsof)
    ++      if (!in_sizeof && !in_typeof && !in_nelementsof)
      	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_elementsof).  */
    ++  /* The level seen at (in_sizeof + in_typeof + in_nelementsof).  */
        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_elementsof;
    ++  t->level = in_sizeof + in_typeof + in_nelementsof;
        t->next = maybe_used_decls;
        maybe_used_decls = t;
      }
    @@ gcc/c/c-typeck.cc: void
      {
        struct maybe_used_decl *p = maybe_used_decls;
     -  int cur_level = in_sizeof + in_typeof;
    -+  int cur_level = in_sizeof + in_typeof + in_elementsof;
    ++  int cur_level = in_sizeof + in_typeof + in_nelementsof;
        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 var;
     +}
     +
    -+/* Return the result of elementsof applied to EXPR.  */
    ++/* Return the result of nelementsof applied to EXPR.  */
     +
     +struct c_expr
    -+c_expr_elementsof_expr (location_t loc, struct c_expr expr)
    ++c_expr_nelementsof_expr (location_t loc, struct c_expr expr)
     +{
     +  struct c_expr ret;
     +  if (expr.value == error_mark_node)
    @@ gcc/c/c-typeck.cc: c_expr_sizeof_type (location_t loc, struct c_type_name *t)
     +
     +      tree folded_expr = c_fully_fold (expr.value, require_constant_value,
     +				       &expr_const_operands);
    -+      ret.value = c_elementsof_type (loc, TREE_TYPE (folded_expr));
    ++      ret.value = c_nelementsof_type (loc, TREE_TYPE (folded_expr));
     +      c_last_sizeof_arg = expr.value;
     +      c_last_sizeof_loc = loc;
    -+      ret.original_code = ELEMENTSOF_EXPR;
    ++      ret.original_code = NELEMENTSOF_EXPR;
     +      ret.original_type = NULL;
     +      ret.m_decimal = 0;
     +      if (is_top_array_vla (TREE_TYPE (folded_expr)))
     +	{
    -+	  /* elementsof is evaluated when given a vla.  */
    ++	  /* nelementsof 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 elementsof applied to T, a structure for the type
    -+   name passed to elementsof (rather than the type itself).  LOC is the
    ++/* Return the result of nelementsof applied to T, a structure for the type
    ++   name passed to nelementsof (rather than the type itself).  LOC is the
     +   location of the original expression.  */
     +
     +struct c_expr
    -+c_expr_elementsof_type (location_t loc, struct c_type_name *t)
    ++c_expr_nelementsof_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_elementsof_type (loc, type);
    ++  ret.value = c_nelementsof_type (loc, type);
     +  c_last_sizeof_arg = type;
     +  c_last_sizeof_loc = loc;
    -+  ret.original_code = ELEMENTSOF_EXPR;
    ++  ret.original_code = NELEMENTSOF_EXPR;
     +  ret.original_type = NULL;
     +  ret.m_decimal = 0;
     +  if (type == error_mark_node)
    @@ 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 elementsof does not get folded to a constant by
    ++	 the result of nelementsof 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 elementsof call is inside
    ++	 arrays must not be applied when this nelementsof 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 ("__elementsof__", ELEMENTSOF_EXPR, "lz", OVL_OP_FLAG_UNARY)
    ++DEF_OPERATOR ("__nelementsof__", NELEMENTSOF_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/doc/extend.texi: If the operand of the @code{__alignof__} expression is a fu
      the expression evaluates to the alignment of the function which may
      be specified by attribute @code{aligned} (@pxref{Common Function Attributes}).
      
    -+@node elementsof
    ++@node nelementsof
     +@section Determining the Number of Elements of Arrays
    -+@cindex elementsof
    ++@cindex nelementsof
     +@cindex number of elements
     +
     +The keyword @code{__elemetsf__} determines the length of an array operand,
    @@ gcc/target.h: enum type_context_kind {
        TCTX_ALIGNOF,
      
     +  /* Directly measuring the number of elements of array T.  */
    -+  TCTX_ELEMENTSOF,
    ++  TCTX_NELEMENTSOF,
     +
        /* Creating objects of type T with static storage duration.  */
        TCTX_STATIC_STORAGE,
      
     
    - ## gcc/testsuite/gcc.dg/elementsof-compile.c (new) ##
    + ## gcc/testsuite/gcc.dg/nelementsof-compile.c (new) ##
     @@
     +/* { dg-do compile } */
     +/* { dg-options "-Wno-declaration-after-statement -Wno-pedantic -Wno-vla" } */
    @@ gcc/testsuite/gcc.dg/elementsof-compile.c (new)
     +static int w[] = {1, 2, 3};
     +
     +static int z[0];
    -+static int y[__elementsof__(z)];
    ++static int y[__nelementsof__(z)];
     +
     +void
     +automatic(void)
     +{
    -+  __elementsof__ (w);
    ++  __nelementsof__ (w);
     +}
     +
     +void
     +incomplete (int p[])
     +{
    -+  __elementsof__ (x);  /* { dg-error "incomplete" } */
    ++  __nelementsof__ (x);  /* { dg-error "incomplete" } */
     +
     +  /* We want to support the following one in the future,
     +     but for now it should fail.  */
    -+  __elementsof__ (p);  /* { dg-error "invalid" } */
    ++  __nelementsof__ (p);  /* { dg-error "invalid" } */
     +}
     +
     +void
    @@ gcc/testsuite/gcc.dg/elementsof-compile.c (new)
     +    int fam[];
     +  } s;
     +
    -+  __elementsof__ (s.fam); /* { dg-error "incomplete" } */
    ++  __nelementsof__ (s.fam); /* { dg-error "incomplete" } */
     +}
     +
    -+void fix_fix (int i, char (*a)[3][5], int (*x)[__elementsof__ (*a)]);
    -+void fix_var (int i, char (*a)[3][i], int (*x)[__elementsof__ (*a)]);
    -+void fix_uns (int i, char (*a)[3][*], int (*x)[__elementsof__ (*a)]);
    ++void fix_fix (int i, char (*a)[3][5], int (*x)[__nelementsof__ (*a)]);
    ++void fix_var (int i, char (*a)[3][i], int (*x)[__nelementsof__ (*a)]);
    ++void fix_uns (int i, char (*a)[3][*], int (*x)[__nelementsof__ (*a)]);
     +
     +void
     +func (void)
    @@ gcc/testsuite/gcc.dg/elementsof-compile.c (new)
     +    int x[3];
     +  } s;
     +
    -+  __elementsof__ (x); /* { dg-error "invalid" } */
    -+  __elementsof__ (int); /* { dg-error "invalid" } */
    -+  __elementsof__ (s); /* { dg-error "invalid" } */
    -+  __elementsof__ (struct s); /* { dg-error "invalid" } */
    -+  __elementsof__ (&x); /* { dg-error "invalid" } */
    -+  __elementsof__ (p); /* { dg-error "invalid" } */
    -+  __elementsof__ (int *); /* { dg-error "invalid" } */
    -+  __elementsof__ (&s.x); /* { dg-error "invalid" } */
    -+  __elementsof__ (int (*)[3]); /* { dg-error "invalid" } */
    ++  __nelementsof__ (x); /* { dg-error "invalid" } */
    ++  __nelementsof__ (int); /* { dg-error "invalid" } */
    ++  __nelementsof__ (s); /* { dg-error "invalid" } */
    ++  __nelementsof__ (struct s); /* { dg-error "invalid" } */
    ++  __nelementsof__ (&x); /* { dg-error "invalid" } */
    ++  __nelementsof__ (p); /* { dg-error "invalid" } */
    ++  __nelementsof__ (int *); /* { dg-error "invalid" } */
    ++  __nelementsof__ (&s.x); /* { dg-error "invalid" } */
    ++  __nelementsof__ (int (*)[3]); /* { dg-error "invalid" } */
     +}
     +
     +static int f1();
    @@ gcc/testsuite/gcc.dg/elementsof-compile.c (new)
     +{
     +  int b[n][n];
     +
    -+  __elementsof__ (a[f1()]);
    -+  __elementsof__ (b[f2()]);
    ++  __nelementsof__ (a[f1()]);
    ++  __nelementsof__ (b[f2()]);
     +}
     +
     +void
     +no_parens(void)
     +{
    -+  __elementsof__ a;
    -+  __elementsof__ *a;
    -+  __elementsof__ (int [3]) {};
    ++  __nelementsof__ a;
    ++  __nelementsof__ *a;
    ++  __nelementsof__ (int [3]) {};
     +
    -+  __elementsof__ int [3]; /* { dg-error "expected expression before" } */
    ++  __nelementsof__ int [3]; /* { dg-error "expected expression before" } */
     +}
     +
     +void
    @@ gcc/testsuite/gcc.dg/elementsof-compile.c (new)
     +{
     +  int n = 7;
     +
    -+  _Static_assert (__elementsof__ (int [3][n]) == 3);
    -+  _Static_assert (__elementsof__ (int [n][3]) == 7); /* { dg-error "not constant" } */
    -+  _Static_assert (__elementsof__ (int [0][3]) == 0);
    -+  _Static_assert (__elementsof__ (int [0]) == 0);
    ++  _Static_assert (__nelementsof__ (int [3][n]) == 3);
    ++  _Static_assert (__nelementsof__ (int [n][3]) == 7); /* { dg-error "not constant" } */
    ++  _Static_assert (__nelementsof__ (int [0][3]) == 0);
    ++  _Static_assert (__nelementsof__ (int [0]) == 0);
     +
    -+  /* FIXME: elementsof(int [0][n]) should result in a constant expression.  */
    -+  _Static_assert (__elementsof__ (int [0][n]) == 0); /* { dg-error "not constant" } */
    ++  /* FIXME: nelementsof(int [0][n]) should result in a constant expression.  */
    ++  _Static_assert (__nelementsof__ (int [0][n]) == 0); /* { dg-error "not constant" } */
     +}
     
    - ## gcc/testsuite/gcc.dg/elementsof-vla.c (new) ##
    + ## gcc/testsuite/gcc.dg/nelementsof-vla.c (new) ##
     @@
     +/* { dg-do compile } */
     +/* { dg-options "-Wno-pedantic -Wvla-parameter" } */
     +
     +void fix_fix (int i,
     +	      char (*a)[3][5],
    -+	      int (*x)[__elementsof__ (*a)]);
    ++	      int (*x)[__nelementsof__ (*a)]);
     +void fix_var (int i,
     +	      char (*a)[3][i], /* dg-warn "variable" */
    -+	      int (*x)[__elementsof__ (*a)]);
    ++	      int (*x)[__nelementsof__ (*a)]);
     +void fix_uns (int i,
     +	      char (*a)[3][*],
    -+	      int (*x)[__elementsof__ (*a)]);
    ++	      int (*x)[__nelementsof__ (*a)]);
     +
     +void zro_fix (int i,
     +	      char (*a)[0][5],
    -+	      int (*x)[__elementsof__ (*a)]);
    ++	      int (*x)[__nelementsof__ (*a)]);
     +void zro_var (int i,
     +	      char (*a)[0][i], /* dg-warn "variable" */
    -+	      int (*x)[__elementsof__ (*a)]);
    ++	      int (*x)[__nelementsof__ (*a)]);
     +void zro_uns (int i,
     +	      char (*a)[0][*],
    -+	      int (*x)[__elementsof__ (*a)]);
    ++	      int (*x)[__nelementsof__ (*a)]);
     +
     +void var_fix (int i,
     +	      char (*a)[i][5], /* dg-warn "variable" */
    -+	      int (*x)[__elementsof__ (*a)]); /* dg-warn "variable" */
    ++	      int (*x)[__nelementsof__ (*a)]); /* dg-warn "variable" */
     +void var_var (int i,
     +	      char (*a)[i][i], /* dg-warn "variable" */
    -+	      int (*x)[__elementsof__ (*a)]); /* dg-warn "variable" */
    ++	      int (*x)[__nelementsof__ (*a)]); /* dg-warn "variable" */
     +void var_uns (int i,
     +	      char (*a)[i][*], /* dg-warn "variable" */
    -+	      int (*x)[__elementsof__ (*a)]); /* dg-warn "variable" */
    ++	      int (*x)[__nelementsof__ (*a)]); /* dg-warn "variable" */
     +
     +void uns_fix (int i,
     +	      char (*a)[*][5],
    -+	      int (*x)[__elementsof__ (*a)]);
    ++	      int (*x)[__nelementsof__ (*a)]);
     +void uns_var (int i,
     +	      char (*a)[*][i], /* dg-warn "variable" */
    -+	      int (*x)[__elementsof__ (*a)]);
    ++	      int (*x)[__nelementsof__ (*a)]);
     +void uns_uns (int i,
     +	      char (*a)[*][*],
    -+	      int (*x)[__elementsof__ (*a)]);
    ++	      int (*x)[__nelementsof__ (*a)]);
     +
     +// Can't test due to bug: <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=116284>
     +//static int z2[0];
    -+//static int y2[__elementsof__(z2)];
    ++//static int y2[__nelementsof__(z2)];
     
    - ## gcc/testsuite/gcc.dg/elementsof.c (new) ##
    + ## gcc/testsuite/gcc.dg/nelementsof.c (new) ##
     @@
     +/* { dg-do run } */
     +/* { dg-options "-Wno-declaration-after-statement -Wno-pedantic -Wno-vla" } */
    @@ gcc/testsuite/gcc.dg/elementsof.c (new)
     +{
     +  short a[7];
     +
    -+  static_assert (__elementsof__ (a) == 7);
    -+  static_assert (__elementsof__ (long [0]) == 0);
    -+  static_assert (__elementsof__ (unsigned [99]) == 99);
    ++  static_assert (__nelementsof__ (a) == 7);
    ++  static_assert (__nelementsof__ (long [0]) == 0);
    ++  static_assert (__nelementsof__ (unsigned [99]) == 99);
     +}
     +
     +void
    @@ gcc/testsuite/gcc.dg/elementsof.c (new)
     +  int a[] = {1, 2, 3};
     +  int z[] = {};
     +
    -+  static_assert (__elementsof__ (a) == 3);
    -+  static_assert (__elementsof__ (z) == 0);
    ++  static_assert (__nelementsof__ (a) == 3);
    ++  static_assert (__nelementsof__ (z) == 0);
     +}
     +
     +void
    @@ gcc/testsuite/gcc.dg/elementsof.c (new)
     +  unsigned n;
     +
     +  n = 99;
    -+  assert (__elementsof__ (short [n - 10]) == 99 - 10);
    ++  assert (__nelementsof__ (short [n - 10]) == 99 - 10);
     +
     +  int v[n / 2];
    -+  assert (__elementsof__ (v) == 99 / 2);
    ++  assert (__nelementsof__ (v) == 99 / 2);
     +
     +  n = 0;
     +  int z[n];
    -+  assert (__elementsof__ (z) == 0);
    ++  assert (__nelementsof__ (z) == 0);
     +}
     +
     +void
    @@ gcc/testsuite/gcc.dg/elementsof.c (new)
     +    int a[8];
     +  } s;
     +
    -+  static_assert (__elementsof__ (s.a) == 8);
    ++  static_assert (__nelementsof__ (s.a) == 8);
     +}
     +
     +void
    @@ gcc/testsuite/gcc.dg/elementsof.c (new)
     +  int i;
     +
     +  i = 7;
    -+  assert (__elementsof__ (struct {int x;}[i++]) == 7);
    ++  assert (__nelementsof__ (struct {int x;}[i++]) == 7);
     +  assert (i == 7 + 1);
     +
     +  int v[i];
     +  int (*p)[i];
     +  p = &v;
    -+  assert (__elementsof__ (*p++) == i);
    ++  assert (__nelementsof__ (*p++) == i);
     +  assert (p - 1 == &v);
     +}
     +
    @@ gcc/testsuite/gcc.dg/elementsof.c (new)
     +  int i;
     +
     +  i = 3;
    -+  static_assert (__elementsof__ (struct {int x[i++];}[3]) == 3);
    ++  static_assert (__nelementsof__ (struct {int x[i++];}[3]) == 3);
     +  assert (i == 3);
     +}
     +
    @@ gcc/testsuite/gcc.dg/elementsof.c (new)
     +array_noeval (void)
     +{
     +  long a[5];
    -+  long (*p)[__elementsof__ (a)];
    ++  long (*p)[__nelementsof__ (a)];
     +
     +  p = &a;
    -+  static_assert (__elementsof__ (*p++) == 5);
    ++  static_assert (__nelementsof__ (*p++) == 5);
     +  assert (p == &a);
     +}
     +
    @@ gcc/testsuite/gcc.dg/elementsof.c (new)
     +{
     +  int i;
     +
    -+  static_assert (__elementsof__ (int [0][4]) == 0);
    ++  static_assert (__nelementsof__ (int [0][4]) == 0);
     +  i = 3;
    -+  assert (__elementsof__ (int [0][i]) == 0);
    ++  assert (__nelementsof__ (int [0][i]) == 0);
     +}
     +
     +void
    @@ gcc/testsuite/gcc.dg/elementsof.c (new)
     +{
     +  int i;
     +
    -+  static_assert (__elementsof__ (int [7][4]) == 7);
    ++  static_assert (__nelementsof__ (int [7][4]) == 7);
     +  i = 3;
    -+  static_assert (__elementsof__ (int [7][i]) == 7);
    ++  static_assert (__nelementsof__ (int [7][i]) == 7);
     +}
     +
     +void
    @@ gcc/testsuite/gcc.dg/elementsof.c (new)
     +  int i, j;
     +
     +  i = 7;
    -+  assert (__elementsof__ (int [i++][4]) == 7);
    ++  assert (__nelementsof__ (int [i++][4]) == 7);
     +  assert (i == 7 + 1);
     +
     +  i = 9;
     +  j = 3;
    -+  assert (__elementsof__ (int [i++][j]) == 9);
    ++  assert (__nelementsof__ (int [i++][j]) == 9);
     +  assert (i == 9 + 1);
     +}
     +
    @@ gcc/testsuite/gcc.dg/elementsof.c (new)
     +  int a[7];
     +  int v[n];
     +
    -+  static_assert (__elementsof__ a == 7); 
    -+  assert (__elementsof__ v == 3); 
    ++  static_assert (__nelementsof__ a == 7); 
    ++  assert (__nelementsof__ v == 3); 
     +}
     +
     +int

base-commit: 4d44f3fc387815eb232d7757352857993a1d21d9
-- 
2.45.2


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 318+ messages in thread

* [PATCH v10 1/3] gcc/: Rename array_type_nelts() => array_type_nelts_minus_one()
  2024-08-19 10:58   ` [PATCH v10 0/3] c: Add __nelementsof__ operator Alejandro Colomar
@ 2024-08-19 10:58     ` Alejandro Colomar
  2024-08-19 16:46       ` Jason Merrill
  2024-08-19 10:58     ` [PATCH v10 2/3] Merge definitions of array_type_nelts_top() Alejandro Colomar
  2024-08-19 10:58     ` [PATCH v10 3/3] c: Add __nelementsof__ operator Alejandro Colomar
  2 siblings, 1 reply; 318+ messages in thread
From: Alejandro Colomar @ 2024-08-19 10:58 UTC (permalink / raw)
  To: gcc-patches
  Cc: Alejandro Colomar, Xavier Del Campo Romero, Martin Uecker,
	Joseph Myers, Gabriel Ravier, Jakub Jelinek, Kees Cook,
	Qing Zhao, Jens Gustedt, David Brown, Florian Weimer,
	Andreas Schwab, Timm Baeder, Daniel Plakosh, A. Jiang,
	Eugene Zelenko, Aaron Ballman, Paul Koning, Daniel Lundin,
	Nikolaos Strimpas, JeanHeyd Meneide, Fernando Borretti,
	Jonathan Protzenko, Chris Bazley, Ville Voutilainen,
	Alex Celeste, Jakub Łukasiewicz, Richard Biener

[-- Attachment #1: Type: text/plain, Size: 12760 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, array_type_nelts_minus_one):
	* tree.h (array_type_nelts, array_type_nelts_minus_one):
	* expr.cc (count_type_elements):
	* config/aarch64/aarch64.cc
	(pure_scalable_type_info::analyze_array):
	* config/i386/i386.cc (ix86_canonical_va_list_type):
	Rename array_type_nelts() => array_type_nelts_minus_one()
	The old name was misleading.

gcc/c/ChangeLog:

	* c-decl.cc (one_element_array_type_p, get_parm_array_spec):
	* c-fold.cc (c_fold_array_ref):
	Rename array_type_nelts() => array_type_nelts_minus_one()

gcc/cp/ChangeLog:

	* decl.cc (reshape_init_array):
	* init.cc
	(build_zero_init_1):
	(build_value_init_noctor):
	(build_vec_init):
	(build_delete):
	* lambda.cc (add_capture):
	* tree.cc (array_type_nelts_top):
	Rename array_type_nelts() => array_type_nelts_minus_one()

gcc/fortran/ChangeLog:

	* trans-array.cc (structure_alloc_comps):
	* trans-openmp.cc
	(gfc_walk_alloc_comps):
	(gfc_omp_clause_linear_ctor):
	Rename array_type_nelts() => array_type_nelts_minus_one()

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 bfd7bcdef7c..f787347b56e 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 d06e2141e56..e3ba9f533fe 100644
--- a/gcc/config/i386/i386.cc
+++ b/gcc/config/i386/i386.cc
@@ -24382,7 +24382,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 f23b635aec9..b6a3cfdf8c4 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 ea5fff2e0c2..47e0447cae5 100644
--- a/gcc/fortran/trans-array.cc
+++ b/gcc/fortran/trans-array.cc
@@ -9728,7 +9728,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] 318+ messages in thread

* [PATCH v10 2/3] Merge definitions of array_type_nelts_top()
  2024-08-19 10:58   ` [PATCH v10 0/3] c: Add __nelementsof__ operator Alejandro Colomar
  2024-08-19 10:58     ` [PATCH v10 1/3] gcc/: Rename array_type_nelts() => array_type_nelts_minus_one() Alejandro Colomar
@ 2024-08-19 10:58     ` Alejandro Colomar
  2024-08-19 10:58     ` [PATCH v10 3/3] c: Add __nelementsof__ operator Alejandro Colomar
  2 siblings, 0 replies; 318+ messages in thread
From: Alejandro Colomar @ 2024-08-19 10:58 UTC (permalink / raw)
  To: gcc-patches
  Cc: Alejandro Colomar, Xavier Del Campo Romero, Martin Uecker,
	Joseph Myers, Gabriel Ravier, Jakub Jelinek, Kees Cook,
	Qing Zhao, Jens Gustedt, David Brown, Florian Weimer,
	Andreas Schwab, Timm Baeder, Daniel Plakosh, A. Jiang,
	Eugene Zelenko, Aaron Ballman, Paul Koning, Daniel Lundin,
	Nikolaos Strimpas, JeanHeyd Meneide, Fernando Borretti,
	Jonathan Protzenko, Chris Bazley, Ville Voutilainen,
	Alex Celeste, Jakub Łukasiewicz

[-- Attachment #1: Type: text/plain, Size: 4883 bytes --]

There were two identical definitions, and none of them are available
where they are needed for implementing __nelementsof__.  Merge them, and
provide the single definition in gcc/tree.{h,cc}, where it's available
for __nelementsof__, 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 a53fbcb43ec..39f23b04a78 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -8103,7 +8103,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] 318+ messages in thread

* [PATCH v10 3/3] c: Add __nelementsof__ operator
  2024-08-19 10:58   ` [PATCH v10 0/3] c: Add __nelementsof__ operator Alejandro Colomar
  2024-08-19 10:58     ` [PATCH v10 1/3] gcc/: Rename array_type_nelts() => array_type_nelts_minus_one() Alejandro Colomar
  2024-08-19 10:58     ` [PATCH v10 2/3] Merge definitions of array_type_nelts_top() Alejandro Colomar
@ 2024-08-19 10:58     ` Alejandro Colomar
  2 siblings, 0 replies; 318+ messages in thread
From: Alejandro Colomar @ 2024-08-19 10:58 UTC (permalink / raw)
  To: gcc-patches
  Cc: Alejandro Colomar, Xavier Del Campo Romero, Martin Uecker,
	Joseph Myers, Gabriel Ravier, Jakub Jelinek, Kees Cook,
	Qing Zhao, Jens Gustedt, David Brown, Florian Weimer,
	Andreas Schwab, Timm Baeder, Daniel Plakosh, A. Jiang,
	Eugene Zelenko, Aaron Ballman, Paul Koning, Daniel Lundin,
	Nikolaos Strimpas, JeanHeyd Meneide, Fernando Borretti,
	Jonathan Protzenko, Chris Bazley, Ville Voutilainen,
	Alex Celeste, Jakub Łukasiewicz

[-- Attachment #1: Type: text/plain, Size: 30885 bytes --]

This operator is similar to sizeof but can only be applied to an array,
and returns its number of elements.

FUTURE DIRECTIONS:

-  We should make it work with array parameters to functions,
   and somehow magically return the number of elements 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>
Cc: Daniel Plakosh <dplakosh@cert.org>
Cc: "A. Jiang" <de34@live.cn>
Cc: Eugene Zelenko <eugene.zelenko@gmail.com>
Cc: Aaron Ballman <aaron.ballman@intel.com>
Cc: Paul Koning <paulkoning@comcast.net>
Cc: Daniel Lundin <daniel.lundin.mail@gmail.com>
Cc: Nikolaos Strimpas <Strnik86@protonmail.com>
Cc: JeanHeyd Meneide <phdofthehouse@gmail.com>
Cc: Fernando Borretti <fernando@borretti.me>
Cc: Jonathan Protzenko <jonathan.protzenko@ens-lyon.org>
Cc: Chris Bazley <Chris.Bazley@arm.com>
Cc: Ville Voutilainen <ville.voutilainen@gmail.com>
Cc: Alex Celeste <alexg.nvfp@gmail.com>
Cc: Jakub Łukasiewicz <jakublukasiewicz@outlook.com>

gcc/ChangeLog:

	* doc/extend.texi: Document __nelementsof__ operator.
	* target.h (enum type_context_kind): Add __nelementsof__ operator.

gcc/c-family/ChangeLog:

	* c-common.h:
	* c-common.def:
	* c-common.cc (c_nelementsof_type): Add __nelementsof__ operator.

gcc/c/ChangeLog:

	* c-tree.h
	(c_expr_nelementsof_expr, c_expr_nelementsof_type):
	* c-decl.cc
	(start_struct, finish_struct):
	(start_enum, finish_enum):
	* c-parser.cc
	(c_parser_sizeof_expression):
	(c_parser_nelementsof_expression):
	(c_parser_sizeof_or_nelementsof_expression):
	(c_parser_unary_expression):
	* c-typeck.cc
	(build_external_ref):
	(record_maybe_used_decl, pop_maybe_used):
	(is_top_array_vla):
	(c_expr_nelementsof_expr, c_expr_nelementsof_type):
	Add __nelementsof__operator.

gcc/cp/ChangeLog:

	* operators.def: Add __nelementsof__ operator.

gcc/testsuite/ChangeLog:

	* gcc.dg/nelementsof-compile.c:
	* gcc.dg/nelementsof-vla.c:
	* gcc.dg/nelementsof.c: Add tests for __nelementsof__ operator.

Link: https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3313.pdf
Link: https://inbox.sourceware.org/gcc/M8S4oQy--3-2@tutanota.com/T/
Link: https://github.com/llvm/llvm-project/issues/102836
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                            |  22 ++-
 gcc/c/c-parser.cc                          |  62 +++++++--
 gcc/c/c-tree.h                             |   4 +
 gcc/c/c-typeck.cc                          | 118 +++++++++++++++-
 gcc/cp/operators.def                       |   1 +
 gcc/doc/extend.texi                        |  30 +++++
 gcc/target.h                               |   3 +
 gcc/testsuite/gcc.dg/nelementsof-compile.c | 115 ++++++++++++++++
 gcc/testsuite/gcc.dg/nelementsof-vla.c     |  46 +++++++
 gcc/testsuite/gcc.dg/nelementsof.c         | 150 +++++++++++++++++++++
 13 files changed, 558 insertions(+), 24 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/nelementsof-compile.c
 create mode 100644 gcc/testsuite/gcc.dg/nelementsof-vla.c
 create mode 100644 gcc/testsuite/gcc.dg/nelementsof.c

diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
index e7e371fd26f..188bb9b65ef 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 },
+  { "__nelementsof__",	RID_NELEMENTSOF, 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 lementsof keyword:
+   Return the number of elements of an array.  */
+
+tree
+c_nelementsof_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 %<nelementsof%> to type %qT", type);
+      return error_mark_node;
+    }
+  if (!COMPLETE_TYPE_P (type))
+    {
+      error_at (loc,
+		"invalid application of %<nelementsof%> 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..12ee0d2adb3 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 'nelementsof' expression.  */
+DEFTREECODE (NELEMENTSOF_EXPR, "nelementsof_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..3b36d8b6513 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_NELEMENTSOF,
   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_nelementsof_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..73449292203 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -8943,12 +8943,17 @@ 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_nelementsof))
     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"
+		       : "nelementsof"))));
 
   if (in_underspecified_init)
     error_at (loc, "%qT defined in underspecified object initializer", ref);
@@ -9908,7 +9913,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_nelementsof)
 	struct_parse_info->struct_types.safe_push (t);
      }
 
@@ -10082,12 +10087,17 @@ 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_nelementsof))
     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"
+		       : "nelementsof"))));
 
   if (in_underspecified_init)
     error_at (loc, "%qT defined in underspecified object initializer",
@@ -10281,7 +10291,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_nelementsof)
     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..d6031d947a8 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_nelementsof_expression (parser, RID_SIZEOF)              \
+)
 
+#define c_parser_nelementsof_expression(parser)                               \
+(                                                                             \
+  c_parser_sizeof_or_nelementsof_expression (parser, RID_NELEMENTSOF)         \
+)
+\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,8 @@ 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_nelementsof_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 +9920,8 @@ c_parser_unary_expression (c_parser *parser)
     case CPP_KEYWORD:
       switch (c_parser_peek_token (parser)->keyword)
 	{
+	case RID_NELEMENTSOF:
+	  return c_parser_nelementsof_expression (parser);
 	case RID_SIZEOF:
 	  return c_parser_sizeof_expression (parser);
 	case RID_ALIGNOF:
@@ -9948,12 +9961,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_nelementsof_expression (c_parser *parser, enum rid rid)
 {
+  const char *op_name = (rid == RID_NELEMENTSOF) ? "nelementsof" : "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 +9976,10 @@ c_parser_sizeof_expression (c_parser *parser)
 
   c_parser_consume_token (parser);
   c_inhibit_evaluation_warnings++;
-  in_sizeof++;
+  if (rid == RID_NELEMENTSOF)
+    in_nelementsof++;
+  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 +9998,10 @@ c_parser_sizeof_expression (c_parser *parser)
 	{
 	  struct c_expr ret;
 	  c_inhibit_evaluation_warnings--;
-	  in_sizeof--;
+	  if (rid == RID_NELEMENTSOF)
+	    in_nelementsof--;
+	  else
+	    in_sizeof--;
 	  ret.set_error ();
 	  ret.original_code = ERROR_MARK;
 	  ret.original_type = NULL;
@@ -9993,31 +10013,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_NELEMENTSOF)
+	{
+	  in_nelementsof--;
+	  result = c_expr_nelementsof_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_NELEMENTSOF)
+	in_nelementsof--;
+      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_NELEMENTSOF)
+	result = c_expr_nelementsof_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..a0149ccae77 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_nelementsof;
 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_nelementsof_expr (location_t, struct c_expr);
+extern struct c_expr c_expr_nelementsof_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..651e5c15b87 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 "nelementsof".  */
+int in_nelementsof;
+
 /* 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_nelementsof)
 	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_nelementsof).  */
   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_nelementsof;
   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_nelementsof;
   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 nelementsof applied to EXPR.  */
+
+struct c_expr
+c_expr_nelementsof_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_nelementsof_type (loc, TREE_TYPE (folded_expr));
+      c_last_sizeof_arg = expr.value;
+      c_last_sizeof_loc = loc;
+      ret.original_code = NELEMENTSOF_EXPR;
+      ret.original_type = NULL;
+      ret.m_decimal = 0;
+      if (is_top_array_vla (TREE_TYPE (folded_expr)))
+	{
+	  /* nelementsof 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 nelementsof applied to T, a structure for the type
+   name passed to nelementsof (rather than the type itself).  LOC is the
+   location of the original expression.  */
+
+struct c_expr
+c_expr_nelementsof_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_nelementsof_type (loc, type);
+  c_last_sizeof_arg = type;
+  c_last_sizeof_loc = loc;
+  ret.original_code = NELEMENTSOF_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 nelementsof 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 nelementsof 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..7f1d24779c8 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 ("__nelementsof__", NELEMENTSOF_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 0ea7a87053c..85bcb059730 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -10481,6 +10481,36 @@ 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 nelementsof
+@section Determining the Number of Elements of Arrays
+@cindex nelementsof
+@cindex number of elements
+
+The keyword @code{__elemetsf__} 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 parenthesized complete array type name
+or an expression of such a type.
+For example:
+
+@smallexample
+int a[n];
+__elemetsf__ (a);  // returns n
+__elemetsf__ (int [7][3]);  // returns 7
+@end smallexample
+
+The result of this operator is an integer constant expression,
+unless the top-level array is a variable-length array.
+The operand is only evaluated
+if the top-level array is a variable-length array.
+For example:
+
+@smallexample
+__elemetsf__ (int [7][n++]);  // integer constant expression
+__elemetsf__ (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..09245d70c1f 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 number of elements of array T.  */
+  TCTX_NELEMENTSOF,
+
   /* Creating objects of type T with static storage duration.  */
   TCTX_STATIC_STORAGE,
 
diff --git a/gcc/testsuite/gcc.dg/nelementsof-compile.c b/gcc/testsuite/gcc.dg/nelementsof-compile.c
new file mode 100644
index 00000000000..211b63fa7b5
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/nelementsof-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[__nelementsof__(z)];
+
+void
+automatic(void)
+{
+  __nelementsof__ (w);
+}
+
+void
+incomplete (int p[])
+{
+  __nelementsof__ (x);  /* { dg-error "incomplete" } */
+
+  /* We want to support the following one in the future,
+     but for now it should fail.  */
+  __nelementsof__ (p);  /* { dg-error "invalid" } */
+}
+
+void
+fam (void)
+{
+  struct {
+    int x;
+    int fam[];
+  } s;
+
+  __nelementsof__ (s.fam); /* { dg-error "incomplete" } */
+}
+
+void fix_fix (int i, char (*a)[3][5], int (*x)[__nelementsof__ (*a)]);
+void fix_var (int i, char (*a)[3][i], int (*x)[__nelementsof__ (*a)]);
+void fix_uns (int i, char (*a)[3][*], int (*x)[__nelementsof__ (*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;
+
+  __nelementsof__ (x); /* { dg-error "invalid" } */
+  __nelementsof__ (int); /* { dg-error "invalid" } */
+  __nelementsof__ (s); /* { dg-error "invalid" } */
+  __nelementsof__ (struct s); /* { dg-error "invalid" } */
+  __nelementsof__ (&x); /* { dg-error "invalid" } */
+  __nelementsof__ (p); /* { dg-error "invalid" } */
+  __nelementsof__ (int *); /* { dg-error "invalid" } */
+  __nelementsof__ (&s.x); /* { dg-error "invalid" } */
+  __nelementsof__ (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];
+
+  __nelementsof__ (a[f1()]);
+  __nelementsof__ (b[f2()]);
+}
+
+void
+no_parens(void)
+{
+  __nelementsof__ a;
+  __nelementsof__ *a;
+  __nelementsof__ (int [3]) {};
+
+  __nelementsof__ int [3]; /* { dg-error "expected expression before" } */
+}
+
+void
+const_expr(void)
+{
+  int n = 7;
+
+  _Static_assert (__nelementsof__ (int [3][n]) == 3);
+  _Static_assert (__nelementsof__ (int [n][3]) == 7); /* { dg-error "not constant" } */
+  _Static_assert (__nelementsof__ (int [0][3]) == 0);
+  _Static_assert (__nelementsof__ (int [0]) == 0);
+
+  /* FIXME: nelementsof(int [0][n]) should result in a constant expression.  */
+  _Static_assert (__nelementsof__ (int [0][n]) == 0); /* { dg-error "not constant" } */
+}
diff --git a/gcc/testsuite/gcc.dg/nelementsof-vla.c b/gcc/testsuite/gcc.dg/nelementsof-vla.c
new file mode 100644
index 00000000000..0cd4dfd37fa
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/nelementsof-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)[__nelementsof__ (*a)]);
+void fix_var (int i,
+	      char (*a)[3][i], /* dg-warn "variable" */
+	      int (*x)[__nelementsof__ (*a)]);
+void fix_uns (int i,
+	      char (*a)[3][*],
+	      int (*x)[__nelementsof__ (*a)]);
+
+void zro_fix (int i,
+	      char (*a)[0][5],
+	      int (*x)[__nelementsof__ (*a)]);
+void zro_var (int i,
+	      char (*a)[0][i], /* dg-warn "variable" */
+	      int (*x)[__nelementsof__ (*a)]);
+void zro_uns (int i,
+	      char (*a)[0][*],
+	      int (*x)[__nelementsof__ (*a)]);
+
+void var_fix (int i,
+	      char (*a)[i][5], /* dg-warn "variable" */
+	      int (*x)[__nelementsof__ (*a)]); /* dg-warn "variable" */
+void var_var (int i,
+	      char (*a)[i][i], /* dg-warn "variable" */
+	      int (*x)[__nelementsof__ (*a)]); /* dg-warn "variable" */
+void var_uns (int i,
+	      char (*a)[i][*], /* dg-warn "variable" */
+	      int (*x)[__nelementsof__ (*a)]); /* dg-warn "variable" */
+
+void uns_fix (int i,
+	      char (*a)[*][5],
+	      int (*x)[__nelementsof__ (*a)]);
+void uns_var (int i,
+	      char (*a)[*][i], /* dg-warn "variable" */
+	      int (*x)[__nelementsof__ (*a)]);
+void uns_uns (int i,
+	      char (*a)[*][*],
+	      int (*x)[__nelementsof__ (*a)]);
+
+// Can't test due to bug: <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=116284>
+//static int z2[0];
+//static int y2[__nelementsof__(z2)];
diff --git a/gcc/testsuite/gcc.dg/nelementsof.c b/gcc/testsuite/gcc.dg/nelementsof.c
new file mode 100644
index 00000000000..292311e2822
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/nelementsof.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 (__nelementsof__ (a) == 7);
+  static_assert (__nelementsof__ (long [0]) == 0);
+  static_assert (__nelementsof__ (unsigned [99]) == 99);
+}
+
+void
+automatic(void)
+{
+  int a[] = {1, 2, 3};
+  int z[] = {};
+
+  static_assert (__nelementsof__ (a) == 3);
+  static_assert (__nelementsof__ (z) == 0);
+}
+
+void
+vla (void)
+{
+  unsigned n;
+
+  n = 99;
+  assert (__nelementsof__ (short [n - 10]) == 99 - 10);
+
+  int v[n / 2];
+  assert (__nelementsof__ (v) == 99 / 2);
+
+  n = 0;
+  int z[n];
+  assert (__nelementsof__ (z) == 0);
+}
+
+void
+member (void)
+{
+  struct {
+    int a[8];
+  } s;
+
+  static_assert (__nelementsof__ (s.a) == 8);
+}
+
+void
+vla_eval (void)
+{
+  int i;
+
+  i = 7;
+  assert (__nelementsof__ (struct {int x;}[i++]) == 7);
+  assert (i == 7 + 1);
+
+  int v[i];
+  int (*p)[i];
+  p = &v;
+  assert (__nelementsof__ (*p++) == i);
+  assert (p - 1 == &v);
+}
+
+void
+inner_vla_noeval (void)
+{
+  int i;
+
+  i = 3;
+  static_assert (__nelementsof__ (struct {int x[i++];}[3]) == 3);
+  assert (i == 3);
+}
+
+void
+array_noeval (void)
+{
+  long a[5];
+  long (*p)[__nelementsof__ (a)];
+
+  p = &a;
+  static_assert (__nelementsof__ (*p++) == 5);
+  assert (p == &a);
+}
+
+void
+matrix_zero (void)
+{
+  int i;
+
+  static_assert (__nelementsof__ (int [0][4]) == 0);
+  i = 3;
+  assert (__nelementsof__ (int [0][i]) == 0);
+}
+
+void
+matrix_fixed (void)
+{
+  int i;
+
+  static_assert (__nelementsof__ (int [7][4]) == 7);
+  i = 3;
+  static_assert (__nelementsof__ (int [7][i]) == 7);
+}
+
+void
+matrix_vla (void)
+{
+  int i, j;
+
+  i = 7;
+  assert (__nelementsof__ (int [i++][4]) == 7);
+  assert (i == 7 + 1);
+
+  i = 9;
+  j = 3;
+  assert (__nelementsof__ (int [i++][j]) == 9);
+  assert (i == 9 + 1);
+}
+
+void
+no_parens(void)
+{
+  int n = 3;
+  int a[7];
+  int v[n];
+
+  static_assert (__nelementsof__ a == 7); 
+  assert (__nelementsof__ 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] 318+ messages in thread

* Re: [PATCH v10 1/3] gcc/: Rename array_type_nelts() => array_type_nelts_minus_one()
  2024-08-19 10:58     ` [PATCH v10 1/3] gcc/: Rename array_type_nelts() => array_type_nelts_minus_one() Alejandro Colomar
@ 2024-08-19 16:46       ` Jason Merrill
  2024-08-20 18:09         ` Alejandro Colomar
  0 siblings, 1 reply; 318+ messages in thread
From: Jason Merrill @ 2024-08-19 16:46 UTC (permalink / raw)
  To: Alejandro Colomar, gcc-patches
  Cc: Xavier Del Campo Romero, Martin Uecker, Joseph Myers,
	Gabriel Ravier, Jakub Jelinek, Kees Cook, Qing Zhao,
	Jens Gustedt, David Brown, Florian Weimer, Andreas Schwab,
	Timm Baeder, Daniel Plakosh, A. Jiang, Eugene Zelenko,
	Aaron Ballman, Paul Koning, Daniel Lundin, Nikolaos Strimpas,
	JeanHeyd Meneide, Fernando Borretti, Jonathan Protzenko,
	Chris Bazley, Ville Voutilainen, Alex Celeste,
	Jakub Łukasiewicz, Richard Biener

On 8/19/24 6:58 AM, Alejandro Colomar wrote:
> 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, array_type_nelts_minus_one):
> 	* tree.h (array_type_nelts, array_type_nelts_minus_one):
> 	* expr.cc (count_type_elements):
> 	* config/aarch64/aarch64.cc
> 	(pure_scalable_type_info::analyze_array):
> [etc]

FYI the commit message checker, which you can run yourself as git 
gcc-verify, will reject this for missing descriptions, e.g.

> ERR: missing description of a change: "	* expr.cc (count_type_elements):"
> ERR: missing description of a change: "	(pure_scalable_type_info::analyze_array):"

To avoid this, you can remove the end-of-line colons for changes 
described farther below.

Jason


^ permalink raw reply	[flat|nested] 318+ messages in thread

* Re: [PATCH v10 1/3] gcc/: Rename array_type_nelts() => array_type_nelts_minus_one()
  2024-08-19 16:46       ` Jason Merrill
@ 2024-08-20 18:09         ` Alejandro Colomar
  0 siblings, 0 replies; 318+ messages in thread
From: Alejandro Colomar @ 2024-08-20 18:09 UTC (permalink / raw)
  To: Jason Merrill
  Cc: gcc-patches, Xavier Del Campo Romero, Martin Uecker,
	Joseph Myers, Gabriel Ravier, Jakub Jelinek, Kees Cook,
	Qing Zhao, Jens Gustedt, David Brown, Florian Weimer,
	Andreas Schwab, Timm Baeder, Daniel Plakosh, A. Jiang,
	Eugene Zelenko, Aaron Ballman, Paul Koning, Daniel Lundin,
	Nikolaos Strimpas, JeanHeyd Meneide, Fernando Borretti,
	Jonathan Protzenko, Chris Bazley, Ville Voutilainen,
	Alex Celeste, Jakub Łukasiewicz, Richard Biener

[-- Attachment #1: Type: text/plain, Size: 1401 bytes --]

Hi Jason,

On Mon, Aug 19, 2024 at 12:46:13PM GMT, Jason Merrill wrote:
> On 8/19/24 6:58 AM, Alejandro Colomar wrote:
> > 
> > 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, array_type_nelts_minus_one):
> > 	* tree.h (array_type_nelts, array_type_nelts_minus_one):
> > 	* expr.cc (count_type_elements):
> > 	* config/aarch64/aarch64.cc
> > 	(pure_scalable_type_info::analyze_array):
> > [etc]
> 
> FYI the commit message checker, which you can run yourself as git
> gcc-verify, will reject this for missing descriptions, e.g.

Hmm, thanks!  I've added some changes to that verifier so that I can
use Cc: and Link: tags.

> 
> > ERR: missing description of a change: "	* expr.cc (count_type_elements):"
> > ERR: missing description of a change: "	(pure_scalable_type_info::analyze_array):"
> 
> To avoid this, you can remove the end-of-line colons for changes described
> farther below.

Thanks!

> 
> Jason
> 

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] 318+ messages in thread

* [PATCH v11 0/4] c: Add __nelementsof__ operator
  2024-07-28 14:15 ` [RFC v1 0/2] c: Add _Lengthof operator Alejandro Colomar
                     ` (15 preceding siblings ...)
  2024-08-19 10:58   ` [PATCH v10 0/3] c: Add __nelementsof__ operator Alejandro Colomar
@ 2024-08-20 18:41   ` Alejandro Colomar
  2024-08-20 18:41     ` [PATCH v11 1/4] contrib/: Add support for Cc: and Link: tags Alejandro Colomar
                       ` (3 more replies)
  2024-08-31 14:56   ` [PATCH v12 0/4] " Alejandro Colomar
                     ` (11 subsequent siblings)
  28 siblings, 4 replies; 318+ messages in thread
From: Alejandro Colomar @ 2024-08-20 18:41 UTC (permalink / raw)
  To: gcc-patches
  Cc: Alejandro Colomar, Joseph Myers, Gabriel Ravier, Jakub Jelinek,
	Kees Cook, Qing Zhao, Jens Gustedt, David Brown, Florian Weimer,
	Andreas Schwab, Timm Baeder, Daniel Plakosh, A. Jiang,
	Eugene Zelenko, Aaron Ballman, Paul Koning, Daniel Lundin,
	Nikolaos Strimpas, JeanHeyd Meneide, Fernando Borretti,
	Jonathan Protzenko, Chris Bazley, Ville Voutilainen,
	Alex Celeste, Jakub Łukasiewicz, Douglas McIlroy,
	Jason Merrill, Xavier Del Campo Romero, Martin Uecker

[-- Attachment #1: Type: text/plain, Size: 11721 bytes --]

Hi!

v11 changes:

-  Add patch for the commit checker, to allow Cc: and Link: tags.

-  CC += Doug, Jason

-  Fix changelog entries to pass the checker, following advice from
   Jason to remove some colons.

-  Move Cc: and Link: tags to below the changelog, since thanks to the
   new patch 1/4 they are not warned anymore.  (Except for links longer
   than 100 characters, which still raised a warning, and so I kept
   above the changelog entries, where they don't trigger warnings.)

-  Change s/Co-developed-by/Co-authored-by/, which seems to be what the
   checker expects.

Below is a range-diff against v10.

Have a lovely day!
Alex


Alejandro Colomar (4):
  contrib/: Add support for Cc: and Link: tags
  gcc/: Rename array_type_nelts() => array_type_nelts_minus_one()
  Merge definitions of array_type_nelts_top()
  c: Add __nelementsof__ operator

 contrib/gcc-changelog/git_commit.py        |   5 +-
 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                            |  32 +++--
 gcc/c/c-fold.cc                            |   7 +-
 gcc/c/c-parser.cc                          |  62 +++++++--
 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                        |  30 +++++
 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/nelementsof-compile.c | 115 ++++++++++++++++
 gcc/testsuite/gcc.dg/nelementsof-vla.c     |  46 +++++++
 gcc/testsuite/gcc.dg/nelementsof.c         | 150 +++++++++++++++++++++
 gcc/tree.cc                                |  17 ++-
 gcc/tree.h                                 |   3 +-
 29 files changed, 604 insertions(+), 80 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/nelementsof-compile.c
 create mode 100644 gcc/testsuite/gcc.dg/nelementsof-vla.c
 create mode 100644 gcc/testsuite/gcc.dg/nelementsof.c

Range-diff against v10:
-:  ----------- > 1:  2e851b8f8d2 contrib/: Add support for Cc: and Link: tags
1:  ab72c4cee8f ! 2:  d582d12adb8 gcc/: Rename array_type_nelts() => array_type_nelts_minus_one()
    @@ Commit message
         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>
    +    Link: <https://inbox.sourceware.org/gcc-patches/9fffd80-dca-2c7e-14b-6c9b509a7215@redhat.com/T/#m2f661c67c8f7b2c405c8c7fc3152dd85dc729120>
     
         gcc/ChangeLog:
     
    -            * tree.cc (array_type_nelts, array_type_nelts_minus_one):
    -            * tree.h (array_type_nelts, array_type_nelts_minus_one):
    -            * expr.cc (count_type_elements):
    +            * tree.cc (array_type_nelts, array_type_nelts_minus_one)
    +            * tree.h (array_type_nelts, array_type_nelts_minus_one)
    +            * expr.cc (count_type_elements)
                 * config/aarch64/aarch64.cc
    -            (pure_scalable_type_info::analyze_array):
    +            (pure_scalable_type_info::analyze_array)
                 * config/i386/i386.cc (ix86_canonical_va_list_type):
                 Rename array_type_nelts() => array_type_nelts_minus_one()
                 The old name was misleading.
     
         gcc/c/ChangeLog:
     
    -            * c-decl.cc (one_element_array_type_p, get_parm_array_spec):
    +            * c-decl.cc (one_element_array_type_p, get_parm_array_spec)
                 * c-fold.cc (c_fold_array_ref):
                 Rename array_type_nelts() => array_type_nelts_minus_one()
     
         gcc/cp/ChangeLog:
     
    -            * decl.cc (reshape_init_array):
    +            * decl.cc (reshape_init_array)
                 * init.cc
    -            (build_zero_init_1):
    -            (build_value_init_noctor):
    -            (build_vec_init):
    -            (build_delete):
    -            * lambda.cc (add_capture):
    +            (build_zero_init_1)
    +            (build_value_init_noctor)
    +            (build_vec_init)
    +            (build_delete)
    +            * lambda.cc (add_capture)
                 * tree.cc (array_type_nelts_top):
                 Rename array_type_nelts() => array_type_nelts_minus_one()
     
         gcc/fortran/ChangeLog:
     
    -            * trans-array.cc (structure_alloc_comps):
    +            * trans-array.cc (structure_alloc_comps)
                 * trans-openmp.cc
    -            (gfc_walk_alloc_comps):
    +            (gfc_walk_alloc_comps)
                 (gfc_omp_clause_linear_ctor):
                 Rename array_type_nelts() => array_type_nelts_minus_one()
     
    @@ Commit message
                 * backend/rust-tree.cc (array_type_nelts_top):
                 Rename array_type_nelts() => array_type_nelts_minus_one()
     
    +    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>
         Suggested-by: Richard Biener <richard.guenther@gmail.com>
         Signed-off-by: Alejandro Colomar <alx@kernel.org>
     
2:  27852be4ac0 ! 3:  34d14beb7da Merge definitions of array_type_nelts_top()
    @@ Commit message
     
         gcc/ChangeLog:
     
    -            * tree.h (array_type_nelts_top):
    +            * 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):
    +            * 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.h (array_type_nelts_top)
                 * backend/rust-tree.cc (array_type_nelts_top):
                 Remove function.
     
3:  9c78ce1f66d ! 4:  49b8d51db4a c: Add __nelementsof__ operator
    @@ Commit message
     
         -  Fix support for [0].
     
    +    gcc/ChangeLog:
    +
    +            * doc/extend.texi: Document __nelementsof__ operator.
    +            * target.h (enum type_context_kind): Add __nelementsof__ operator.
    +
    +    gcc/c-family/ChangeLog:
    +
    +            * c-common.h
    +            * c-common.def:
    +            * c-common.cc (c_nelementsof_type): Add __nelementsof__ operator.
    +
    +    gcc/c/ChangeLog:
    +
    +            * c-tree.h
    +            (c_expr_nelementsof_expr, c_expr_nelementsof_type)
    +            * c-decl.cc
    +            (start_struct, finish_struct)
    +            (start_enum, finish_enum)
    +            * c-parser.cc
    +            (c_parser_sizeof_expression)
    +            (c_parser_nelementsof_expression)
    +            (c_parser_sizeof_or_nelementsof_expression)
    +            (c_parser_unary_expression)
    +            * c-typeck.cc
    +            (build_external_ref)
    +            (record_maybe_used_decl, pop_maybe_used)
    +            (is_top_array_vla)
    +            (c_expr_nelementsof_expr, c_expr_nelementsof_type):
    +            Add __nelementsof__operator.
    +
    +    gcc/cp/ChangeLog:
    +
    +            * operators.def: Add __nelementsof__ operator.
    +
    +    gcc/testsuite/ChangeLog:
    +
    +            * gcc.dg/nelementsof-compile.c
    +            * gcc.dg/nelementsof-vla.c
    +            * gcc.dg/nelementsof.c: Add tests for __nelementsof__ operator.
    +
    +    Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3313.pdf>
    +    Link: <https://inbox.sourceware.org/gcc/M8S4oQy--3-2@tutanota.com/T/>
    +    Link: <https://github.com/llvm/llvm-project/issues/102836>
         Cc: Joseph Myers <josmyers@redhat.com>
         Cc: Gabriel Ravier <gabravier@gmail.com>
         Cc: Jakub Jelinek <jakub@redhat.com>
    @@ Commit message
         Cc: Ville Voutilainen <ville.voutilainen@gmail.com>
         Cc: Alex Celeste <alexg.nvfp@gmail.com>
         Cc: Jakub Łukasiewicz <jakublukasiewicz@outlook.com>
    -
    -    gcc/ChangeLog:
    -
    -            * doc/extend.texi: Document __nelementsof__ operator.
    -            * target.h (enum type_context_kind): Add __nelementsof__ operator.
    -
    -    gcc/c-family/ChangeLog:
    -
    -            * c-common.h:
    -            * c-common.def:
    -            * c-common.cc (c_nelementsof_type): Add __nelementsof__ operator.
    -
    -    gcc/c/ChangeLog:
    -
    -            * c-tree.h
    -            (c_expr_nelementsof_expr, c_expr_nelementsof_type):
    -            * c-decl.cc
    -            (start_struct, finish_struct):
    -            (start_enum, finish_enum):
    -            * c-parser.cc
    -            (c_parser_sizeof_expression):
    -            (c_parser_nelementsof_expression):
    -            (c_parser_sizeof_or_nelementsof_expression):
    -            (c_parser_unary_expression):
    -            * c-typeck.cc
    -            (build_external_ref):
    -            (record_maybe_used_decl, pop_maybe_used):
    -            (is_top_array_vla):
    -            (c_expr_nelementsof_expr, c_expr_nelementsof_type):
    -            Add __nelementsof__operator.
    -
    -    gcc/cp/ChangeLog:
    -
    -            * operators.def: Add __nelementsof__ operator.
    -
    -    gcc/testsuite/ChangeLog:
    -
    -            * gcc.dg/nelementsof-compile.c:
    -            * gcc.dg/nelementsof-vla.c:
    -            * gcc.dg/nelementsof.c: Add tests for __nelementsof__ operator.
    -
    -    Link: https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3313.pdf
    -    Link: https://inbox.sourceware.org/gcc/M8S4oQy--3-2@tutanota.com/T/
    -    Link: https://github.com/llvm/llvm-project/issues/102836
    +    Cc: Douglas McIlroy <douglas.mcilroy@dartmouth.edu>
    +    Cc: Jason Merrill <jason@redhat.com>
         Suggested-by: Xavier Del Campo Romero <xavi.dcr@tutanota.com>
    -    Co-developed-by: Martin Uecker <uecker@tugraz.at>
    +    Co-authored-by: Martin Uecker <uecker@tugraz.at>
         Signed-off-by: Alejandro Colomar <alx@kernel.org>
     
      ## gcc/c-family/c-common.cc ##
-- 
2.45.2


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 318+ messages in thread

* [PATCH v11 1/4] contrib/: Add support for Cc: and Link: tags
  2024-08-20 18:41   ` [PATCH v11 0/4] " Alejandro Colomar
@ 2024-08-20 18:41     ` Alejandro Colomar
  2024-08-20 18:49       ` Alejandro Colomar
  2024-08-20 18:41     ` [PATCH v11 2/4] gcc/: Rename array_type_nelts() => array_type_nelts_minus_one() Alejandro Colomar
                       ` (2 subsequent siblings)
  3 siblings, 1 reply; 318+ messages in thread
From: Alejandro Colomar @ 2024-08-20 18:41 UTC (permalink / raw)
  To: gcc-patches
  Cc: Alejandro Colomar, Joseph Myers, Gabriel Ravier, Jakub Jelinek,
	Kees Cook, Qing Zhao, Jens Gustedt, David Brown, Florian Weimer,
	Andreas Schwab, Timm Baeder, Daniel Plakosh, A. Jiang,
	Eugene Zelenko, Aaron Ballman, Paul Koning, Daniel Lundin,
	Nikolaos Strimpas, JeanHeyd Meneide, Fernando Borretti,
	Jonathan Protzenko, Chris Bazley, Ville Voutilainen,
	Alex Celeste, Jakub Łukasiewicz, Douglas McIlroy,
	Jason Merrill, Xavier Del Campo Romero, Martin Uecker

[-- Attachment #1: Type: text/plain, Size: 1259 bytes --]

contrib/ChangeLog:

	* gcc-changelog/git_commit.py: (GitCommit):
	Add support for 'Cc: ' and 'Link: ' tags.

Cc: Jason Merrill <jason@redhat.com>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
---
 contrib/gcc-changelog/git_commit.py | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/contrib/gcc-changelog/git_commit.py b/contrib/gcc-changelog/git_commit.py
index 87ecb9e1a17..64fb986b74c 100755
--- a/contrib/gcc-changelog/git_commit.py
+++ b/contrib/gcc-changelog/git_commit.py
@@ -182,7 +182,8 @@ CO_AUTHORED_BY_PREFIX = 'co-authored-by: '
 
 REVIEW_PREFIXES = ('reviewed-by: ', 'reviewed-on: ', 'signed-off-by: ',
                    'acked-by: ', 'tested-by: ', 'reported-by: ',
-                   'suggested-by: ')
+                   'suggested-by: ', 'cc: ')
+LINK_PREFIXES = ('link: ')
 DATE_FORMAT = '%Y-%m-%d'
 
 
@@ -524,6 +525,8 @@ class GitCommit:
                     continue
                 elif lowered_line.startswith(REVIEW_PREFIXES):
                     continue
+                elif lowered_line.startswith(LINK_PREFIXES):
+                    continue
                 else:
                     m = cherry_pick_regex.search(line)
                     if m:
-- 
2.45.2


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 318+ messages in thread

* [PATCH v11 2/4] gcc/: Rename array_type_nelts() => array_type_nelts_minus_one()
  2024-08-20 18:41   ` [PATCH v11 0/4] " Alejandro Colomar
  2024-08-20 18:41     ` [PATCH v11 1/4] contrib/: Add support for Cc: and Link: tags Alejandro Colomar
@ 2024-08-20 18:41     ` Alejandro Colomar
  2024-08-20 18:41     ` [PATCH v11 3/4] Merge definitions of array_type_nelts_top() Alejandro Colomar
  2024-08-20 18:41     ` [PATCH v11 4/4] c: Add __nelementsof__ operator Alejandro Colomar
  3 siblings, 0 replies; 318+ messages in thread
From: Alejandro Colomar @ 2024-08-20 18:41 UTC (permalink / raw)
  To: gcc-patches
  Cc: Alejandro Colomar, Joseph Myers, Gabriel Ravier, Jakub Jelinek,
	Kees Cook, Qing Zhao, Jens Gustedt, David Brown, Florian Weimer,
	Andreas Schwab, Timm Baeder, Daniel Plakosh, A. Jiang,
	Eugene Zelenko, Aaron Ballman, Paul Koning, Daniel Lundin,
	Nikolaos Strimpas, JeanHeyd Meneide, Fernando Borretti,
	Jonathan Protzenko, Chris Bazley, Ville Voutilainen,
	Alex Celeste, Jakub Łukasiewicz, Douglas McIlroy,
	Jason Merrill, Xavier Del Campo Romero, Martin Uecker,
	Richard Biener

[-- Attachment #1: Type: text/plain, Size: 12749 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>

gcc/ChangeLog:

	* tree.cc (array_type_nelts, array_type_nelts_minus_one)
	* tree.h (array_type_nelts, array_type_nelts_minus_one)
	* expr.cc (count_type_elements)
	* config/aarch64/aarch64.cc
	(pure_scalable_type_info::analyze_array)
	* config/i386/i386.cc (ix86_canonical_va_list_type):
	Rename array_type_nelts() => array_type_nelts_minus_one()
	The old name was misleading.

gcc/c/ChangeLog:

	* c-decl.cc (one_element_array_type_p, get_parm_array_spec)
	* c-fold.cc (c_fold_array_ref):
	Rename array_type_nelts() => array_type_nelts_minus_one()

gcc/cp/ChangeLog:

	* decl.cc (reshape_init_array)
	* init.cc
	(build_zero_init_1)
	(build_value_init_noctor)
	(build_vec_init)
	(build_delete)
	* lambda.cc (add_capture)
	* tree.cc (array_type_nelts_top):
	Rename array_type_nelts() => array_type_nelts_minus_one()

gcc/fortran/ChangeLog:

	* trans-array.cc (structure_alloc_comps)
	* trans-openmp.cc
	(gfc_walk_alloc_comps)
	(gfc_omp_clause_linear_ctor):
	Rename array_type_nelts() => array_type_nelts_minus_one()

gcc/rust/ChangeLog:

	* backend/rust-tree.cc (array_type_nelts_top):
	Rename array_type_nelts() => array_type_nelts_minus_one()

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>
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 bfd7bcdef7c..f787347b56e 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 d06e2141e56..e3ba9f533fe 100644
--- a/gcc/config/i386/i386.cc
+++ b/gcc/config/i386/i386.cc
@@ -24382,7 +24382,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 f23b635aec9..b6a3cfdf8c4 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 ea5fff2e0c2..47e0447cae5 100644
--- a/gcc/fortran/trans-array.cc
+++ b/gcc/fortran/trans-array.cc
@@ -9728,7 +9728,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] 318+ messages in thread

* [PATCH v11 3/4] Merge definitions of array_type_nelts_top()
  2024-08-20 18:41   ` [PATCH v11 0/4] " Alejandro Colomar
  2024-08-20 18:41     ` [PATCH v11 1/4] contrib/: Add support for Cc: and Link: tags Alejandro Colomar
  2024-08-20 18:41     ` [PATCH v11 2/4] gcc/: Rename array_type_nelts() => array_type_nelts_minus_one() Alejandro Colomar
@ 2024-08-20 18:41     ` Alejandro Colomar
  2024-08-20 18:41     ` [PATCH v11 4/4] c: Add __nelementsof__ operator Alejandro Colomar
  3 siblings, 0 replies; 318+ messages in thread
From: Alejandro Colomar @ 2024-08-20 18:41 UTC (permalink / raw)
  To: gcc-patches
  Cc: Alejandro Colomar, Joseph Myers, Gabriel Ravier, Jakub Jelinek,
	Kees Cook, Qing Zhao, Jens Gustedt, David Brown, Florian Weimer,
	Andreas Schwab, Timm Baeder, Daniel Plakosh, A. Jiang,
	Eugene Zelenko, Aaron Ballman, Paul Koning, Daniel Lundin,
	Nikolaos Strimpas, JeanHeyd Meneide, Fernando Borretti,
	Jonathan Protzenko, Chris Bazley, Ville Voutilainen,
	Alex Celeste, Jakub Łukasiewicz, Douglas McIlroy,
	Jason Merrill, Xavier Del Campo Romero, Martin Uecker

[-- Attachment #1: Type: text/plain, Size: 4880 bytes --]

There were two identical definitions, and none of them are available
where they are needed for implementing __nelementsof__.  Merge them, and
provide the single definition in gcc/tree.{h,cc}, where it's available
for __nelementsof__, 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 a53fbcb43ec..39f23b04a78 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -8103,7 +8103,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] 318+ messages in thread

* [PATCH v11 4/4] c: Add __nelementsof__ operator
  2024-08-20 18:41   ` [PATCH v11 0/4] " Alejandro Colomar
                       ` (2 preceding siblings ...)
  2024-08-20 18:41     ` [PATCH v11 3/4] Merge definitions of array_type_nelts_top() Alejandro Colomar
@ 2024-08-20 18:41     ` Alejandro Colomar
  3 siblings, 0 replies; 318+ messages in thread
From: Alejandro Colomar @ 2024-08-20 18:41 UTC (permalink / raw)
  To: gcc-patches
  Cc: Alejandro Colomar, Joseph Myers, Gabriel Ravier, Jakub Jelinek,
	Kees Cook, Qing Zhao, Jens Gustedt, David Brown, Florian Weimer,
	Andreas Schwab, Timm Baeder, Daniel Plakosh, A. Jiang,
	Eugene Zelenko, Aaron Ballman, Paul Koning, Daniel Lundin,
	Nikolaos Strimpas, JeanHeyd Meneide, Fernando Borretti,
	Jonathan Protzenko, Chris Bazley, Ville Voutilainen,
	Alex Celeste, Jakub Łukasiewicz, Douglas McIlroy,
	Jason Merrill, Xavier Del Campo Romero, Martin Uecker

[-- Attachment #1: Type: text/plain, Size: 30966 bytes --]

This operator is similar to sizeof but can only be applied to an array,
and returns its number of elements.

FUTURE DIRECTIONS:

-  We should make it work with array parameters to functions,
   and somehow magically return the number of elements of the array,
   regardless of it being really a pointer.

-  Fix support for [0].

gcc/ChangeLog:

	* doc/extend.texi: Document __nelementsof__ operator.
	* target.h (enum type_context_kind): Add __nelementsof__ operator.

gcc/c-family/ChangeLog:

	* c-common.h
	* c-common.def:
	* c-common.cc (c_nelementsof_type): Add __nelementsof__ operator.

gcc/c/ChangeLog:

	* c-tree.h
	(c_expr_nelementsof_expr, c_expr_nelementsof_type)
	* c-decl.cc
	(start_struct, finish_struct)
	(start_enum, finish_enum)
	* c-parser.cc
	(c_parser_sizeof_expression)
	(c_parser_nelementsof_expression)
	(c_parser_sizeof_or_nelementsof_expression)
	(c_parser_unary_expression)
	* c-typeck.cc
	(build_external_ref)
	(record_maybe_used_decl, pop_maybe_used)
	(is_top_array_vla)
	(c_expr_nelementsof_expr, c_expr_nelementsof_type):
	Add __nelementsof__operator.

gcc/cp/ChangeLog:

	* operators.def: Add __nelementsof__ operator.

gcc/testsuite/ChangeLog:

	* gcc.dg/nelementsof-compile.c
	* gcc.dg/nelementsof-vla.c
	* gcc.dg/nelementsof.c: Add tests for __nelementsof__ operator.

Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3313.pdf>
Link: <https://inbox.sourceware.org/gcc/M8S4oQy--3-2@tutanota.com/T/>
Link: <https://github.com/llvm/llvm-project/issues/102836>
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>
Cc: Daniel Plakosh <dplakosh@cert.org>
Cc: "A. Jiang" <de34@live.cn>
Cc: Eugene Zelenko <eugene.zelenko@gmail.com>
Cc: Aaron Ballman <aaron.ballman@intel.com>
Cc: Paul Koning <paulkoning@comcast.net>
Cc: Daniel Lundin <daniel.lundin.mail@gmail.com>
Cc: Nikolaos Strimpas <Strnik86@protonmail.com>
Cc: JeanHeyd Meneide <phdofthehouse@gmail.com>
Cc: Fernando Borretti <fernando@borretti.me>
Cc: Jonathan Protzenko <jonathan.protzenko@ens-lyon.org>
Cc: Chris Bazley <Chris.Bazley@arm.com>
Cc: Ville Voutilainen <ville.voutilainen@gmail.com>
Cc: Alex Celeste <alexg.nvfp@gmail.com>
Cc: Jakub Łukasiewicz <jakublukasiewicz@outlook.com>
Cc: Douglas McIlroy <douglas.mcilroy@dartmouth.edu>
Cc: Jason Merrill <jason@redhat.com>
Suggested-by: Xavier Del Campo Romero <xavi.dcr@tutanota.com>
Co-authored-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                            |  22 ++-
 gcc/c/c-parser.cc                          |  62 +++++++--
 gcc/c/c-tree.h                             |   4 +
 gcc/c/c-typeck.cc                          | 118 +++++++++++++++-
 gcc/cp/operators.def                       |   1 +
 gcc/doc/extend.texi                        |  30 +++++
 gcc/target.h                               |   3 +
 gcc/testsuite/gcc.dg/nelementsof-compile.c | 115 ++++++++++++++++
 gcc/testsuite/gcc.dg/nelementsof-vla.c     |  46 +++++++
 gcc/testsuite/gcc.dg/nelementsof.c         | 150 +++++++++++++++++++++
 13 files changed, 558 insertions(+), 24 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/nelementsof-compile.c
 create mode 100644 gcc/testsuite/gcc.dg/nelementsof-vla.c
 create mode 100644 gcc/testsuite/gcc.dg/nelementsof.c

diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
index e7e371fd26f..188bb9b65ef 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 },
+  { "__nelementsof__",	RID_NELEMENTSOF, 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 lementsof keyword:
+   Return the number of elements of an array.  */
+
+tree
+c_nelementsof_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 %<nelementsof%> to type %qT", type);
+      return error_mark_node;
+    }
+  if (!COMPLETE_TYPE_P (type))
+    {
+      error_at (loc,
+		"invalid application of %<nelementsof%> 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..12ee0d2adb3 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 'nelementsof' expression.  */
+DEFTREECODE (NELEMENTSOF_EXPR, "nelementsof_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..3b36d8b6513 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_NELEMENTSOF,
   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_nelementsof_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..73449292203 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -8943,12 +8943,17 @@ 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_nelementsof))
     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"
+		       : "nelementsof"))));
 
   if (in_underspecified_init)
     error_at (loc, "%qT defined in underspecified object initializer", ref);
@@ -9908,7 +9913,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_nelementsof)
 	struct_parse_info->struct_types.safe_push (t);
      }
 
@@ -10082,12 +10087,17 @@ 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_nelementsof))
     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"
+		       : "nelementsof"))));
 
   if (in_underspecified_init)
     error_at (loc, "%qT defined in underspecified object initializer",
@@ -10281,7 +10291,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_nelementsof)
     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..d6031d947a8 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_nelementsof_expression (parser, RID_SIZEOF)              \
+)
 
+#define c_parser_nelementsof_expression(parser)                               \
+(                                                                             \
+  c_parser_sizeof_or_nelementsof_expression (parser, RID_NELEMENTSOF)         \
+)
+\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,8 @@ 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_nelementsof_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 +9920,8 @@ c_parser_unary_expression (c_parser *parser)
     case CPP_KEYWORD:
       switch (c_parser_peek_token (parser)->keyword)
 	{
+	case RID_NELEMENTSOF:
+	  return c_parser_nelementsof_expression (parser);
 	case RID_SIZEOF:
 	  return c_parser_sizeof_expression (parser);
 	case RID_ALIGNOF:
@@ -9948,12 +9961,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_nelementsof_expression (c_parser *parser, enum rid rid)
 {
+  const char *op_name = (rid == RID_NELEMENTSOF) ? "nelementsof" : "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 +9976,10 @@ c_parser_sizeof_expression (c_parser *parser)
 
   c_parser_consume_token (parser);
   c_inhibit_evaluation_warnings++;
-  in_sizeof++;
+  if (rid == RID_NELEMENTSOF)
+    in_nelementsof++;
+  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 +9998,10 @@ c_parser_sizeof_expression (c_parser *parser)
 	{
 	  struct c_expr ret;
 	  c_inhibit_evaluation_warnings--;
-	  in_sizeof--;
+	  if (rid == RID_NELEMENTSOF)
+	    in_nelementsof--;
+	  else
+	    in_sizeof--;
 	  ret.set_error ();
 	  ret.original_code = ERROR_MARK;
 	  ret.original_type = NULL;
@@ -9993,31 +10013,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_NELEMENTSOF)
+	{
+	  in_nelementsof--;
+	  result = c_expr_nelementsof_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_NELEMENTSOF)
+	in_nelementsof--;
+      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_NELEMENTSOF)
+	result = c_expr_nelementsof_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..a0149ccae77 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_nelementsof;
 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_nelementsof_expr (location_t, struct c_expr);
+extern struct c_expr c_expr_nelementsof_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..651e5c15b87 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 "nelementsof".  */
+int in_nelementsof;
+
 /* 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_nelementsof)
 	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_nelementsof).  */
   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_nelementsof;
   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_nelementsof;
   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 nelementsof applied to EXPR.  */
+
+struct c_expr
+c_expr_nelementsof_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_nelementsof_type (loc, TREE_TYPE (folded_expr));
+      c_last_sizeof_arg = expr.value;
+      c_last_sizeof_loc = loc;
+      ret.original_code = NELEMENTSOF_EXPR;
+      ret.original_type = NULL;
+      ret.m_decimal = 0;
+      if (is_top_array_vla (TREE_TYPE (folded_expr)))
+	{
+	  /* nelementsof 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 nelementsof applied to T, a structure for the type
+   name passed to nelementsof (rather than the type itself).  LOC is the
+   location of the original expression.  */
+
+struct c_expr
+c_expr_nelementsof_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_nelementsof_type (loc, type);
+  c_last_sizeof_arg = type;
+  c_last_sizeof_loc = loc;
+  ret.original_code = NELEMENTSOF_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 nelementsof 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 nelementsof 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..7f1d24779c8 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 ("__nelementsof__", NELEMENTSOF_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 0ea7a87053c..85bcb059730 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -10481,6 +10481,36 @@ 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 nelementsof
+@section Determining the Number of Elements of Arrays
+@cindex nelementsof
+@cindex number of elements
+
+The keyword @code{__elemetsf__} 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 parenthesized complete array type name
+or an expression of such a type.
+For example:
+
+@smallexample
+int a[n];
+__elemetsf__ (a);  // returns n
+__elemetsf__ (int [7][3]);  // returns 7
+@end smallexample
+
+The result of this operator is an integer constant expression,
+unless the top-level array is a variable-length array.
+The operand is only evaluated
+if the top-level array is a variable-length array.
+For example:
+
+@smallexample
+__elemetsf__ (int [7][n++]);  // integer constant expression
+__elemetsf__ (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..09245d70c1f 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 number of elements of array T.  */
+  TCTX_NELEMENTSOF,
+
   /* Creating objects of type T with static storage duration.  */
   TCTX_STATIC_STORAGE,
 
diff --git a/gcc/testsuite/gcc.dg/nelementsof-compile.c b/gcc/testsuite/gcc.dg/nelementsof-compile.c
new file mode 100644
index 00000000000..211b63fa7b5
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/nelementsof-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[__nelementsof__(z)];
+
+void
+automatic(void)
+{
+  __nelementsof__ (w);
+}
+
+void
+incomplete (int p[])
+{
+  __nelementsof__ (x);  /* { dg-error "incomplete" } */
+
+  /* We want to support the following one in the future,
+     but for now it should fail.  */
+  __nelementsof__ (p);  /* { dg-error "invalid" } */
+}
+
+void
+fam (void)
+{
+  struct {
+    int x;
+    int fam[];
+  } s;
+
+  __nelementsof__ (s.fam); /* { dg-error "incomplete" } */
+}
+
+void fix_fix (int i, char (*a)[3][5], int (*x)[__nelementsof__ (*a)]);
+void fix_var (int i, char (*a)[3][i], int (*x)[__nelementsof__ (*a)]);
+void fix_uns (int i, char (*a)[3][*], int (*x)[__nelementsof__ (*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;
+
+  __nelementsof__ (x); /* { dg-error "invalid" } */
+  __nelementsof__ (int); /* { dg-error "invalid" } */
+  __nelementsof__ (s); /* { dg-error "invalid" } */
+  __nelementsof__ (struct s); /* { dg-error "invalid" } */
+  __nelementsof__ (&x); /* { dg-error "invalid" } */
+  __nelementsof__ (p); /* { dg-error "invalid" } */
+  __nelementsof__ (int *); /* { dg-error "invalid" } */
+  __nelementsof__ (&s.x); /* { dg-error "invalid" } */
+  __nelementsof__ (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];
+
+  __nelementsof__ (a[f1()]);
+  __nelementsof__ (b[f2()]);
+}
+
+void
+no_parens(void)
+{
+  __nelementsof__ a;
+  __nelementsof__ *a;
+  __nelementsof__ (int [3]) {};
+
+  __nelementsof__ int [3]; /* { dg-error "expected expression before" } */
+}
+
+void
+const_expr(void)
+{
+  int n = 7;
+
+  _Static_assert (__nelementsof__ (int [3][n]) == 3);
+  _Static_assert (__nelementsof__ (int [n][3]) == 7); /* { dg-error "not constant" } */
+  _Static_assert (__nelementsof__ (int [0][3]) == 0);
+  _Static_assert (__nelementsof__ (int [0]) == 0);
+
+  /* FIXME: nelementsof(int [0][n]) should result in a constant expression.  */
+  _Static_assert (__nelementsof__ (int [0][n]) == 0); /* { dg-error "not constant" } */
+}
diff --git a/gcc/testsuite/gcc.dg/nelementsof-vla.c b/gcc/testsuite/gcc.dg/nelementsof-vla.c
new file mode 100644
index 00000000000..0cd4dfd37fa
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/nelementsof-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)[__nelementsof__ (*a)]);
+void fix_var (int i,
+	      char (*a)[3][i], /* dg-warn "variable" */
+	      int (*x)[__nelementsof__ (*a)]);
+void fix_uns (int i,
+	      char (*a)[3][*],
+	      int (*x)[__nelementsof__ (*a)]);
+
+void zro_fix (int i,
+	      char (*a)[0][5],
+	      int (*x)[__nelementsof__ (*a)]);
+void zro_var (int i,
+	      char (*a)[0][i], /* dg-warn "variable" */
+	      int (*x)[__nelementsof__ (*a)]);
+void zro_uns (int i,
+	      char (*a)[0][*],
+	      int (*x)[__nelementsof__ (*a)]);
+
+void var_fix (int i,
+	      char (*a)[i][5], /* dg-warn "variable" */
+	      int (*x)[__nelementsof__ (*a)]); /* dg-warn "variable" */
+void var_var (int i,
+	      char (*a)[i][i], /* dg-warn "variable" */
+	      int (*x)[__nelementsof__ (*a)]); /* dg-warn "variable" */
+void var_uns (int i,
+	      char (*a)[i][*], /* dg-warn "variable" */
+	      int (*x)[__nelementsof__ (*a)]); /* dg-warn "variable" */
+
+void uns_fix (int i,
+	      char (*a)[*][5],
+	      int (*x)[__nelementsof__ (*a)]);
+void uns_var (int i,
+	      char (*a)[*][i], /* dg-warn "variable" */
+	      int (*x)[__nelementsof__ (*a)]);
+void uns_uns (int i,
+	      char (*a)[*][*],
+	      int (*x)[__nelementsof__ (*a)]);
+
+// Can't test due to bug: <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=116284>
+//static int z2[0];
+//static int y2[__nelementsof__(z2)];
diff --git a/gcc/testsuite/gcc.dg/nelementsof.c b/gcc/testsuite/gcc.dg/nelementsof.c
new file mode 100644
index 00000000000..292311e2822
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/nelementsof.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 (__nelementsof__ (a) == 7);
+  static_assert (__nelementsof__ (long [0]) == 0);
+  static_assert (__nelementsof__ (unsigned [99]) == 99);
+}
+
+void
+automatic(void)
+{
+  int a[] = {1, 2, 3};
+  int z[] = {};
+
+  static_assert (__nelementsof__ (a) == 3);
+  static_assert (__nelementsof__ (z) == 0);
+}
+
+void
+vla (void)
+{
+  unsigned n;
+
+  n = 99;
+  assert (__nelementsof__ (short [n - 10]) == 99 - 10);
+
+  int v[n / 2];
+  assert (__nelementsof__ (v) == 99 / 2);
+
+  n = 0;
+  int z[n];
+  assert (__nelementsof__ (z) == 0);
+}
+
+void
+member (void)
+{
+  struct {
+    int a[8];
+  } s;
+
+  static_assert (__nelementsof__ (s.a) == 8);
+}
+
+void
+vla_eval (void)
+{
+  int i;
+
+  i = 7;
+  assert (__nelementsof__ (struct {int x;}[i++]) == 7);
+  assert (i == 7 + 1);
+
+  int v[i];
+  int (*p)[i];
+  p = &v;
+  assert (__nelementsof__ (*p++) == i);
+  assert (p - 1 == &v);
+}
+
+void
+inner_vla_noeval (void)
+{
+  int i;
+
+  i = 3;
+  static_assert (__nelementsof__ (struct {int x[i++];}[3]) == 3);
+  assert (i == 3);
+}
+
+void
+array_noeval (void)
+{
+  long a[5];
+  long (*p)[__nelementsof__ (a)];
+
+  p = &a;
+  static_assert (__nelementsof__ (*p++) == 5);
+  assert (p == &a);
+}
+
+void
+matrix_zero (void)
+{
+  int i;
+
+  static_assert (__nelementsof__ (int [0][4]) == 0);
+  i = 3;
+  assert (__nelementsof__ (int [0][i]) == 0);
+}
+
+void
+matrix_fixed (void)
+{
+  int i;
+
+  static_assert (__nelementsof__ (int [7][4]) == 7);
+  i = 3;
+  static_assert (__nelementsof__ (int [7][i]) == 7);
+}
+
+void
+matrix_vla (void)
+{
+  int i, j;
+
+  i = 7;
+  assert (__nelementsof__ (int [i++][4]) == 7);
+  assert (i == 7 + 1);
+
+  i = 9;
+  j = 3;
+  assert (__nelementsof__ (int [i++][j]) == 9);
+  assert (i == 9 + 1);
+}
+
+void
+no_parens(void)
+{
+  int n = 3;
+  int a[7];
+  int v[n];
+
+  static_assert (__nelementsof__ a == 7); 
+  assert (__nelementsof__ 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] 318+ messages in thread

* Re: [PATCH v11 1/4] contrib/: Add support for Cc: and Link: tags
  2024-08-20 18:41     ` [PATCH v11 1/4] contrib/: Add support for Cc: and Link: tags Alejandro Colomar
@ 2024-08-20 18:49       ` Alejandro Colomar
  0 siblings, 0 replies; 318+ messages in thread
From: Alejandro Colomar @ 2024-08-20 18:49 UTC (permalink / raw)
  To: gcc-patches; +Cc: Jason Merrill

[-- Attachment #1: Type: text/plain, Size: 1670 bytes --]

Hi,

On Tue, Aug 20, 2024 at 08:41:28PM GMT, Alejandro Colomar wrote:
> contrib/ChangeLog:
> 
> 	* gcc-changelog/git_commit.py: (GitCommit):

There's a spurious ':' in the line above (before the '(').  I've removed
it for an eventual v12.

> 	Add support for 'Cc: ' and 'Link: ' tags.
> 
> Cc: Jason Merrill <jason@redhat.com>
> Signed-off-by: Alejandro Colomar <alx@kernel.org>

Is it ok to send this patch together with this patch set, or should I
send it separately?

Cheers,
Alex

> ---
>  contrib/gcc-changelog/git_commit.py | 5 ++++-
>  1 file changed, 4 insertions(+), 1 deletion(-)
> 
> diff --git a/contrib/gcc-changelog/git_commit.py b/contrib/gcc-changelog/git_commit.py
> index 87ecb9e1a17..64fb986b74c 100755
> --- a/contrib/gcc-changelog/git_commit.py
> +++ b/contrib/gcc-changelog/git_commit.py
> @@ -182,7 +182,8 @@ CO_AUTHORED_BY_PREFIX = 'co-authored-by: '
>  
>  REVIEW_PREFIXES = ('reviewed-by: ', 'reviewed-on: ', 'signed-off-by: ',
>                     'acked-by: ', 'tested-by: ', 'reported-by: ',
> -                   'suggested-by: ')
> +                   'suggested-by: ', 'cc: ')
> +LINK_PREFIXES = ('link: ')
>  DATE_FORMAT = '%Y-%m-%d'
>  
>  
> @@ -524,6 +525,8 @@ class GitCommit:
>                      continue
>                  elif lowered_line.startswith(REVIEW_PREFIXES):
>                      continue
> +                elif lowered_line.startswith(LINK_PREFIXES):
> +                    continue
>                  else:
>                      m = cherry_pick_regex.search(line)
>                      if m:
> -- 
> 2.45.2
> 



-- 
<https://www.alejandro-colomar.es/>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 318+ messages in thread

* [PATCH v12 0/4] c: Add __nelementsof__ operator
  2024-07-28 14:15 ` [RFC v1 0/2] c: Add _Lengthof operator Alejandro Colomar
                     ` (16 preceding siblings ...)
  2024-08-20 18:41   ` [PATCH v11 0/4] " Alejandro Colomar
@ 2024-08-31 14:56   ` Alejandro Colomar
  2024-08-31 14:56     ` [PATCH v12 1/4] contrib/: Add support for Cc: and Link: tags Alejandro Colomar
                       ` (4 more replies)
  2024-10-02  9:41   ` [PATCH v13 0/4] c: Add __lengthof__ operator Alejandro Colomar
                     ` (10 subsequent siblings)
  28 siblings, 5 replies; 318+ messages in thread
From: Alejandro Colomar @ 2024-08-31 14:56 UTC (permalink / raw)
  To: gcc-patches, Martin Uecker, Joseph Myers
  Cc: Alejandro Colomar, Gabriel Ravier, Jakub Jelinek, Kees Cook,
	Qing Zhao, Jens Gustedt, David Brown, Florian Weimer,
	Andreas Schwab, Timm Baeder, Daniel Plakosh, A. Jiang,
	Eugene Zelenko, Aaron Ballman, Paul Koning, Daniel Lundin,
	Nikolaos Strimpas, JeanHeyd Meneide, Fernando Borretti,
	Jonathan Protzenko, Chris Bazley, Ville Voutilainen,
	Alex Celeste, Jakub Łukasiewicz, Douglas McIlroy,
	Jason Merrill, Xavier Del Campo Romero, Siddhesh Poyarekar,
	DJ Delorie, Carlos O'Donell, Stephen Coady, ganandan,
	mnewsome

[-- Attachment #1: Type: text/plain, Size: 23961 bytes --]

Hi!

v12 changes:

-  Fix typo in changelog entry.

For ISO C2y, I'm proposing either nelementsof() or a contracted version
of that name.  However, since in GCC we want an uglified name that
already takes four characters for the __*__, I think this long name
makes sense.  See also:
<https://inbox.sourceware.org/gcc/ewksn7n5blrzhvy565ztxnt2pagxy4rdhuq2i4k6beqsimoqgw@74wy7erikpwt/1.2-elementsof.pdf>

The WG14 discussion seems to have settled, and while the exact name
isn't yet clear, there seems to be rough consensus on something derived
from "number of elements of" (with some votes for "lenght", but not so
many), and the rest of the properties of the operator don't seem to be
questioned.

Martin, Joseph, can you please review and merge?  Thanks!

Have a lovely day!
Alex

Alejandro Colomar (4):
  contrib/: Add support for Cc: and Link: tags
  gcc/: Rename array_type_nelts() => array_type_nelts_minus_one()
  Merge definitions of array_type_nelts_top()
  c: Add __nelementsof__ operator

 contrib/gcc-changelog/git_commit.py        |   5 +-
 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                            |  32 +++--
 gcc/c/c-fold.cc                            |   7 +-
 gcc/c/c-parser.cc                          |  62 +++++++--
 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                        |  30 +++++
 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/nelementsof-compile.c | 115 ++++++++++++++++
 gcc/testsuite/gcc.dg/nelementsof-vla.c     |  46 +++++++
 gcc/testsuite/gcc.dg/nelementsof.c         | 150 +++++++++++++++++++++
 gcc/tree.cc                                |  17 ++-
 gcc/tree.h                                 |   3 +-
 29 files changed, 604 insertions(+), 80 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/nelementsof-compile.c
 create mode 100644 gcc/testsuite/gcc.dg/nelementsof-vla.c
 create mode 100644 gcc/testsuite/gcc.dg/nelementsof.c

Range-diff against v11:
1:  2e851b8f8d2 ! 1:  d7fca49888a contrib/: Add support for Cc: and Link: tags
    @@ Commit message
     
         contrib/ChangeLog:
     
    -            * gcc-changelog/git_commit.py: (GitCommit):
    +            * gcc-changelog/git_commit.py (GitCommit):
                 Add support for 'Cc: ' and 'Link: ' tags.
     
         Cc: Jason Merrill <jason@redhat.com>
2:  d582d12adb8 = 2:  e65245ac294 gcc/: Rename array_type_nelts() => array_type_nelts_minus_one()
3:  34d14beb7da = 3:  03de2d67bb1 Merge definitions of array_type_nelts_top()
4:  49b8d51db4a = 4:  4373c48205d c: Add __nelementsof__ operator

base-commit: 9cbcf8d1de159e6113fafb5dc2feb4a7e467a302
prerequisite-patch-id: 3bb58e302e54b35e987452de2e3cb6da7f6917ce
prerequisite-patch-id: 090612df745c5ed878a75175606ce1deabf61cb0
prerequisite-patch-id: c3a80d94c326f7402bdf46049c434e809a9f376e
prerequisite-patch-id: 883007acf6a47f51128798dc952895854b40e1ff
prerequisite-patch-id: 93e211483ce2b939ce5e549de78e9ac4606bb114
prerequisite-patch-id: 008f55a1dc4b0a2551e4682b3319a3b0df86c72e
prerequisite-patch-id: be6ecc95f5fcf2fe9ac44263e6eae8a69068ee53
prerequisite-patch-id: e64a9e239738ff1af9753893372bb0fff907d8e6
prerequisite-patch-id: 22cc97d05ab08735db2341f5062c737f9cff9209
prerequisite-patch-id: 9e9756ca0458d4f6f162229e5ffe5923ffceb9d7
prerequisite-patch-id: 9d64d075010c059eaceb2fb2326d48f6a8798950
prerequisite-patch-id: be2e5a5deb6836b4715e4715cddd03018d2f3346
prerequisite-patch-id: a627d18e62fc98b7ccf11b31b0dc885a52994795
prerequisite-patch-id: 39aea8b15f043ab5e2804a6e127d2fe5108d814b
prerequisite-patch-id: 8cb26809cc4de24fe408e71a468fbc278241faab
prerequisite-patch-id: 1b0dd932c7637d953a7b7086aa5625287df6c79a
prerequisite-patch-id: 0bb1888a37e3537ba48e69ac378b7b3e41453949
prerequisite-patch-id: 79657c31c616c9bf477ec015a4ccb94f298193c0
prerequisite-patch-id: 2506a44e9d695cffa4c710176092c30392037103
prerequisite-patch-id: da4a114bc9bef4aafb816328f1674b5f85818753
prerequisite-patch-id: f4a32714d46e022356759a3fb305a8827ef565e9
prerequisite-patch-id: 08a6388b590804ab3f8da8c03d953e88428228e9
prerequisite-patch-id: 37fb8203174274fa9e3054ba0d83ff41dd9ba206
prerequisite-patch-id: 5a6559b661dd999abf5d5b0a40309636faa3504e
prerequisite-patch-id: a66c0ace262f24e19546e0669fecd0bbb6c4b4bf
prerequisite-patch-id: de6b8f05d41b61f29fc517883fafdf89aada7de9
prerequisite-patch-id: 4412c0ef6909608fc761b86cfb22722d862d61d0
prerequisite-patch-id: ad452759de17adaaf82c9f30e556fb477e3b1941
prerequisite-patch-id: 7b8615c4ad8e6c825ee192c8225e7b8f673aaeb4
prerequisite-patch-id: 7f806ab2c8bac5b2a79fad8eef55c4190ec33d44
prerequisite-patch-id: 84d3e86a4b573228dab7d37c3d89845ec1989723
prerequisite-patch-id: 293a69cf606ea42badcc678f43b53f2e47aded19
prerequisite-patch-id: 1a871a86b6c1b147ed731970f999b5d102444d1d
prerequisite-patch-id: 7798a8ca79c1f13268e3762d47861ff94d8eba02
prerequisite-patch-id: ea12050f12ad6e1278b695f5fe345ca9bc842b1f
prerequisite-patch-id: 775ec83e6019784675e3412125ae6215b4bf045d
prerequisite-patch-id: 8cc5a6f94523c8120086dcb2217ba8168b045a3e
prerequisite-patch-id: ee9fa7eb9352555ff989551e0af040359671f3d7
prerequisite-patch-id: 02737f65218d4b0c2766cfcf8c0fcde24ca93ac2
prerequisite-patch-id: 4649eac88f8eb70f79e7777b7cebff4460d8cfc7
prerequisite-patch-id: 6cba96eb4bee2e8b3b47e0bf6b21ec9fa8639480
prerequisite-patch-id: 67691213e43b5776c999e8c0927df69be8689e14
prerequisite-patch-id: c92d8f4dab324c8f42605d626035999cd990a18e
prerequisite-patch-id: f0a10e37287f97e915eb245d6394ad8e1115905a
prerequisite-patch-id: f67343a2b854a5f51d75200d56715b2cd10ddc9c
prerequisite-patch-id: 0d42c83260a2a02de43ad5066f76b4483703f155
prerequisite-patch-id: 71fc9c326b88271512ee65320dcb3b3454326472
prerequisite-patch-id: 5770267c01d4e5b5d0187445d31ee87b662fa61d
prerequisite-patch-id: 999d706f78ac4f85adbfad63adc3df03615ce716
prerequisite-patch-id: a3a7f88920dcaec397cdce89680dd341da6b7d50
prerequisite-patch-id: 74495be2707634e339b90ed5ad3a4c375f6b9ec2
prerequisite-patch-id: 7be19bb7867585445b6119f6357b69f5f8baa5b8
prerequisite-patch-id: 03efabd23ba77ba8141aa0a8f19b04f0fa6c97f1
prerequisite-patch-id: 04a4ddcad10e249f4e8cd96ade03c16997e8f83f
prerequisite-patch-id: b0b8243418ae865a61a5f92d1da80fdbed6d23d4
prerequisite-patch-id: 349842ef44ddca54066bdbb26d634ac24e076710
prerequisite-patch-id: d15d4d8c4c0b6843118774fee0c8231e948779cf
prerequisite-patch-id: eff8d7df797afdd2ba6b14c1d8ec9dbdc58b5c3d
prerequisite-patch-id: 18ae20d67e1f01478d4b01981488e0a3d6864ad2
prerequisite-patch-id: b6c162640de66eeaf8f2b470801dc3cec9d1141e
prerequisite-patch-id: fccd6815aa703114b7ea3e61b3971621316a8706
prerequisite-patch-id: ec894a0480c8c523b9f895eea7b809b68998bbfe
prerequisite-patch-id: a408ede8ac2c69f821dd06cdad368652784e975f
prerequisite-patch-id: 31f81b5fce5e577e66c09784d24727fadce0b71b
prerequisite-patch-id: 0fa06efe4a2349a00a6e1d7ed3fcb7ededef127e
prerequisite-patch-id: e7dba9a68bc0d4481b2cebf029595bdb9f47271f
prerequisite-patch-id: 4ac7ef554fdd4c2fcceb9f5bd83e9203adaddaf3
prerequisite-patch-id: ec0a3bc81af005d80235b38f44c227b0a1c248d2
prerequisite-patch-id: 7083aa4a6a21ae34a8d6457791068ba419c1187d
prerequisite-patch-id: 7b3ceb60e52271be1655ab07595e1000d8734ae8
prerequisite-patch-id: 069dd47701f5607db952e7410b66bfc4a77b907c
prerequisite-patch-id: 6de803a1b4d8dba8b403205327bff91f239a39a8
prerequisite-patch-id: 8dfcdb9d5cdf69c54766a59a8f194af09c0840b8
prerequisite-patch-id: f7834a2848f562a130f3d6f28a6b849723dbe18f
prerequisite-patch-id: 2f283e2b6ff758a2b1f0f4f491c962499be68f91
prerequisite-patch-id: 7ca906fcc364ab07d6ab9b48fe8162e8006499b9
prerequisite-patch-id: 0ef05db7ab79653ae096f50497946214bc5084b9
prerequisite-patch-id: 1d60704d316f4b0f66d5c7e4bf17b025cf99c617
prerequisite-patch-id: ed3314a4690d9c15bbcfee441599a58e37215877
prerequisite-patch-id: 34ec93f88bed41db1608e214800f87fdc5a7f9f9
prerequisite-patch-id: aca1f8cc97d88784936517c7e8050c457c77c9af
prerequisite-patch-id: b499a1bfa95368ee03daa8c7d45b3ae9c1206871
prerequisite-patch-id: 5f1cb1245044b3ad4169500916c8b9459711416e
prerequisite-patch-id: 88e3e2e5947fbfa907213daa9ceef1651976d72f
prerequisite-patch-id: b4d4f67cd84b9ccb4c4eb48d8e7e20fc70b702ec
prerequisite-patch-id: b807936c32d4a4539a29ba56b637a3f4733713e3
prerequisite-patch-id: 72b95ab107eb6ae60f6517410ecce24a3308fa6e
prerequisite-patch-id: 007b9853bbb41eb2d2b85fd67c1b39d58c2dcc4d
prerequisite-patch-id: e6e05315ec9827b069836b4f394099272c4b3998
prerequisite-patch-id: cd63bd21f25dfb458c751306f1ba8fba6db43a35
prerequisite-patch-id: 790fe51546bed957d4094668086a87009ea6bc3e
prerequisite-patch-id: c55ca764e1bde1857cab3d1c7a569172e3a60dd0
prerequisite-patch-id: 4574efb15f6e60ba84b21718381c19faa2d06e6a
prerequisite-patch-id: 4026283a30594ccf4c5c297a45b817d7c95dcc81
prerequisite-patch-id: 2f6425ce98f57c1833fcfc1cb963a4b00550daaa
prerequisite-patch-id: 671d4f6b289715eecf11df3b8e94e566b4e3f358
prerequisite-patch-id: 59d20ef094471e06900a58216a35fb466e6350a6
prerequisite-patch-id: 8f6ac7d59fcdd44f015dce5b41ca7e20ed551b17
prerequisite-patch-id: b3f0435a6a54a62ae2b895ede265f657b2826929
prerequisite-patch-id: 06784b4d67904e2a8eab05f652d985750aeae26a
prerequisite-patch-id: 48e9916f08c8502323eadf9595d11a3ad7cf1b0c
prerequisite-patch-id: 9c5b9353f575b545d6ba706aa33a4200dc163e1e
prerequisite-patch-id: efadc065d2991129a9fa4380ed782b9dfac9807f
prerequisite-patch-id: 5a3e46fd6d5f1324a307bd01656993131644e59d
prerequisite-patch-id: 40be26b80ff47971946da8ccca6574333b4ac511
prerequisite-patch-id: 249d8bc2c8226ea94c27e2d2db8dfda056b8221d
prerequisite-patch-id: 64c7dc66a01b47fdc1d178e4264dbfb17f65cb48
prerequisite-patch-id: 7651dda34bd7be0a7c0c58b813abbfe4e75057a5
prerequisite-patch-id: 5b677afd301ba2d8385e73d6f55ef259e69cdd06
prerequisite-patch-id: f41124cb1f7db66cf578ee87b768438dcf66227d
prerequisite-patch-id: 6a173ab5f27750a6f4a2f8adebff537f95225d38
prerequisite-patch-id: c42d87f4f18b34c20121d7a7ee22564b8f2a9c3b
prerequisite-patch-id: e4c4b6c5c635e67f641c1bb4902bb5ec1a0eb1be
prerequisite-patch-id: 197202a25498a915f35f4417efb38e8844cac309
prerequisite-patch-id: 1e23186a890510f123ecd202f8a50d2094201277
prerequisite-patch-id: ba3e7e54dfbd8370ff50d1a5e85ac06d803fe68d
prerequisite-patch-id: edcca1af6061de5006b58ff7cd52a039aec88192
prerequisite-patch-id: 50ee0f2c714091aeab155cd40a94214fd1844463
prerequisite-patch-id: 31adcc5191ebc8b2ea26ee1e4b7de78a3d8e0f48
prerequisite-patch-id: dafdb698d23a185ee4adfbf9cbaf43ea31661bc1
prerequisite-patch-id: 683d340258d86d0774c772cc5d4bc4dfc6c214ac
prerequisite-patch-id: 0052a313ada5ebbd0e24905f2b75974736dae59e
prerequisite-patch-id: 1cbdbf0cf8727d07cfb7251551bbb8f47ca4f9d8
prerequisite-patch-id: c059fdfb33923cc5d728f53136021e01cab5f316
prerequisite-patch-id: d8cd3ac99c209600a4686d85627fae2956864272
prerequisite-patch-id: 7bfa53abc0cd50a22a81782353e30f0503bf87b3
prerequisite-patch-id: a2837d8005f85e1764d2baf4c5269ac4c26d0e03
prerequisite-patch-id: c7c2ba071a328f24d36a7bc73d096f701ff049c4
prerequisite-patch-id: 49edd721efd5860bce7a6da39a3983c1729dfb09
prerequisite-patch-id: b41ba2264cf8d51fad69c0d60b23282fdcaa02ed
prerequisite-patch-id: ce1094369b939e5df1c9ff586ba6e77eadd6755b
prerequisite-patch-id: cc76aa21e68006e190b6c095a7eab1f71a350035
prerequisite-patch-id: 016dbed32a9d26e0daa7fe068846dc5bf0bab4b2
prerequisite-patch-id: ea3270295ff22f15ae5a5213ae7ef0fb24f3d90e
prerequisite-patch-id: 0d7ec035c0ac8ea612791940c47c720fd0fc0983
prerequisite-patch-id: 073689ebff4dc3ed400b7a6a09b2aa3222eb5eaf
prerequisite-patch-id: 3de9c5dcd90a94356e41cd6c3a6b3a3ebd6da40f
prerequisite-patch-id: 02173a8508f62560dfc0c873ed4f8ffd3b2da127
prerequisite-patch-id: 325c71a3064a69ed233417bb0dd06ac5afe22ecd
prerequisite-patch-id: fb5f0634575b9cd445be39af1b442f641f33669e
prerequisite-patch-id: 375ec357c82582464519ccd102ba9c9969b27ccd
prerequisite-patch-id: 96724bd515fee1e70896e427ca5443cf6c3bd1c6
prerequisite-patch-id: d11653d1691c233ceac344313e1facf239c075e6
prerequisite-patch-id: a0c4b6d4fa27a1f1738ccd7d2c1c5203f4acc10c
prerequisite-patch-id: bcf62e2802a1d35bbeb601750792f3043e18e02e
prerequisite-patch-id: b6027c3dd6b0d7a576397c3f7cead1cb2e32ab3d
prerequisite-patch-id: 2993826cfc8ecb4743d1104ce9062ce064dee436
prerequisite-patch-id: 2de773c80c1d53b349768f3a9c1dedd9473141e2
prerequisite-patch-id: dcd065f3bede4933cf1071ca0ff8f631af30537e
prerequisite-patch-id: e8f9cef7f9a80d21786bdbc63de84dad5bb0f11b
prerequisite-patch-id: adefc62a9de4bcbb15ddba73edcdb96740b8527f
prerequisite-patch-id: b8028f15bc6bcfc0053852516acd70129434ef64
prerequisite-patch-id: a9378612984ceace5d8fc99c192de3d07fad4b4c
prerequisite-patch-id: 3e64fd39d97c528b5901f648d7ab92c9b3dfebd1
prerequisite-patch-id: 6900b6fcf58f765fa3266432dc9e2eebcacfbb4f
prerequisite-patch-id: 0d796b1a9c84ad77fecacee5450ae4fe067e7748
prerequisite-patch-id: c8cd1e1f3efda1056dd2f393a43b97a675f8fc00
prerequisite-patch-id: a1e5e6ee3a85aa293485f42163c5e6fb8ed7ac6c
prerequisite-patch-id: 29865d865b97531dd5be3019e22adb1066bcd0a3
prerequisite-patch-id: f5e05f1932b2fd24d00c3a7e64a2589f9c62a4e7
prerequisite-patch-id: 9f875036c21954004d3533697f89c7b8f3f35673
prerequisite-patch-id: f0f917f79ebed24ee4cd3427393d6cc24b9f2617
prerequisite-patch-id: 949be1cb8e66006949d4654aa60cf11b990bea13
prerequisite-patch-id: a035355f8731aa2619cd876157cfd2a9321c4814
prerequisite-patch-id: d23b3af12de5f250b5aded06076390d855065d34
prerequisite-patch-id: b649f233ca196c43de136937fbcaf0a5b792a7c7
prerequisite-patch-id: 0b474fc99e8b05aee2f470e8166d715261b9eb11
prerequisite-patch-id: a8f595e6c8b9714bfc4d89a7e39d5be3a9665d87
prerequisite-patch-id: 362ec11aff3d8ddc90f8b1aeb31d0fde8785384b
prerequisite-patch-id: 3695552670237d21bbd21fef03105083754ed6d1
prerequisite-patch-id: 89f2689e530147ac5530197ff972bc44135a1fe5
prerequisite-patch-id: e4a07cbaee52cbe451bfb9938b6b2a8636cac2f0
prerequisite-patch-id: f8f8edb0e66d2612359021654361be7fd0a55b70
prerequisite-patch-id: 743f4e4444f9cac24e67abce2bda52d6a421d870
prerequisite-patch-id: 8f0d19793716d0c18759e4261ef18c6db21c7f66
prerequisite-patch-id: 016a97f4bb36008d268ed1142d4fe67263d18c5f
prerequisite-patch-id: c9b1ea941f12ec7c34d17a7a81b999cdc90a46bb
prerequisite-patch-id: 2e4f5844a1680c659f4fe9af3723f8c9e6171c98
prerequisite-patch-id: 9b218d7632794493bcc98298de79e9d881bc4de2
prerequisite-patch-id: bd18dcb6c060ae56cadb55ad248138918b4542fa
prerequisite-patch-id: 5f4f31b906f1a415721c42bb4f06e9a97e6d9826
prerequisite-patch-id: fd625a00389f10724c4df0c309f46588ff4db63e
prerequisite-patch-id: 6aa7f6e164a2fc200361fd96399ad1c10f0825e2
prerequisite-patch-id: de267e462ebf8b5fda3d3df92d84914f3d49b093
prerequisite-patch-id: 10e0c0ed7bb11a5e9d50b4210a67d56d0baa7ae7
prerequisite-patch-id: 881a354db3dcf42e71ff51e86a712fe24a82378f
prerequisite-patch-id: 471c157425528ec5fa2fe0371dfc9babeff74c57
prerequisite-patch-id: a7d752c724506c047c0c69fb568f9e3e421773b5
prerequisite-patch-id: e207260eff0bee9b47719902663721ac36371856
prerequisite-patch-id: c978ecf00ccf17014919ba6d22a634f1fa5378b8
prerequisite-patch-id: c30ea3d0e9179a8f91523e4775aa1d7697777031
prerequisite-patch-id: 9caf8f6dc88c899b90242124e9efccecf61e6580
prerequisite-patch-id: 8104c6e0f28b79353bb1fe3d6d5bd49b8a1d4656
prerequisite-patch-id: ad97388f77ab9d4cc88a369418deec6f796d9ac3
prerequisite-patch-id: 1f6acfacff835f1d7f922614262505c4acbcb067
prerequisite-patch-id: 95d5625e0f04636a4c3ec335c77f34a5fecaa952
prerequisite-patch-id: 82e613feb908a11046bdafc6e874bcd8c4f52200
prerequisite-patch-id: 5f7a850dcf2102e4ac82791ba95ed0c0bc695613
prerequisite-patch-id: 50d03e282b31737919a2b979d59c5c4c17107627
prerequisite-patch-id: 8b51bae8e714a0e5277f67ff9d1455fd2f4e36b7
prerequisite-patch-id: eee196eb6f44f53040e52305d9c48909eb3bf2c5
prerequisite-patch-id: 35494985bedf6015cb3a8c2c70f58099e9c44316
prerequisite-patch-id: c3c5c822735b385dd0e55260f514623bf3f9ff1a
prerequisite-patch-id: b21222f6f96276b46ff605bdd1d2a75c9af839ca
prerequisite-patch-id: b63e092548d498d642b6363eae9c98247f5300f9
prerequisite-patch-id: 99cf93d15a50ad94c049c736b375bbdb77cf0ef6
prerequisite-patch-id: e2d86b651e3ff2f70848f827b29cc804cead48b2
prerequisite-patch-id: 1ec76b0303530aaa120186fb249252cd3a1bd7ec
prerequisite-patch-id: 9a35b1041fb252654255045df37478c8eb15a501
prerequisite-patch-id: e7227e60ea90415b54c6fcd553ddece24dd402fc
prerequisite-patch-id: 2f45861307fafa6a5696098406e164e166f4d207
prerequisite-patch-id: ab037b78ccf8a9db312333f5e01e6fd2e54832ca
prerequisite-patch-id: 9c886d5ccd279d6f283fcd60a794e66c94fe782d
prerequisite-patch-id: fa5a4fc2f2d77e9ad000d7477f56b822efce457f
prerequisite-patch-id: a0699fc9eb0ee36f53bc937770887d6086d2a7b8
prerequisite-patch-id: b383634edd50afef4180be293861d1014491d86d
prerequisite-patch-id: 2f404a754f2e1048165df254e963e26f6789de7f
prerequisite-patch-id: 07d59a1d0796816d8421b5a236175b1568d1f63f
prerequisite-patch-id: 9f904d43a86cb4e55a2a00440dd042ec717c8eb8
prerequisite-patch-id: b30b252bdf0646403dbd132c7dc629188e4f6a4b
prerequisite-patch-id: 73e2691afad05a42cb6cb5a28894eb958516f39c
prerequisite-patch-id: ef0f8b6061c55ada19107f026164c8598ebc66bd
prerequisite-patch-id: da21009a2dbc3384309cfdc4c49e10b86de6e747
prerequisite-patch-id: 2ef5022df54288b85ef1c8fe4e7a02a03d4577ff
prerequisite-patch-id: 5193b8507248975783d1eb6bc911265e6b55988e
prerequisite-patch-id: 1aef895eb9c159d33d617d7b2475928f75a73303
prerequisite-patch-id: bf87652bd502aeaf671da92e243553fb9a94f5d5
prerequisite-patch-id: cf9856dfd70d154fab043ffd2ee89288d9d41827
prerequisite-patch-id: f9daf7a441685aa6d25225b6616e51be5fcfe772
prerequisite-patch-id: 0101aa9af501543384863fa8c090febd6939f80f
prerequisite-patch-id: ccf1ac224734562e2f4207847b8128cd3c8b9d31
prerequisite-patch-id: 589ae86ee30b01355ce220ab9fc89c5403d95076
prerequisite-patch-id: 6e809a44a0ef69883eb812f8a4b57eb52ad32f41
prerequisite-patch-id: 116d110f795045527d54f2897e1ac12bb2f59238
prerequisite-patch-id: f4e0f48a8ce61bc6c229a18bf41f4b3cdec3a9d0
prerequisite-patch-id: e78df0253e48cdf5f9e44c17a169fc9cccb82c7e
prerequisite-patch-id: 1e6951da0eba531f4b445996167fea1e7320e3ae
prerequisite-patch-id: b1903fb1a742dd33ebb635299c725e9fc2a4e9ae
prerequisite-patch-id: eb07c15789948b34c0b219ff05f61c530882845d
prerequisite-patch-id: 92c0ba647ef4b4b7e83297554f6fa7e31f3a8fb5
prerequisite-patch-id: f968b1250e573119cb65aab0b98c225d8a7c4d8a
prerequisite-patch-id: 5e6dee90fe5f7a891794b5ea6bed41b1157c2930
prerequisite-patch-id: 3b10245cae08595a6bcbdc82ff836becaf6d04d2
prerequisite-patch-id: d7f15f333560e8ccfe2ad073e99ca4ef502e15d1
prerequisite-patch-id: 4c95c2badbd5911a7405a64e0d84e3091526444d
prerequisite-patch-id: f839c9824865564c12cbb7064ff455f34dc039f7
prerequisite-patch-id: 071e2570569f005c75ed7d8bf112db80cca310e5
prerequisite-patch-id: 7ee42594ecf51591428ae7f13bfb8403affed8cb
prerequisite-patch-id: 4b2105c900cf8ed047a9c0d1866fb2bdb4f9a59e
prerequisite-patch-id: dd4697ba0013408e637223fadd027c9b34945060
prerequisite-patch-id: e0881345b919ec25525c626303ba5d5e160f97f2
prerequisite-patch-id: fc6865c7e1fb19530ac8e77090eaa0b179f70496
prerequisite-patch-id: e3b8081ed28b7f0d370548044237287f52179967
prerequisite-patch-id: b672da115531fc52a591c9e50ac4da9e8b09e144
prerequisite-patch-id: f2764b91aa819feb1879d007993bda7aeb7f5df6
prerequisite-patch-id: dfb13890022578746ce611a965c62c34905b1f18
prerequisite-patch-id: bef3730ba816c84cb056d12e30b91a8c1f4b6aac
prerequisite-patch-id: 265211a01667357c86ce905ee33e4adbb81887d9
prerequisite-patch-id: c02d2492949e079494b9552c397e689774fad639
prerequisite-patch-id: 0f4180d693806ae210396ec1512be8e1d45c9530
prerequisite-patch-id: 22b486e7286a8b1a8ef90d3f1f4a4d48e43fb25c
prerequisite-patch-id: 0020828bf1b65907c906fb9ebf24104a5e72c790
prerequisite-patch-id: 4afad41c227028a4c6c35d1c43b0ee7883852a1e
prerequisite-patch-id: 890e19d588eca2dacfb83475c19ac461c0d83058
prerequisite-patch-id: f35d03d5ed63be69d2dfec77d07b28d21c40dc9a
prerequisite-patch-id: 2bebc000037d37260152802423445d39bc463f8e
prerequisite-patch-id: ccbec53de5ad88beb7657680ae6aa167f3505fd6
prerequisite-patch-id: 3c588bad04050087679a1d4f5479efb0da2537bb
prerequisite-patch-id: 87d915c6c5495d2accc7864dc592f2f651012fca
prerequisite-patch-id: a327cf20636f57b5feb31928c49d6517f102a709
prerequisite-patch-id: 8106cf8afd07cf37f3ecd63b831f1a22fa99998a
prerequisite-patch-id: a4ff39b72413dc2d894d269629919ce5199eb0fd
prerequisite-patch-id: c0db74dd58a097e7130420bd294b0f3d200730be
prerequisite-patch-id: df5bd199584a63d1ca2af8ca5e9bc659baffb8ab
prerequisite-patch-id: 9f8d32c0a8df05688a4e6779d45538056d891a72
prerequisite-patch-id: 167566e1096e56d7189393aed3528b8047421a2b
prerequisite-patch-id: 5ade75da262706c05c72bc2e1095cdc137334928
prerequisite-patch-id: 725cd8d55b55117b8732240a36ef6dd57560b7aa
prerequisite-patch-id: 2283e8ab28c671cd97fdba344bad9fad3b740955
prerequisite-patch-id: d86fed5ed934d2622a0e640677483dbd5e493b50
prerequisite-patch-id: 5a523603c0cc2344952de69d65a1dd6c9c28b1b0
prerequisite-patch-id: 8276956515aab9f3e81a9b4d51f5d270fea82c8b
prerequisite-patch-id: 1c0b8c20b01944262081a7fac4905a24a1f51afd
prerequisite-patch-id: 90b6ed9e4633014209d3291157104fe2db6cc268
prerequisite-patch-id: b78d480e28a5684e5a04f9e2d1dc6c8d6b6115d8
prerequisite-patch-id: 85129a45f66a9afd1d6aeb78a266f2b33131effc
prerequisite-patch-id: 46c2c0f251c385f740ec0f021ddf71b214dcf188
prerequisite-patch-id: de94541c97cd5dfb8f02b4210557a29264c60f28
prerequisite-patch-id: cb4a135f378247e43ecb9c5c1ca421e778356cd3
prerequisite-patch-id: 6941030e002fe4dac24a7e431297837bcebd6637
prerequisite-patch-id: 16ed31acf9114e5bcdeab9ac6f8b3c1d460d40ab
prerequisite-patch-id: 5a24fb875f0c703d031c3dcfd40faf2072a691b1
prerequisite-patch-id: 278384975e9224209b9df58781cb0d57d33cce91
prerequisite-patch-id: 8b4be8616dd4f2e1b6189657017e81999e3379bf
prerequisite-patch-id: 99853a3b8283b9aae581ec9c7a4b30dd27a9075f
prerequisite-patch-id: a48c177e8a82248dfd6642c35da34019d765a4a8
prerequisite-patch-id: 6b4419d64c7d1e887578e30a73fc476aad5408a6
prerequisite-patch-id: 93b79b926b74052e9bbba631e0f30da89c1dd0ec
prerequisite-patch-id: 9fe442b02446f58ea358d748da5f5f82805bc7ef
prerequisite-patch-id: 26828312870404b6611ccd685b162aa082dfce57
prerequisite-patch-id: 6ce31c6bb1a2b79ca465dca7a1157d1bb379d51b
prerequisite-patch-id: e6b4e8bd8a45796125d4fdcc169f97f5a3fb8bf8
prerequisite-patch-id: 94637d65272a73ec3e2b19dc3595d864fdea4836
prerequisite-patch-id: dd5dfa3e4d58a7db1f158bcc0daec057c028ce00
prerequisite-patch-id: 2295114d438c62a2128620775fc0300b0b418ff9
prerequisite-patch-id: 080adcee4042fd9511680fb10beebcae24a4dc06
prerequisite-patch-id: 022f540464bfd6c2202cdeb5530502903d207417
prerequisite-patch-id: 5ffcb1ea5dafbfe47753ce4165afa1f99d46cc82
prerequisite-patch-id: c4dcb2f3f063115727c204d3e0b0ef7c7a66cda9
prerequisite-patch-id: 984a29d2480696456528847eb7365e5785613ab6
prerequisite-patch-id: fa4b35b9b0874bdf8057f88303e204ff3b6e0538
prerequisite-patch-id: 12dac397d93e001201a2b8fcbadbca24a91a1f5a
prerequisite-patch-id: 51112edb6d85135a1930262e7a63f8f2fad3b22d
-- 
2.45.2


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 318+ messages in thread

* [PATCH v12 1/4] contrib/: Add support for Cc: and Link: tags
  2024-08-31 14:56   ` [PATCH v12 0/4] " Alejandro Colomar
@ 2024-08-31 14:56     ` Alejandro Colomar
  2024-08-31 14:56     ` [PATCH v12 2/4] gcc/: Rename array_type_nelts() => array_type_nelts_minus_one() Alejandro Colomar
                       ` (3 subsequent siblings)
  4 siblings, 0 replies; 318+ messages in thread
From: Alejandro Colomar @ 2024-08-31 14:56 UTC (permalink / raw)
  To: gcc-patches
  Cc: Alejandro Colomar, Joseph Myers, Gabriel Ravier, Jakub Jelinek,
	Kees Cook, Qing Zhao, Jens Gustedt, David Brown, Florian Weimer,
	Andreas Schwab, Timm Baeder, Daniel Plakosh, A. Jiang,
	Eugene Zelenko, Aaron Ballman, Paul Koning, Daniel Lundin,
	Nikolaos Strimpas, JeanHeyd Meneide, Fernando Borretti,
	Jonathan Protzenko, Chris Bazley, Ville Voutilainen,
	Alex Celeste, Jakub Łukasiewicz, Douglas McIlroy,
	Jason Merrill, Xavier Del Campo Romero, Martin Uecker,
	Siddhesh Poyarekar, DJ Delorie, Carlos O'Donell,
	Stephen Coady, ganandan, mnewsome

[-- Attachment #1: Type: text/plain, Size: 1258 bytes --]

contrib/ChangeLog:

	* gcc-changelog/git_commit.py (GitCommit):
	Add support for 'Cc: ' and 'Link: ' tags.

Cc: Jason Merrill <jason@redhat.com>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
---
 contrib/gcc-changelog/git_commit.py | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/contrib/gcc-changelog/git_commit.py b/contrib/gcc-changelog/git_commit.py
index 87ecb9e1a17..64fb986b74c 100755
--- a/contrib/gcc-changelog/git_commit.py
+++ b/contrib/gcc-changelog/git_commit.py
@@ -182,7 +182,8 @@ CO_AUTHORED_BY_PREFIX = 'co-authored-by: '
 
 REVIEW_PREFIXES = ('reviewed-by: ', 'reviewed-on: ', 'signed-off-by: ',
                    'acked-by: ', 'tested-by: ', 'reported-by: ',
-                   'suggested-by: ')
+                   'suggested-by: ', 'cc: ')
+LINK_PREFIXES = ('link: ')
 DATE_FORMAT = '%Y-%m-%d'
 
 
@@ -524,6 +525,8 @@ class GitCommit:
                     continue
                 elif lowered_line.startswith(REVIEW_PREFIXES):
                     continue
+                elif lowered_line.startswith(LINK_PREFIXES):
+                    continue
                 else:
                     m = cherry_pick_regex.search(line)
                     if m:
-- 
2.45.2


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 318+ messages in thread

* [PATCH v12 2/4] gcc/: Rename array_type_nelts() => array_type_nelts_minus_one()
  2024-08-31 14:56   ` [PATCH v12 0/4] " Alejandro Colomar
  2024-08-31 14:56     ` [PATCH v12 1/4] contrib/: Add support for Cc: and Link: tags Alejandro Colomar
@ 2024-08-31 14:56     ` Alejandro Colomar
  2024-08-31 14:56     ` [PATCH v12 3/4] Merge definitions of array_type_nelts_top() Alejandro Colomar
                       ` (2 subsequent siblings)
  4 siblings, 0 replies; 318+ messages in thread
From: Alejandro Colomar @ 2024-08-31 14:56 UTC (permalink / raw)
  To: gcc-patches
  Cc: Alejandro Colomar, Joseph Myers, Gabriel Ravier, Jakub Jelinek,
	Kees Cook, Qing Zhao, Jens Gustedt, David Brown, Florian Weimer,
	Andreas Schwab, Timm Baeder, Daniel Plakosh, A. Jiang,
	Eugene Zelenko, Aaron Ballman, Paul Koning, Daniel Lundin,
	Nikolaos Strimpas, JeanHeyd Meneide, Fernando Borretti,
	Jonathan Protzenko, Chris Bazley, Ville Voutilainen,
	Alex Celeste, Jakub Łukasiewicz, Douglas McIlroy,
	Jason Merrill, Xavier Del Campo Romero, Martin Uecker,
	Siddhesh Poyarekar, DJ Delorie, Carlos O'Donell,
	Stephen Coady, ganandan, mnewsome, Richard Biener

[-- Attachment #1: Type: text/plain, Size: 12749 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>

gcc/ChangeLog:

	* tree.cc (array_type_nelts, array_type_nelts_minus_one)
	* tree.h (array_type_nelts, array_type_nelts_minus_one)
	* expr.cc (count_type_elements)
	* config/aarch64/aarch64.cc
	(pure_scalable_type_info::analyze_array)
	* config/i386/i386.cc (ix86_canonical_va_list_type):
	Rename array_type_nelts() => array_type_nelts_minus_one()
	The old name was misleading.

gcc/c/ChangeLog:

	* c-decl.cc (one_element_array_type_p, get_parm_array_spec)
	* c-fold.cc (c_fold_array_ref):
	Rename array_type_nelts() => array_type_nelts_minus_one()

gcc/cp/ChangeLog:

	* decl.cc (reshape_init_array)
	* init.cc
	(build_zero_init_1)
	(build_value_init_noctor)
	(build_vec_init)
	(build_delete)
	* lambda.cc (add_capture)
	* tree.cc (array_type_nelts_top):
	Rename array_type_nelts() => array_type_nelts_minus_one()

gcc/fortran/ChangeLog:

	* trans-array.cc (structure_alloc_comps)
	* trans-openmp.cc
	(gfc_walk_alloc_comps)
	(gfc_omp_clause_linear_ctor):
	Rename array_type_nelts() => array_type_nelts_minus_one()

gcc/rust/ChangeLog:

	* backend/rust-tree.cc (array_type_nelts_top):
	Rename array_type_nelts() => array_type_nelts_minus_one()

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>
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 aa7f69d1b7b..c73d3107efb 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -5358,7 +5358,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]".  */
@@ -6306,15 +6306,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 27e24ba70ab..21606701725 100644
--- a/gcc/config/aarch64/aarch64.cc
+++ b/gcc/config/aarch64/aarch64.cc
@@ -1084,7 +1084,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 546c964d2a4..c6407843fc5 100644
--- a/gcc/config/i386/i386.cc
+++ b/gcc/config/i386/i386.cc
@@ -24393,7 +24393,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 6458e96bded..98133894c48 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -6908,7 +6908,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 320be8b17a1..803da754be1 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 8c35926436d..22ac3c1a5f3 100644
--- a/gcc/fortran/trans-array.cc
+++ b/gcc/fortran/trans-array.cc
@@ -9640,7 +9640,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 b14cfbe7929..7439777f307 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;
 
@@ -14789,7 +14789,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 93aa7d22d6f..4e29544a36c 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] 318+ messages in thread

* [PATCH v12 3/4] Merge definitions of array_type_nelts_top()
  2024-08-31 14:56   ` [PATCH v12 0/4] " Alejandro Colomar
  2024-08-31 14:56     ` [PATCH v12 1/4] contrib/: Add support for Cc: and Link: tags Alejandro Colomar
  2024-08-31 14:56     ` [PATCH v12 2/4] gcc/: Rename array_type_nelts() => array_type_nelts_minus_one() Alejandro Colomar
@ 2024-08-31 14:56     ` Alejandro Colomar
  2024-08-31 14:56     ` [PATCH v12 4/4] c: Add __nelementsof__ operator Alejandro Colomar
  2024-10-02  8:34     ` [PATCH v12 0/4] " Alejandro Colomar
  4 siblings, 0 replies; 318+ messages in thread
From: Alejandro Colomar @ 2024-08-31 14:56 UTC (permalink / raw)
  To: gcc-patches
  Cc: Alejandro Colomar, Joseph Myers, Gabriel Ravier, Jakub Jelinek,
	Kees Cook, Qing Zhao, Jens Gustedt, David Brown, Florian Weimer,
	Andreas Schwab, Timm Baeder, Daniel Plakosh, A. Jiang,
	Eugene Zelenko, Aaron Ballman, Paul Koning, Daniel Lundin,
	Nikolaos Strimpas, JeanHeyd Meneide, Fernando Borretti,
	Jonathan Protzenko, Chris Bazley, Ville Voutilainen,
	Alex Celeste, Jakub Łukasiewicz, Douglas McIlroy,
	Jason Merrill, Xavier Del Campo Romero, Martin Uecker,
	Siddhesh Poyarekar, DJ Delorie, Carlos O'Donell,
	Stephen Coady, ganandan, mnewsome

[-- Attachment #1: Type: text/plain, Size: 4880 bytes --]

There were two identical definitions, and none of them are available
where they are needed for implementing __nelementsof__.  Merge them, and
provide the single definition in gcc/tree.{h,cc}, where it's available
for __nelementsof__, 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 2eeb5e3e8b1..6913175c3ce 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -8108,7 +8108,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 7439777f307..d0a7156d982 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 4e29544a36c..372f4dd71da 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] 318+ messages in thread

* [PATCH v12 4/4] c: Add __nelementsof__ operator
  2024-08-31 14:56   ` [PATCH v12 0/4] " Alejandro Colomar
                       ` (2 preceding siblings ...)
  2024-08-31 14:56     ` [PATCH v12 3/4] Merge definitions of array_type_nelts_top() Alejandro Colomar
@ 2024-08-31 14:56     ` Alejandro Colomar
  2024-10-02  8:34     ` [PATCH v12 0/4] " Alejandro Colomar
  4 siblings, 0 replies; 318+ messages in thread
From: Alejandro Colomar @ 2024-08-31 14:56 UTC (permalink / raw)
  To: gcc-patches
  Cc: Alejandro Colomar, Joseph Myers, Gabriel Ravier, Jakub Jelinek,
	Kees Cook, Qing Zhao, Jens Gustedt, David Brown, Florian Weimer,
	Andreas Schwab, Timm Baeder, Daniel Plakosh, A. Jiang,
	Eugene Zelenko, Aaron Ballman, Paul Koning, Daniel Lundin,
	Nikolaos Strimpas, JeanHeyd Meneide, Fernando Borretti,
	Jonathan Protzenko, Chris Bazley, Ville Voutilainen,
	Alex Celeste, Jakub Łukasiewicz, Douglas McIlroy,
	Jason Merrill, Xavier Del Campo Romero, Martin Uecker,
	Siddhesh Poyarekar, DJ Delorie, Carlos O'Donell,
	Stephen Coady, ganandan, mnewsome

[-- Attachment #1: Type: text/plain, Size: 30966 bytes --]

This operator is similar to sizeof but can only be applied to an array,
and returns its number of elements.

FUTURE DIRECTIONS:

-  We should make it work with array parameters to functions,
   and somehow magically return the number of elements of the array,
   regardless of it being really a pointer.

-  Fix support for [0].

gcc/ChangeLog:

	* doc/extend.texi: Document __nelementsof__ operator.
	* target.h (enum type_context_kind): Add __nelementsof__ operator.

gcc/c-family/ChangeLog:

	* c-common.h
	* c-common.def:
	* c-common.cc (c_nelementsof_type): Add __nelementsof__ operator.

gcc/c/ChangeLog:

	* c-tree.h
	(c_expr_nelementsof_expr, c_expr_nelementsof_type)
	* c-decl.cc
	(start_struct, finish_struct)
	(start_enum, finish_enum)
	* c-parser.cc
	(c_parser_sizeof_expression)
	(c_parser_nelementsof_expression)
	(c_parser_sizeof_or_nelementsof_expression)
	(c_parser_unary_expression)
	* c-typeck.cc
	(build_external_ref)
	(record_maybe_used_decl, pop_maybe_used)
	(is_top_array_vla)
	(c_expr_nelementsof_expr, c_expr_nelementsof_type):
	Add __nelementsof__operator.

gcc/cp/ChangeLog:

	* operators.def: Add __nelementsof__ operator.

gcc/testsuite/ChangeLog:

	* gcc.dg/nelementsof-compile.c
	* gcc.dg/nelementsof-vla.c
	* gcc.dg/nelementsof.c: Add tests for __nelementsof__ operator.

Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3313.pdf>
Link: <https://inbox.sourceware.org/gcc/M8S4oQy--3-2@tutanota.com/T/>
Link: <https://github.com/llvm/llvm-project/issues/102836>
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>
Cc: Daniel Plakosh <dplakosh@cert.org>
Cc: "A. Jiang" <de34@live.cn>
Cc: Eugene Zelenko <eugene.zelenko@gmail.com>
Cc: Aaron Ballman <aaron.ballman@intel.com>
Cc: Paul Koning <paulkoning@comcast.net>
Cc: Daniel Lundin <daniel.lundin.mail@gmail.com>
Cc: Nikolaos Strimpas <Strnik86@protonmail.com>
Cc: JeanHeyd Meneide <phdofthehouse@gmail.com>
Cc: Fernando Borretti <fernando@borretti.me>
Cc: Jonathan Protzenko <jonathan.protzenko@ens-lyon.org>
Cc: Chris Bazley <Chris.Bazley@arm.com>
Cc: Ville Voutilainen <ville.voutilainen@gmail.com>
Cc: Alex Celeste <alexg.nvfp@gmail.com>
Cc: Jakub Łukasiewicz <jakublukasiewicz@outlook.com>
Cc: Douglas McIlroy <douglas.mcilroy@dartmouth.edu>
Cc: Jason Merrill <jason@redhat.com>
Suggested-by: Xavier Del Campo Romero <xavi.dcr@tutanota.com>
Co-authored-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                            |  22 ++-
 gcc/c/c-parser.cc                          |  62 +++++++--
 gcc/c/c-tree.h                             |   4 +
 gcc/c/c-typeck.cc                          | 118 +++++++++++++++-
 gcc/cp/operators.def                       |   1 +
 gcc/doc/extend.texi                        |  30 +++++
 gcc/target.h                               |   3 +
 gcc/testsuite/gcc.dg/nelementsof-compile.c | 115 ++++++++++++++++
 gcc/testsuite/gcc.dg/nelementsof-vla.c     |  46 +++++++
 gcc/testsuite/gcc.dg/nelementsof.c         | 150 +++++++++++++++++++++
 13 files changed, 558 insertions(+), 24 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/nelementsof-compile.c
 create mode 100644 gcc/testsuite/gcc.dg/nelementsof-vla.c
 create mode 100644 gcc/testsuite/gcc.dg/nelementsof.c

diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
index e7e371fd26f..188bb9b65ef 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 },
+  { "__nelementsof__",	RID_NELEMENTSOF, 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 lementsof keyword:
+   Return the number of elements of an array.  */
+
+tree
+c_nelementsof_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 %<nelementsof%> to type %qT", type);
+      return error_mark_node;
+    }
+  if (!COMPLETE_TYPE_P (type))
+    {
+      error_at (loc,
+		"invalid application of %<nelementsof%> 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..12ee0d2adb3 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 'nelementsof' expression.  */
+DEFTREECODE (NELEMENTSOF_EXPR, "nelementsof_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 d3827573a36..66b705d42e1 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_NELEMENTSOF,
   RID_VA_ARG,
   RID_EXTENSION, RID_IMAGPART, RID_REALPART, RID_LABEL,    RID_CHOOSE_EXPR,
   RID_TYPES_COMPATIBLE_P,      RID_BUILTIN_COMPLEX,	   RID_BUILTIN_SHUFFLE,
@@ -887,6 +888,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_nelementsof_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 c73d3107efb..e4385293ee1 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -8992,12 +8992,17 @@ 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_nelementsof))
     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"
+		       : "nelementsof"))));
 
   if (in_underspecified_init)
     error_at (loc, "%qT defined in underspecified object initializer", ref);
@@ -9957,7 +9962,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_nelementsof)
 	struct_parse_info->struct_types.safe_push (t);
      }
 
@@ -10131,12 +10136,17 @@ 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_nelementsof))
     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"
+		       : "nelementsof"))));
 
   if (in_underspecified_init)
     error_at (loc, "%qT defined in underspecified object initializer",
@@ -10330,7 +10340,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_nelementsof)
     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 aff5af17430..24a01e08baf 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_nelementsof_expression (parser, RID_SIZEOF)              \
+)
 
+#define c_parser_nelementsof_expression(parser)                               \
+(                                                                             \
+  c_parser_sizeof_or_nelementsof_expression (parser, RID_NELEMENTSOF)         \
+)
+\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,8 @@ 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_nelementsof_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 *,
@@ -9910,6 +9921,8 @@ c_parser_unary_expression (c_parser *parser)
     case CPP_KEYWORD:
       switch (c_parser_peek_token (parser)->keyword)
 	{
+	case RID_NELEMENTSOF:
+	  return c_parser_nelementsof_expression (parser);
 	case RID_SIZEOF:
 	  return c_parser_sizeof_expression (parser);
 	case RID_ALIGNOF:
@@ -9949,12 +9962,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_nelementsof_expression (c_parser *parser, enum rid rid)
 {
+  const char *op_name = (rid == RID_NELEMENTSOF) ? "nelementsof" : "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;
@@ -9963,7 +9977,10 @@ c_parser_sizeof_expression (c_parser *parser)
 
   c_parser_consume_token (parser);
   c_inhibit_evaluation_warnings++;
-  in_sizeof++;
+  if (rid == RID_NELEMENTSOF)
+    in_nelementsof++;
+  else
+    in_sizeof++;
   if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)
       && c_token_starts_compound_literal (c_parser_peek_2nd_token (parser)))
     {
@@ -9982,7 +9999,10 @@ c_parser_sizeof_expression (c_parser *parser)
 	{
 	  struct c_expr ret;
 	  c_inhibit_evaluation_warnings--;
-	  in_sizeof--;
+	  if (rid == RID_NELEMENTSOF)
+	    in_nelementsof--;
+	  else
+	    in_sizeof--;
 	  ret.set_error ();
 	  ret.original_code = ERROR_MARK;
 	  ret.original_type = NULL;
@@ -9994,31 +10014,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_NELEMENTSOF)
+	{
+	  in_nelementsof--;
+	  result = c_expr_nelementsof_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_NELEMENTSOF)
+	in_nelementsof--;
+      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_NELEMENTSOF)
+	result = c_expr_nelementsof_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 57befb94c08..4ea45661bc9 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_nelementsof;
 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_nelementsof_expr (location_t, struct c_expr);
+extern struct c_expr c_expr_nelementsof_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..651e5c15b87 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 "nelementsof".  */
+int in_nelementsof;
+
 /* 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_nelementsof)
 	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_nelementsof).  */
   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_nelementsof;
   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_nelementsof;
   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 nelementsof applied to EXPR.  */
+
+struct c_expr
+c_expr_nelementsof_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_nelementsof_type (loc, TREE_TYPE (folded_expr));
+      c_last_sizeof_arg = expr.value;
+      c_last_sizeof_loc = loc;
+      ret.original_code = NELEMENTSOF_EXPR;
+      ret.original_type = NULL;
+      ret.m_decimal = 0;
+      if (is_top_array_vla (TREE_TYPE (folded_expr)))
+	{
+	  /* nelementsof 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 nelementsof applied to T, a structure for the type
+   name passed to nelementsof (rather than the type itself).  LOC is the
+   location of the original expression.  */
+
+struct c_expr
+c_expr_nelementsof_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_nelementsof_type (loc, type);
+  c_last_sizeof_arg = type;
+  c_last_sizeof_loc = loc;
+  ret.original_code = NELEMENTSOF_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 nelementsof 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 nelementsof 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..7f1d24779c8 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 ("__nelementsof__", NELEMENTSOF_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 5845bcedf6e..3057d39f873 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -10544,6 +10544,36 @@ 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 nelementsof
+@section Determining the Number of Elements of Arrays
+@cindex nelementsof
+@cindex number of elements
+
+The keyword @code{__elemetsf__} 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 parenthesized complete array type name
+or an expression of such a type.
+For example:
+
+@smallexample
+int a[n];
+__elemetsf__ (a);  // returns n
+__elemetsf__ (int [7][3]);  // returns 7
+@end smallexample
+
+The result of this operator is an integer constant expression,
+unless the top-level array is a variable-length array.
+The operand is only evaluated
+if the top-level array is a variable-length array.
+For example:
+
+@smallexample
+__elemetsf__ (int [7][n++]);  // integer constant expression
+__elemetsf__ (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..09245d70c1f 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 number of elements of array T.  */
+  TCTX_NELEMENTSOF,
+
   /* Creating objects of type T with static storage duration.  */
   TCTX_STATIC_STORAGE,
 
diff --git a/gcc/testsuite/gcc.dg/nelementsof-compile.c b/gcc/testsuite/gcc.dg/nelementsof-compile.c
new file mode 100644
index 00000000000..211b63fa7b5
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/nelementsof-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[__nelementsof__(z)];
+
+void
+automatic(void)
+{
+  __nelementsof__ (w);
+}
+
+void
+incomplete (int p[])
+{
+  __nelementsof__ (x);  /* { dg-error "incomplete" } */
+
+  /* We want to support the following one in the future,
+     but for now it should fail.  */
+  __nelementsof__ (p);  /* { dg-error "invalid" } */
+}
+
+void
+fam (void)
+{
+  struct {
+    int x;
+    int fam[];
+  } s;
+
+  __nelementsof__ (s.fam); /* { dg-error "incomplete" } */
+}
+
+void fix_fix (int i, char (*a)[3][5], int (*x)[__nelementsof__ (*a)]);
+void fix_var (int i, char (*a)[3][i], int (*x)[__nelementsof__ (*a)]);
+void fix_uns (int i, char (*a)[3][*], int (*x)[__nelementsof__ (*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;
+
+  __nelementsof__ (x); /* { dg-error "invalid" } */
+  __nelementsof__ (int); /* { dg-error "invalid" } */
+  __nelementsof__ (s); /* { dg-error "invalid" } */
+  __nelementsof__ (struct s); /* { dg-error "invalid" } */
+  __nelementsof__ (&x); /* { dg-error "invalid" } */
+  __nelementsof__ (p); /* { dg-error "invalid" } */
+  __nelementsof__ (int *); /* { dg-error "invalid" } */
+  __nelementsof__ (&s.x); /* { dg-error "invalid" } */
+  __nelementsof__ (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];
+
+  __nelementsof__ (a[f1()]);
+  __nelementsof__ (b[f2()]);
+}
+
+void
+no_parens(void)
+{
+  __nelementsof__ a;
+  __nelementsof__ *a;
+  __nelementsof__ (int [3]) {};
+
+  __nelementsof__ int [3]; /* { dg-error "expected expression before" } */
+}
+
+void
+const_expr(void)
+{
+  int n = 7;
+
+  _Static_assert (__nelementsof__ (int [3][n]) == 3);
+  _Static_assert (__nelementsof__ (int [n][3]) == 7); /* { dg-error "not constant" } */
+  _Static_assert (__nelementsof__ (int [0][3]) == 0);
+  _Static_assert (__nelementsof__ (int [0]) == 0);
+
+  /* FIXME: nelementsof(int [0][n]) should result in a constant expression.  */
+  _Static_assert (__nelementsof__ (int [0][n]) == 0); /* { dg-error "not constant" } */
+}
diff --git a/gcc/testsuite/gcc.dg/nelementsof-vla.c b/gcc/testsuite/gcc.dg/nelementsof-vla.c
new file mode 100644
index 00000000000..0cd4dfd37fa
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/nelementsof-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)[__nelementsof__ (*a)]);
+void fix_var (int i,
+	      char (*a)[3][i], /* dg-warn "variable" */
+	      int (*x)[__nelementsof__ (*a)]);
+void fix_uns (int i,
+	      char (*a)[3][*],
+	      int (*x)[__nelementsof__ (*a)]);
+
+void zro_fix (int i,
+	      char (*a)[0][5],
+	      int (*x)[__nelementsof__ (*a)]);
+void zro_var (int i,
+	      char (*a)[0][i], /* dg-warn "variable" */
+	      int (*x)[__nelementsof__ (*a)]);
+void zro_uns (int i,
+	      char (*a)[0][*],
+	      int (*x)[__nelementsof__ (*a)]);
+
+void var_fix (int i,
+	      char (*a)[i][5], /* dg-warn "variable" */
+	      int (*x)[__nelementsof__ (*a)]); /* dg-warn "variable" */
+void var_var (int i,
+	      char (*a)[i][i], /* dg-warn "variable" */
+	      int (*x)[__nelementsof__ (*a)]); /* dg-warn "variable" */
+void var_uns (int i,
+	      char (*a)[i][*], /* dg-warn "variable" */
+	      int (*x)[__nelementsof__ (*a)]); /* dg-warn "variable" */
+
+void uns_fix (int i,
+	      char (*a)[*][5],
+	      int (*x)[__nelementsof__ (*a)]);
+void uns_var (int i,
+	      char (*a)[*][i], /* dg-warn "variable" */
+	      int (*x)[__nelementsof__ (*a)]);
+void uns_uns (int i,
+	      char (*a)[*][*],
+	      int (*x)[__nelementsof__ (*a)]);
+
+// Can't test due to bug: <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=116284>
+//static int z2[0];
+//static int y2[__nelementsof__(z2)];
diff --git a/gcc/testsuite/gcc.dg/nelementsof.c b/gcc/testsuite/gcc.dg/nelementsof.c
new file mode 100644
index 00000000000..292311e2822
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/nelementsof.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 (__nelementsof__ (a) == 7);
+  static_assert (__nelementsof__ (long [0]) == 0);
+  static_assert (__nelementsof__ (unsigned [99]) == 99);
+}
+
+void
+automatic(void)
+{
+  int a[] = {1, 2, 3};
+  int z[] = {};
+
+  static_assert (__nelementsof__ (a) == 3);
+  static_assert (__nelementsof__ (z) == 0);
+}
+
+void
+vla (void)
+{
+  unsigned n;
+
+  n = 99;
+  assert (__nelementsof__ (short [n - 10]) == 99 - 10);
+
+  int v[n / 2];
+  assert (__nelementsof__ (v) == 99 / 2);
+
+  n = 0;
+  int z[n];
+  assert (__nelementsof__ (z) == 0);
+}
+
+void
+member (void)
+{
+  struct {
+    int a[8];
+  } s;
+
+  static_assert (__nelementsof__ (s.a) == 8);
+}
+
+void
+vla_eval (void)
+{
+  int i;
+
+  i = 7;
+  assert (__nelementsof__ (struct {int x;}[i++]) == 7);
+  assert (i == 7 + 1);
+
+  int v[i];
+  int (*p)[i];
+  p = &v;
+  assert (__nelementsof__ (*p++) == i);
+  assert (p - 1 == &v);
+}
+
+void
+inner_vla_noeval (void)
+{
+  int i;
+
+  i = 3;
+  static_assert (__nelementsof__ (struct {int x[i++];}[3]) == 3);
+  assert (i == 3);
+}
+
+void
+array_noeval (void)
+{
+  long a[5];
+  long (*p)[__nelementsof__ (a)];
+
+  p = &a;
+  static_assert (__nelementsof__ (*p++) == 5);
+  assert (p == &a);
+}
+
+void
+matrix_zero (void)
+{
+  int i;
+
+  static_assert (__nelementsof__ (int [0][4]) == 0);
+  i = 3;
+  assert (__nelementsof__ (int [0][i]) == 0);
+}
+
+void
+matrix_fixed (void)
+{
+  int i;
+
+  static_assert (__nelementsof__ (int [7][4]) == 7);
+  i = 3;
+  static_assert (__nelementsof__ (int [7][i]) == 7);
+}
+
+void
+matrix_vla (void)
+{
+  int i, j;
+
+  i = 7;
+  assert (__nelementsof__ (int [i++][4]) == 7);
+  assert (i == 7 + 1);
+
+  i = 9;
+  j = 3;
+  assert (__nelementsof__ (int [i++][j]) == 9);
+  assert (i == 9 + 1);
+}
+
+void
+no_parens(void)
+{
+  int n = 3;
+  int a[7];
+  int v[n];
+
+  static_assert (__nelementsof__ a == 7); 
+  assert (__nelementsof__ 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] 318+ messages in thread

* VLA is a misnomer (rebuttal to n3187)
  2024-08-14 15:44                         ` Jens Gustedt
@ 2024-09-01  9:10                           ` Alejandro Colomar
  2024-09-01  9:51                             ` Martin Uecker
  0 siblings, 1 reply; 318+ messages in thread
From: Alejandro Colomar @ 2024-09-01  9:10 UTC (permalink / raw)
  To: Jens Gustedt, Martin Uecker
  Cc: Ballman, Aaron, Xavier Del Campo Romero, Gcc Patches,
	Daniel Plakosh, Joseph Myers, Gabriel Ravier, Jakub Jelinek,
	Kees Cook, Qing Zhao, David Brown, Florian Weimer,
	Andreas Schwab, Timm Baeder, A. Jiang, Eugene Zelenko

[-- Attachment #1: Type: text/plain, Size: 4417 bytes --]

Hi Jens, Martin,

On Wed, Aug 14, 2024 at 05:44:57PM GMT, Jens Gustedt wrote:
> Am 14. August 2024 16:47:32 MESZ schrieb Alejandro Colomar <alx@kernel.org>:
> > > > I was thinking of renaming the proposal to elementsof(), to avoid
> > > > confusion between length of an array and length of a string.  Would you
> > > > mind checking if elementsof() is ok?
> > > 
> > > No, not for me. I really want as to go consistently to talk about
> > > array length for this. Consistent terminology is important.
> > 
> > I understand your desire for consistency.  I think your paper is a net
> > improvement over the status quo (which is a mix of length, size, and
> > number of elements).  After your proposal, there will be only length and
> > number of elements.  That's great.
> > 
> > However, strlen(3) came first, and we must respect it.
> 
> Sure,  string length, a dynamic feature, and array length are two features.
> 
> But we also have VLA and not VNEA in the standard, So we should respect this ;-)

I hadn't thought about it until yesterday after Martin insisted in
preferring lengthof over nelementsof or a contraction of it, and worried
about nelementsof possibly causing ambiguity with multi-dimensional
arrays.  But:

VLA is a misnomer.
~~~~~~~~~~~~~~~~~~

First, let's assume length refers to the number of elements, as we all
agree that length should not refer to the size in bytes of an array,
since we already have the term "size" for it, which is consistent with
sizeof.

	int vla[3][n];

The array from above is a so-called variable length array, according to
the standard.  But it does not have a variable length, according to the
presumed meaning of length.  It does indeed have a variable size.  The
element of vla is itself an array, which is the one that really has a
variable length (or number of elements, as is the more technical term).

So, if n3187 develops, and really pretends to uniquely and unambiguously
use a term for the number of elements and another one for the size of an
array, it should also rename "variable length array" into "variable size
array".

It is indeed due to this problematic misuse of the colloquial term
length that "lenght" and not "number of elements" is misleading in
multi-dimensional arrays.  The standard is very strict in using NoE for
the first dimension of an array (so its true dimension), and not for
the dimensions of arrays that are elements of it.

And now you could say that this is only a problem of multi-dimensional
arrays.  It's not.  They're just the composition of arrays with elements
of type array.  The same problem arises with single dimensional arrays
in complex situations (although, admittedly, this is non-standard):

	$ cat vla.c 
	int
	main(void)
	{
		int n = 5;

		struct s {
			int  v[n];
		};

		struct s  a[3];

		return sizeof(a);
	}
	$ gcc -Wall -Wextra -Wpedantic vla.c 
	vla.c: In function ‘main’:
	vla.c:7:22: warning: a member of a structure or union cannot have a variably modified type [-Wpedantic]
	    7 |                 int  v[n];
	      |                      ^
	$ ./a.out; echo $?
	60

a is a VLA even if it is a single-dimension array of known constant
number of elements.  Huh?  :)

Terminology
~~~~~~~~~~~

Once we've determined that "length" in VLA does refer to the size and
not the number of elements, it's hard to justify a reformation of
terminology that would base on length meaning number of elements.

Indeed, either basing justifications of the origins of length on
strlen(3) or on VLA, we must conclude that "variable length array" must
be renamed to "variable size array".  I'm preparing a paper for that.

If eventually that paper would be accepted, I'd prepare a second paper
that would reform every use of size and length with arrays so that size
always refers to the size in bytes, length is completely removed, and
number of elements stands as the only term to refer to the number of
elements.


Have a lovely day!
Alex

> > Since you haven't proposed eliminating "number of elements" from the
> > standard, and it would still be used alongside length, I think
> > elementsof() would be consistent with your view (consistent with "number
> > of elements").
> 
> didn't we ? Then this is actually a good idea to do so, thanks for the idea !

-- 
<https://www.alejandro-colomar.es/>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 318+ messages in thread

* Re: VLA is a misnomer (rebuttal to n3187)
  2024-09-01  9:10                           ` VLA is a misnomer (rebuttal to n3187) Alejandro Colomar
@ 2024-09-01  9:51                             ` Martin Uecker
  0 siblings, 0 replies; 318+ messages in thread
From: Martin Uecker @ 2024-09-01  9:51 UTC (permalink / raw)
  To: Alejandro Colomar, Jens Gustedt
  Cc: Ballman, Aaron, Xavier Del Campo Romero, Gcc Patches,
	Daniel Plakosh, Joseph Myers, Gabriel Ravier, Jakub Jelinek,
	Kees Cook, Qing Zhao, David Brown, Florian Weimer,
	Andreas Schwab, Timm Baeder, A. Jiang, Eugene Zelenko


Alex,

I am all for making things more consistent, but there is also a cost
to changing stuff too much.   length is the established 
term in most programming languages and I would recommend to stick
to it.

Note that it is not true that the standard consistently refers to 

char a[3][n]

as a VLA. It does so in the description in sizeof but not in the
type compatibility rules, at least as understood by most compilers. 
This is an inconsistency we *should* fix, but I do not think that
changing away from "length" is a good ida.

Note that "number of elements" is inherently an ambiguous term for
multi-dimensional arrays, and I am not sure how you want to avoid
this without making the wording more complex (e.g. "number of elements
of the outermost array).

So I would recommend not to go this way. You would need a really
good argument to convince me to vote for this, and I haven't seen
any such argument.

Martin



Am Sonntag, dem 01.09.2024 um 11:10 +0200 schrieb Alejandro Colomar:
> Hi Jens, Martin,
> 
> On Wed, Aug 14, 2024 at 05:44:57PM GMT, Jens Gustedt wrote:
> > Am 14. August 2024 16:47:32 MESZ schrieb Alejandro Colomar <alx@kernel.org>:
> > > > > I was thinking of renaming the proposal to elementsof(), to avoid
> > > > > confusion between length of an array and length of a string.  Would you
> > > > > mind checking if elementsof() is ok?
> > > > 
> > > > No, not for me. I really want as to go consistently to talk about
> > > > array length for this. Consistent terminology is important.
> > > 
> > > I understand your desire for consistency.  I think your paper is a net
> > > improvement over the status quo (which is a mix of length, size, and
> > > number of elements).  After your proposal, there will be only length and
> > > number of elements.  That's great.
> > > 
> > > However, strlen(3) came first, and we must respect it.
> > 
> > Sure,  string length, a dynamic feature, and array length are two features.
> > 
> > But we also have VLA and not VNEA in the standard, So we should respect this ;-)
> 
> I hadn't thought about it until yesterday after Martin insisted in
> preferring lengthof over nelementsof or a contraction of it, and worried
> about nelementsof possibly causing ambiguity with multi-dimensional
> arrays.  But:
> 
> VLA is a misnomer.
> ~~~~~~~~~~~~~~~~~~
> 
> First, let's assume length refers to the number of elements, as we all
> agree that length should not refer to the size in bytes of an array,
> since we already have the term "size" for it, which is consistent with
> sizeof.
> 
> 	int vla[3][n];
> 
> The array from above is a so-called variable length array, according to
> the standard.  But it does not have a variable length, according to the
> presumed meaning of length.  It does indeed have a variable size.  The
> element of vla is itself an array, which is the one that really has a
> variable length (or number of elements, as is the more technical term).
> 
> So, if n3187 develops, and really pretends to uniquely and unambiguously
> use a term for the number of elements and another one for the size of an
> array, it should also rename "variable length array" into "variable size
> array".
> 
> It is indeed due to this problematic misuse of the colloquial term
> length that "lenght" and not "number of elements" is misleading in
> multi-dimensional arrays.  The standard is very strict in using NoE for
> the first dimension of an array (so its true dimension), and not for
> the dimensions of arrays that are elements of it.
> 
> And now you could say that this is only a problem of multi-dimensional
> arrays.  It's not.  They're just the composition of arrays with elements
> of type array.  The same problem arises with single dimensional arrays
> in complex situations (although, admittedly, this is non-standard):
> 
> 	$ cat vla.c 
> 	int
> 	main(void)
> 	{
> 		int n = 5;
> 
> 		struct s {
> 			int  v[n];
> 		};
> 
> 		struct s  a[3];
> 
> 		return sizeof(a);
> 	}
> 	$ gcc -Wall -Wextra -Wpedantic vla.c 
> 	vla.c: In function ‘main’:
> 	vla.c:7:22: warning: a member of a structure or union cannot have a variably modified type [-Wpedantic]
> 	    7 |                 int  v[n];
> 	      |                      ^
> 	$ ./a.out; echo $?
> 	60
> 
> a is a VLA even if it is a single-dimension array of known constant
> number of elements.  Huh?  :)
> 
> Terminology
> ~~~~~~~~~~~
> 
> Once we've determined that "length" in VLA does refer to the size and
> not the number of elements, it's hard to justify a reformation of
> terminology that would base on length meaning number of elements.
> 
> Indeed, either basing justifications of the origins of length on
> strlen(3) or on VLA, we must conclude that "variable length array" must
> be renamed to "variable size array".  I'm preparing a paper for that.
> 
> If eventually that paper would be accepted, I'd prepare a second paper
> that would reform every use of size and length with arrays so that size
> always refers to the size in bytes, length is completely removed, and
> number of elements stands as the only term to refer to the number of
> elements.
> 
> 
> Have a lovely day!
> Alex
> 
> > > Since you haven't proposed eliminating "number of elements" from the
> > > standard, and it would still be used alongside length, I think
> > > elementsof() would be consistent with your view (consistent with "number
> > > of elements").
> > 
> > didn't we ? Then this is actually a good idea to do so, thanks for the idea !
> 


^ permalink raw reply	[flat|nested] 318+ messages in thread

* Re: [PATCH v12 0/4] c: Add __nelementsof__ operator
  2024-08-31 14:56   ` [PATCH v12 0/4] " Alejandro Colomar
                       ` (3 preceding siblings ...)
  2024-08-31 14:56     ` [PATCH v12 4/4] c: Add __nelementsof__ operator Alejandro Colomar
@ 2024-10-02  8:34     ` Alejandro Colomar
  4 siblings, 0 replies; 318+ messages in thread
From: Alejandro Colomar @ 2024-10-02  8:34 UTC (permalink / raw)
  To: gcc-patches, Martin Uecker, Joseph Myers
  Cc: Gabriel Ravier, Jakub Jelinek, Kees Cook, Qing Zhao,
	Jens Gustedt, David Brown, Florian Weimer, Andreas Schwab,
	Timm Baeder, Daniel Plakosh, A. Jiang, Eugene Zelenko,
	Aaron Ballman, Paul Koning, Daniel Lundin, Nikolaos Strimpas,
	JeanHeyd Meneide, Fernando Borretti, Jonathan Protzenko,
	Chris Bazley, Ville Voutilainen, Alex Celeste,
	Jakub Łukasiewicz, Douglas McIlroy, Jason Merrill,
	Xavier Del Campo Romero, Siddhesh Poyarekar, DJ Delorie,
	Carlos O'Donell, Stephen Coady, ganandan, mnewsome

[-- Attachment #1: Type: text/plain, Size: 25663 bytes --]

Hi!

On Sat, Aug 31, 2024 at 04:56:28PM GMT, Alejandro Colomar wrote:
> Hi!
> 
> v12 changes:
> 
> -  Fix typo in changelog entry.
> 
> For ISO C2y, I'm proposing either nelementsof() or a contracted version
> of that name.  However, since in GCC we want an uglified name that
> already takes four characters for the __*__, I think this long name
> makes sense.  See also:
> <https://inbox.sourceware.org/gcc/ewksn7n5blrzhvy565ztxnt2pagxy4rdhuq2i4k6beqsimoqgw@74wy7erikpwt/1.2-elementsof.pdf>
> 
> The WG14 discussion seems to have settled, and while the exact name
> isn't yet clear, there seems to be rough consensus on something derived
> from "number of elements of" (with some votes for "lenght", but not so
> many), and the rest of the properties of the operator don't seem to be
> questioned.
> 
> Martin, Joseph, can you please review and merge?  Thanks!

WG14 (the C standard committee) has voted this feature yesterday.  A few
things to note:

-  The semantics are accepted exactly as implemented here.

-  There was divided consensus on the question "Should the name derive
   from 'number of elements' or 'count' (5 votes) or from something else
   including mainly length (8 votes) with some abstentions.

   After that poll, there was another to choose between 'length' or
   something else, and there was an overwhelming majority to prefer
   'length' over anything else.  However, that still leaves 'length' vs
   'number of elements'/'count' with only a small difference in votes,
   which I'm not entirely happy with.

I will resend this patch with only renaming the operator to lengthof.

Have a lovely day!
Alex

> 
> Have a lovely day!
> Alex
> 
> Alejandro Colomar (4):
>   contrib/: Add support for Cc: and Link: tags
>   gcc/: Rename array_type_nelts() => array_type_nelts_minus_one()
>   Merge definitions of array_type_nelts_top()
>   c: Add __nelementsof__ operator
> 
>  contrib/gcc-changelog/git_commit.py        |   5 +-
>  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                            |  32 +++--
>  gcc/c/c-fold.cc                            |   7 +-
>  gcc/c/c-parser.cc                          |  62 +++++++--
>  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                        |  30 +++++
>  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/nelementsof-compile.c | 115 ++++++++++++++++
>  gcc/testsuite/gcc.dg/nelementsof-vla.c     |  46 +++++++
>  gcc/testsuite/gcc.dg/nelementsof.c         | 150 +++++++++++++++++++++
>  gcc/tree.cc                                |  17 ++-
>  gcc/tree.h                                 |   3 +-
>  29 files changed, 604 insertions(+), 80 deletions(-)
>  create mode 100644 gcc/testsuite/gcc.dg/nelementsof-compile.c
>  create mode 100644 gcc/testsuite/gcc.dg/nelementsof-vla.c
>  create mode 100644 gcc/testsuite/gcc.dg/nelementsof.c
> 
> Range-diff against v11:
> 1:  2e851b8f8d2 ! 1:  d7fca49888a contrib/: Add support for Cc: and Link: tags
>     @@ Commit message
>      
>          contrib/ChangeLog:
>      
>     -            * gcc-changelog/git_commit.py: (GitCommit):
>     +            * gcc-changelog/git_commit.py (GitCommit):
>                  Add support for 'Cc: ' and 'Link: ' tags.
>      
>          Cc: Jason Merrill <jason@redhat.com>
> 2:  d582d12adb8 = 2:  e65245ac294 gcc/: Rename array_type_nelts() => array_type_nelts_minus_one()
> 3:  34d14beb7da = 3:  03de2d67bb1 Merge definitions of array_type_nelts_top()
> 4:  49b8d51db4a = 4:  4373c48205d c: Add __nelementsof__ operator
> 
> base-commit: 9cbcf8d1de159e6113fafb5dc2feb4a7e467a302
> prerequisite-patch-id: 3bb58e302e54b35e987452de2e3cb6da7f6917ce
> prerequisite-patch-id: 090612df745c5ed878a75175606ce1deabf61cb0
> prerequisite-patch-id: c3a80d94c326f7402bdf46049c434e809a9f376e
> prerequisite-patch-id: 883007acf6a47f51128798dc952895854b40e1ff
> prerequisite-patch-id: 93e211483ce2b939ce5e549de78e9ac4606bb114
> prerequisite-patch-id: 008f55a1dc4b0a2551e4682b3319a3b0df86c72e
> prerequisite-patch-id: be6ecc95f5fcf2fe9ac44263e6eae8a69068ee53
> prerequisite-patch-id: e64a9e239738ff1af9753893372bb0fff907d8e6
> prerequisite-patch-id: 22cc97d05ab08735db2341f5062c737f9cff9209
> prerequisite-patch-id: 9e9756ca0458d4f6f162229e5ffe5923ffceb9d7
> prerequisite-patch-id: 9d64d075010c059eaceb2fb2326d48f6a8798950
> prerequisite-patch-id: be2e5a5deb6836b4715e4715cddd03018d2f3346
> prerequisite-patch-id: a627d18e62fc98b7ccf11b31b0dc885a52994795
> prerequisite-patch-id: 39aea8b15f043ab5e2804a6e127d2fe5108d814b
> prerequisite-patch-id: 8cb26809cc4de24fe408e71a468fbc278241faab
> prerequisite-patch-id: 1b0dd932c7637d953a7b7086aa5625287df6c79a
> prerequisite-patch-id: 0bb1888a37e3537ba48e69ac378b7b3e41453949
> prerequisite-patch-id: 79657c31c616c9bf477ec015a4ccb94f298193c0
> prerequisite-patch-id: 2506a44e9d695cffa4c710176092c30392037103
> prerequisite-patch-id: da4a114bc9bef4aafb816328f1674b5f85818753
> prerequisite-patch-id: f4a32714d46e022356759a3fb305a8827ef565e9
> prerequisite-patch-id: 08a6388b590804ab3f8da8c03d953e88428228e9
> prerequisite-patch-id: 37fb8203174274fa9e3054ba0d83ff41dd9ba206
> prerequisite-patch-id: 5a6559b661dd999abf5d5b0a40309636faa3504e
> prerequisite-patch-id: a66c0ace262f24e19546e0669fecd0bbb6c4b4bf
> prerequisite-patch-id: de6b8f05d41b61f29fc517883fafdf89aada7de9
> prerequisite-patch-id: 4412c0ef6909608fc761b86cfb22722d862d61d0
> prerequisite-patch-id: ad452759de17adaaf82c9f30e556fb477e3b1941
> prerequisite-patch-id: 7b8615c4ad8e6c825ee192c8225e7b8f673aaeb4
> prerequisite-patch-id: 7f806ab2c8bac5b2a79fad8eef55c4190ec33d44
> prerequisite-patch-id: 84d3e86a4b573228dab7d37c3d89845ec1989723
> prerequisite-patch-id: 293a69cf606ea42badcc678f43b53f2e47aded19
> prerequisite-patch-id: 1a871a86b6c1b147ed731970f999b5d102444d1d
> prerequisite-patch-id: 7798a8ca79c1f13268e3762d47861ff94d8eba02
> prerequisite-patch-id: ea12050f12ad6e1278b695f5fe345ca9bc842b1f
> prerequisite-patch-id: 775ec83e6019784675e3412125ae6215b4bf045d
> prerequisite-patch-id: 8cc5a6f94523c8120086dcb2217ba8168b045a3e
> prerequisite-patch-id: ee9fa7eb9352555ff989551e0af040359671f3d7
> prerequisite-patch-id: 02737f65218d4b0c2766cfcf8c0fcde24ca93ac2
> prerequisite-patch-id: 4649eac88f8eb70f79e7777b7cebff4460d8cfc7
> prerequisite-patch-id: 6cba96eb4bee2e8b3b47e0bf6b21ec9fa8639480
> prerequisite-patch-id: 67691213e43b5776c999e8c0927df69be8689e14
> prerequisite-patch-id: c92d8f4dab324c8f42605d626035999cd990a18e
> prerequisite-patch-id: f0a10e37287f97e915eb245d6394ad8e1115905a
> prerequisite-patch-id: f67343a2b854a5f51d75200d56715b2cd10ddc9c
> prerequisite-patch-id: 0d42c83260a2a02de43ad5066f76b4483703f155
> prerequisite-patch-id: 71fc9c326b88271512ee65320dcb3b3454326472
> prerequisite-patch-id: 5770267c01d4e5b5d0187445d31ee87b662fa61d
> prerequisite-patch-id: 999d706f78ac4f85adbfad63adc3df03615ce716
> prerequisite-patch-id: a3a7f88920dcaec397cdce89680dd341da6b7d50
> prerequisite-patch-id: 74495be2707634e339b90ed5ad3a4c375f6b9ec2
> prerequisite-patch-id: 7be19bb7867585445b6119f6357b69f5f8baa5b8
> prerequisite-patch-id: 03efabd23ba77ba8141aa0a8f19b04f0fa6c97f1
> prerequisite-patch-id: 04a4ddcad10e249f4e8cd96ade03c16997e8f83f
> prerequisite-patch-id: b0b8243418ae865a61a5f92d1da80fdbed6d23d4
> prerequisite-patch-id: 349842ef44ddca54066bdbb26d634ac24e076710
> prerequisite-patch-id: d15d4d8c4c0b6843118774fee0c8231e948779cf
> prerequisite-patch-id: eff8d7df797afdd2ba6b14c1d8ec9dbdc58b5c3d
> prerequisite-patch-id: 18ae20d67e1f01478d4b01981488e0a3d6864ad2
> prerequisite-patch-id: b6c162640de66eeaf8f2b470801dc3cec9d1141e
> prerequisite-patch-id: fccd6815aa703114b7ea3e61b3971621316a8706
> prerequisite-patch-id: ec894a0480c8c523b9f895eea7b809b68998bbfe
> prerequisite-patch-id: a408ede8ac2c69f821dd06cdad368652784e975f
> prerequisite-patch-id: 31f81b5fce5e577e66c09784d24727fadce0b71b
> prerequisite-patch-id: 0fa06efe4a2349a00a6e1d7ed3fcb7ededef127e
> prerequisite-patch-id: e7dba9a68bc0d4481b2cebf029595bdb9f47271f
> prerequisite-patch-id: 4ac7ef554fdd4c2fcceb9f5bd83e9203adaddaf3
> prerequisite-patch-id: ec0a3bc81af005d80235b38f44c227b0a1c248d2
> prerequisite-patch-id: 7083aa4a6a21ae34a8d6457791068ba419c1187d
> prerequisite-patch-id: 7b3ceb60e52271be1655ab07595e1000d8734ae8
> prerequisite-patch-id: 069dd47701f5607db952e7410b66bfc4a77b907c
> prerequisite-patch-id: 6de803a1b4d8dba8b403205327bff91f239a39a8
> prerequisite-patch-id: 8dfcdb9d5cdf69c54766a59a8f194af09c0840b8
> prerequisite-patch-id: f7834a2848f562a130f3d6f28a6b849723dbe18f
> prerequisite-patch-id: 2f283e2b6ff758a2b1f0f4f491c962499be68f91
> prerequisite-patch-id: 7ca906fcc364ab07d6ab9b48fe8162e8006499b9
> prerequisite-patch-id: 0ef05db7ab79653ae096f50497946214bc5084b9
> prerequisite-patch-id: 1d60704d316f4b0f66d5c7e4bf17b025cf99c617
> prerequisite-patch-id: ed3314a4690d9c15bbcfee441599a58e37215877
> prerequisite-patch-id: 34ec93f88bed41db1608e214800f87fdc5a7f9f9
> prerequisite-patch-id: aca1f8cc97d88784936517c7e8050c457c77c9af
> prerequisite-patch-id: b499a1bfa95368ee03daa8c7d45b3ae9c1206871
> prerequisite-patch-id: 5f1cb1245044b3ad4169500916c8b9459711416e
> prerequisite-patch-id: 88e3e2e5947fbfa907213daa9ceef1651976d72f
> prerequisite-patch-id: b4d4f67cd84b9ccb4c4eb48d8e7e20fc70b702ec
> prerequisite-patch-id: b807936c32d4a4539a29ba56b637a3f4733713e3
> prerequisite-patch-id: 72b95ab107eb6ae60f6517410ecce24a3308fa6e
> prerequisite-patch-id: 007b9853bbb41eb2d2b85fd67c1b39d58c2dcc4d
> prerequisite-patch-id: e6e05315ec9827b069836b4f394099272c4b3998
> prerequisite-patch-id: cd63bd21f25dfb458c751306f1ba8fba6db43a35
> prerequisite-patch-id: 790fe51546bed957d4094668086a87009ea6bc3e
> prerequisite-patch-id: c55ca764e1bde1857cab3d1c7a569172e3a60dd0
> prerequisite-patch-id: 4574efb15f6e60ba84b21718381c19faa2d06e6a
> prerequisite-patch-id: 4026283a30594ccf4c5c297a45b817d7c95dcc81
> prerequisite-patch-id: 2f6425ce98f57c1833fcfc1cb963a4b00550daaa
> prerequisite-patch-id: 671d4f6b289715eecf11df3b8e94e566b4e3f358
> prerequisite-patch-id: 59d20ef094471e06900a58216a35fb466e6350a6
> prerequisite-patch-id: 8f6ac7d59fcdd44f015dce5b41ca7e20ed551b17
> prerequisite-patch-id: b3f0435a6a54a62ae2b895ede265f657b2826929
> prerequisite-patch-id: 06784b4d67904e2a8eab05f652d985750aeae26a
> prerequisite-patch-id: 48e9916f08c8502323eadf9595d11a3ad7cf1b0c
> prerequisite-patch-id: 9c5b9353f575b545d6ba706aa33a4200dc163e1e
> prerequisite-patch-id: efadc065d2991129a9fa4380ed782b9dfac9807f
> prerequisite-patch-id: 5a3e46fd6d5f1324a307bd01656993131644e59d
> prerequisite-patch-id: 40be26b80ff47971946da8ccca6574333b4ac511
> prerequisite-patch-id: 249d8bc2c8226ea94c27e2d2db8dfda056b8221d
> prerequisite-patch-id: 64c7dc66a01b47fdc1d178e4264dbfb17f65cb48
> prerequisite-patch-id: 7651dda34bd7be0a7c0c58b813abbfe4e75057a5
> prerequisite-patch-id: 5b677afd301ba2d8385e73d6f55ef259e69cdd06
> prerequisite-patch-id: f41124cb1f7db66cf578ee87b768438dcf66227d
> prerequisite-patch-id: 6a173ab5f27750a6f4a2f8adebff537f95225d38
> prerequisite-patch-id: c42d87f4f18b34c20121d7a7ee22564b8f2a9c3b
> prerequisite-patch-id: e4c4b6c5c635e67f641c1bb4902bb5ec1a0eb1be
> prerequisite-patch-id: 197202a25498a915f35f4417efb38e8844cac309
> prerequisite-patch-id: 1e23186a890510f123ecd202f8a50d2094201277
> prerequisite-patch-id: ba3e7e54dfbd8370ff50d1a5e85ac06d803fe68d
> prerequisite-patch-id: edcca1af6061de5006b58ff7cd52a039aec88192
> prerequisite-patch-id: 50ee0f2c714091aeab155cd40a94214fd1844463
> prerequisite-patch-id: 31adcc5191ebc8b2ea26ee1e4b7de78a3d8e0f48
> prerequisite-patch-id: dafdb698d23a185ee4adfbf9cbaf43ea31661bc1
> prerequisite-patch-id: 683d340258d86d0774c772cc5d4bc4dfc6c214ac
> prerequisite-patch-id: 0052a313ada5ebbd0e24905f2b75974736dae59e
> prerequisite-patch-id: 1cbdbf0cf8727d07cfb7251551bbb8f47ca4f9d8
> prerequisite-patch-id: c059fdfb33923cc5d728f53136021e01cab5f316
> prerequisite-patch-id: d8cd3ac99c209600a4686d85627fae2956864272
> prerequisite-patch-id: 7bfa53abc0cd50a22a81782353e30f0503bf87b3
> prerequisite-patch-id: a2837d8005f85e1764d2baf4c5269ac4c26d0e03
> prerequisite-patch-id: c7c2ba071a328f24d36a7bc73d096f701ff049c4
> prerequisite-patch-id: 49edd721efd5860bce7a6da39a3983c1729dfb09
> prerequisite-patch-id: b41ba2264cf8d51fad69c0d60b23282fdcaa02ed
> prerequisite-patch-id: ce1094369b939e5df1c9ff586ba6e77eadd6755b
> prerequisite-patch-id: cc76aa21e68006e190b6c095a7eab1f71a350035
> prerequisite-patch-id: 016dbed32a9d26e0daa7fe068846dc5bf0bab4b2
> prerequisite-patch-id: ea3270295ff22f15ae5a5213ae7ef0fb24f3d90e
> prerequisite-patch-id: 0d7ec035c0ac8ea612791940c47c720fd0fc0983
> prerequisite-patch-id: 073689ebff4dc3ed400b7a6a09b2aa3222eb5eaf
> prerequisite-patch-id: 3de9c5dcd90a94356e41cd6c3a6b3a3ebd6da40f
> prerequisite-patch-id: 02173a8508f62560dfc0c873ed4f8ffd3b2da127
> prerequisite-patch-id: 325c71a3064a69ed233417bb0dd06ac5afe22ecd
> prerequisite-patch-id: fb5f0634575b9cd445be39af1b442f641f33669e
> prerequisite-patch-id: 375ec357c82582464519ccd102ba9c9969b27ccd
> prerequisite-patch-id: 96724bd515fee1e70896e427ca5443cf6c3bd1c6
> prerequisite-patch-id: d11653d1691c233ceac344313e1facf239c075e6
> prerequisite-patch-id: a0c4b6d4fa27a1f1738ccd7d2c1c5203f4acc10c
> prerequisite-patch-id: bcf62e2802a1d35bbeb601750792f3043e18e02e
> prerequisite-patch-id: b6027c3dd6b0d7a576397c3f7cead1cb2e32ab3d
> prerequisite-patch-id: 2993826cfc8ecb4743d1104ce9062ce064dee436
> prerequisite-patch-id: 2de773c80c1d53b349768f3a9c1dedd9473141e2
> prerequisite-patch-id: dcd065f3bede4933cf1071ca0ff8f631af30537e
> prerequisite-patch-id: e8f9cef7f9a80d21786bdbc63de84dad5bb0f11b
> prerequisite-patch-id: adefc62a9de4bcbb15ddba73edcdb96740b8527f
> prerequisite-patch-id: b8028f15bc6bcfc0053852516acd70129434ef64
> prerequisite-patch-id: a9378612984ceace5d8fc99c192de3d07fad4b4c
> prerequisite-patch-id: 3e64fd39d97c528b5901f648d7ab92c9b3dfebd1
> prerequisite-patch-id: 6900b6fcf58f765fa3266432dc9e2eebcacfbb4f
> prerequisite-patch-id: 0d796b1a9c84ad77fecacee5450ae4fe067e7748
> prerequisite-patch-id: c8cd1e1f3efda1056dd2f393a43b97a675f8fc00
> prerequisite-patch-id: a1e5e6ee3a85aa293485f42163c5e6fb8ed7ac6c
> prerequisite-patch-id: 29865d865b97531dd5be3019e22adb1066bcd0a3
> prerequisite-patch-id: f5e05f1932b2fd24d00c3a7e64a2589f9c62a4e7
> prerequisite-patch-id: 9f875036c21954004d3533697f89c7b8f3f35673
> prerequisite-patch-id: f0f917f79ebed24ee4cd3427393d6cc24b9f2617
> prerequisite-patch-id: 949be1cb8e66006949d4654aa60cf11b990bea13
> prerequisite-patch-id: a035355f8731aa2619cd876157cfd2a9321c4814
> prerequisite-patch-id: d23b3af12de5f250b5aded06076390d855065d34
> prerequisite-patch-id: b649f233ca196c43de136937fbcaf0a5b792a7c7
> prerequisite-patch-id: 0b474fc99e8b05aee2f470e8166d715261b9eb11
> prerequisite-patch-id: a8f595e6c8b9714bfc4d89a7e39d5be3a9665d87
> prerequisite-patch-id: 362ec11aff3d8ddc90f8b1aeb31d0fde8785384b
> prerequisite-patch-id: 3695552670237d21bbd21fef03105083754ed6d1
> prerequisite-patch-id: 89f2689e530147ac5530197ff972bc44135a1fe5
> prerequisite-patch-id: e4a07cbaee52cbe451bfb9938b6b2a8636cac2f0
> prerequisite-patch-id: f8f8edb0e66d2612359021654361be7fd0a55b70
> prerequisite-patch-id: 743f4e4444f9cac24e67abce2bda52d6a421d870
> prerequisite-patch-id: 8f0d19793716d0c18759e4261ef18c6db21c7f66
> prerequisite-patch-id: 016a97f4bb36008d268ed1142d4fe67263d18c5f
> prerequisite-patch-id: c9b1ea941f12ec7c34d17a7a81b999cdc90a46bb
> prerequisite-patch-id: 2e4f5844a1680c659f4fe9af3723f8c9e6171c98
> prerequisite-patch-id: 9b218d7632794493bcc98298de79e9d881bc4de2
> prerequisite-patch-id: bd18dcb6c060ae56cadb55ad248138918b4542fa
> prerequisite-patch-id: 5f4f31b906f1a415721c42bb4f06e9a97e6d9826
> prerequisite-patch-id: fd625a00389f10724c4df0c309f46588ff4db63e
> prerequisite-patch-id: 6aa7f6e164a2fc200361fd96399ad1c10f0825e2
> prerequisite-patch-id: de267e462ebf8b5fda3d3df92d84914f3d49b093
> prerequisite-patch-id: 10e0c0ed7bb11a5e9d50b4210a67d56d0baa7ae7
> prerequisite-patch-id: 881a354db3dcf42e71ff51e86a712fe24a82378f
> prerequisite-patch-id: 471c157425528ec5fa2fe0371dfc9babeff74c57
> prerequisite-patch-id: a7d752c724506c047c0c69fb568f9e3e421773b5
> prerequisite-patch-id: e207260eff0bee9b47719902663721ac36371856
> prerequisite-patch-id: c978ecf00ccf17014919ba6d22a634f1fa5378b8
> prerequisite-patch-id: c30ea3d0e9179a8f91523e4775aa1d7697777031
> prerequisite-patch-id: 9caf8f6dc88c899b90242124e9efccecf61e6580
> prerequisite-patch-id: 8104c6e0f28b79353bb1fe3d6d5bd49b8a1d4656
> prerequisite-patch-id: ad97388f77ab9d4cc88a369418deec6f796d9ac3
> prerequisite-patch-id: 1f6acfacff835f1d7f922614262505c4acbcb067
> prerequisite-patch-id: 95d5625e0f04636a4c3ec335c77f34a5fecaa952
> prerequisite-patch-id: 82e613feb908a11046bdafc6e874bcd8c4f52200
> prerequisite-patch-id: 5f7a850dcf2102e4ac82791ba95ed0c0bc695613
> prerequisite-patch-id: 50d03e282b31737919a2b979d59c5c4c17107627
> prerequisite-patch-id: 8b51bae8e714a0e5277f67ff9d1455fd2f4e36b7
> prerequisite-patch-id: eee196eb6f44f53040e52305d9c48909eb3bf2c5
> prerequisite-patch-id: 35494985bedf6015cb3a8c2c70f58099e9c44316
> prerequisite-patch-id: c3c5c822735b385dd0e55260f514623bf3f9ff1a
> prerequisite-patch-id: b21222f6f96276b46ff605bdd1d2a75c9af839ca
> prerequisite-patch-id: b63e092548d498d642b6363eae9c98247f5300f9
> prerequisite-patch-id: 99cf93d15a50ad94c049c736b375bbdb77cf0ef6
> prerequisite-patch-id: e2d86b651e3ff2f70848f827b29cc804cead48b2
> prerequisite-patch-id: 1ec76b0303530aaa120186fb249252cd3a1bd7ec
> prerequisite-patch-id: 9a35b1041fb252654255045df37478c8eb15a501
> prerequisite-patch-id: e7227e60ea90415b54c6fcd553ddece24dd402fc
> prerequisite-patch-id: 2f45861307fafa6a5696098406e164e166f4d207
> prerequisite-patch-id: ab037b78ccf8a9db312333f5e01e6fd2e54832ca
> prerequisite-patch-id: 9c886d5ccd279d6f283fcd60a794e66c94fe782d
> prerequisite-patch-id: fa5a4fc2f2d77e9ad000d7477f56b822efce457f
> prerequisite-patch-id: a0699fc9eb0ee36f53bc937770887d6086d2a7b8
> prerequisite-patch-id: b383634edd50afef4180be293861d1014491d86d
> prerequisite-patch-id: 2f404a754f2e1048165df254e963e26f6789de7f
> prerequisite-patch-id: 07d59a1d0796816d8421b5a236175b1568d1f63f
> prerequisite-patch-id: 9f904d43a86cb4e55a2a00440dd042ec717c8eb8
> prerequisite-patch-id: b30b252bdf0646403dbd132c7dc629188e4f6a4b
> prerequisite-patch-id: 73e2691afad05a42cb6cb5a28894eb958516f39c
> prerequisite-patch-id: ef0f8b6061c55ada19107f026164c8598ebc66bd
> prerequisite-patch-id: da21009a2dbc3384309cfdc4c49e10b86de6e747
> prerequisite-patch-id: 2ef5022df54288b85ef1c8fe4e7a02a03d4577ff
> prerequisite-patch-id: 5193b8507248975783d1eb6bc911265e6b55988e
> prerequisite-patch-id: 1aef895eb9c159d33d617d7b2475928f75a73303
> prerequisite-patch-id: bf87652bd502aeaf671da92e243553fb9a94f5d5
> prerequisite-patch-id: cf9856dfd70d154fab043ffd2ee89288d9d41827
> prerequisite-patch-id: f9daf7a441685aa6d25225b6616e51be5fcfe772
> prerequisite-patch-id: 0101aa9af501543384863fa8c090febd6939f80f
> prerequisite-patch-id: ccf1ac224734562e2f4207847b8128cd3c8b9d31
> prerequisite-patch-id: 589ae86ee30b01355ce220ab9fc89c5403d95076
> prerequisite-patch-id: 6e809a44a0ef69883eb812f8a4b57eb52ad32f41
> prerequisite-patch-id: 116d110f795045527d54f2897e1ac12bb2f59238
> prerequisite-patch-id: f4e0f48a8ce61bc6c229a18bf41f4b3cdec3a9d0
> prerequisite-patch-id: e78df0253e48cdf5f9e44c17a169fc9cccb82c7e
> prerequisite-patch-id: 1e6951da0eba531f4b445996167fea1e7320e3ae
> prerequisite-patch-id: b1903fb1a742dd33ebb635299c725e9fc2a4e9ae
> prerequisite-patch-id: eb07c15789948b34c0b219ff05f61c530882845d
> prerequisite-patch-id: 92c0ba647ef4b4b7e83297554f6fa7e31f3a8fb5
> prerequisite-patch-id: f968b1250e573119cb65aab0b98c225d8a7c4d8a
> prerequisite-patch-id: 5e6dee90fe5f7a891794b5ea6bed41b1157c2930
> prerequisite-patch-id: 3b10245cae08595a6bcbdc82ff836becaf6d04d2
> prerequisite-patch-id: d7f15f333560e8ccfe2ad073e99ca4ef502e15d1
> prerequisite-patch-id: 4c95c2badbd5911a7405a64e0d84e3091526444d
> prerequisite-patch-id: f839c9824865564c12cbb7064ff455f34dc039f7
> prerequisite-patch-id: 071e2570569f005c75ed7d8bf112db80cca310e5
> prerequisite-patch-id: 7ee42594ecf51591428ae7f13bfb8403affed8cb
> prerequisite-patch-id: 4b2105c900cf8ed047a9c0d1866fb2bdb4f9a59e
> prerequisite-patch-id: dd4697ba0013408e637223fadd027c9b34945060
> prerequisite-patch-id: e0881345b919ec25525c626303ba5d5e160f97f2
> prerequisite-patch-id: fc6865c7e1fb19530ac8e77090eaa0b179f70496
> prerequisite-patch-id: e3b8081ed28b7f0d370548044237287f52179967
> prerequisite-patch-id: b672da115531fc52a591c9e50ac4da9e8b09e144
> prerequisite-patch-id: f2764b91aa819feb1879d007993bda7aeb7f5df6
> prerequisite-patch-id: dfb13890022578746ce611a965c62c34905b1f18
> prerequisite-patch-id: bef3730ba816c84cb056d12e30b91a8c1f4b6aac
> prerequisite-patch-id: 265211a01667357c86ce905ee33e4adbb81887d9
> prerequisite-patch-id: c02d2492949e079494b9552c397e689774fad639
> prerequisite-patch-id: 0f4180d693806ae210396ec1512be8e1d45c9530
> prerequisite-patch-id: 22b486e7286a8b1a8ef90d3f1f4a4d48e43fb25c
> prerequisite-patch-id: 0020828bf1b65907c906fb9ebf24104a5e72c790
> prerequisite-patch-id: 4afad41c227028a4c6c35d1c43b0ee7883852a1e
> prerequisite-patch-id: 890e19d588eca2dacfb83475c19ac461c0d83058
> prerequisite-patch-id: f35d03d5ed63be69d2dfec77d07b28d21c40dc9a
> prerequisite-patch-id: 2bebc000037d37260152802423445d39bc463f8e
> prerequisite-patch-id: ccbec53de5ad88beb7657680ae6aa167f3505fd6
> prerequisite-patch-id: 3c588bad04050087679a1d4f5479efb0da2537bb
> prerequisite-patch-id: 87d915c6c5495d2accc7864dc592f2f651012fca
> prerequisite-patch-id: a327cf20636f57b5feb31928c49d6517f102a709
> prerequisite-patch-id: 8106cf8afd07cf37f3ecd63b831f1a22fa99998a
> prerequisite-patch-id: a4ff39b72413dc2d894d269629919ce5199eb0fd
> prerequisite-patch-id: c0db74dd58a097e7130420bd294b0f3d200730be
> prerequisite-patch-id: df5bd199584a63d1ca2af8ca5e9bc659baffb8ab
> prerequisite-patch-id: 9f8d32c0a8df05688a4e6779d45538056d891a72
> prerequisite-patch-id: 167566e1096e56d7189393aed3528b8047421a2b
> prerequisite-patch-id: 5ade75da262706c05c72bc2e1095cdc137334928
> prerequisite-patch-id: 725cd8d55b55117b8732240a36ef6dd57560b7aa
> prerequisite-patch-id: 2283e8ab28c671cd97fdba344bad9fad3b740955
> prerequisite-patch-id: d86fed5ed934d2622a0e640677483dbd5e493b50
> prerequisite-patch-id: 5a523603c0cc2344952de69d65a1dd6c9c28b1b0
> prerequisite-patch-id: 8276956515aab9f3e81a9b4d51f5d270fea82c8b
> prerequisite-patch-id: 1c0b8c20b01944262081a7fac4905a24a1f51afd
> prerequisite-patch-id: 90b6ed9e4633014209d3291157104fe2db6cc268
> prerequisite-patch-id: b78d480e28a5684e5a04f9e2d1dc6c8d6b6115d8
> prerequisite-patch-id: 85129a45f66a9afd1d6aeb78a266f2b33131effc
> prerequisite-patch-id: 46c2c0f251c385f740ec0f021ddf71b214dcf188
> prerequisite-patch-id: de94541c97cd5dfb8f02b4210557a29264c60f28
> prerequisite-patch-id: cb4a135f378247e43ecb9c5c1ca421e778356cd3
> prerequisite-patch-id: 6941030e002fe4dac24a7e431297837bcebd6637
> prerequisite-patch-id: 16ed31acf9114e5bcdeab9ac6f8b3c1d460d40ab
> prerequisite-patch-id: 5a24fb875f0c703d031c3dcfd40faf2072a691b1
> prerequisite-patch-id: 278384975e9224209b9df58781cb0d57d33cce91
> prerequisite-patch-id: 8b4be8616dd4f2e1b6189657017e81999e3379bf
> prerequisite-patch-id: 99853a3b8283b9aae581ec9c7a4b30dd27a9075f
> prerequisite-patch-id: a48c177e8a82248dfd6642c35da34019d765a4a8
> prerequisite-patch-id: 6b4419d64c7d1e887578e30a73fc476aad5408a6
> prerequisite-patch-id: 93b79b926b74052e9bbba631e0f30da89c1dd0ec
> prerequisite-patch-id: 9fe442b02446f58ea358d748da5f5f82805bc7ef
> prerequisite-patch-id: 26828312870404b6611ccd685b162aa082dfce57
> prerequisite-patch-id: 6ce31c6bb1a2b79ca465dca7a1157d1bb379d51b
> prerequisite-patch-id: e6b4e8bd8a45796125d4fdcc169f97f5a3fb8bf8
> prerequisite-patch-id: 94637d65272a73ec3e2b19dc3595d864fdea4836
> prerequisite-patch-id: dd5dfa3e4d58a7db1f158bcc0daec057c028ce00
> prerequisite-patch-id: 2295114d438c62a2128620775fc0300b0b418ff9
> prerequisite-patch-id: 080adcee4042fd9511680fb10beebcae24a4dc06
> prerequisite-patch-id: 022f540464bfd6c2202cdeb5530502903d207417
> prerequisite-patch-id: 5ffcb1ea5dafbfe47753ce4165afa1f99d46cc82
> prerequisite-patch-id: c4dcb2f3f063115727c204d3e0b0ef7c7a66cda9
> prerequisite-patch-id: 984a29d2480696456528847eb7365e5785613ab6
> prerequisite-patch-id: fa4b35b9b0874bdf8057f88303e204ff3b6e0538
> prerequisite-patch-id: 12dac397d93e001201a2b8fcbadbca24a91a1f5a
> prerequisite-patch-id: 51112edb6d85135a1930262e7a63f8f2fad3b22d
> -- 
> 2.45.2
> 



-- 
<https://www.alejandro-colomar.es/>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 318+ messages in thread

* [PATCH v13 0/4] c: Add __lengthof__ operator
  2024-07-28 14:15 ` [RFC v1 0/2] c: Add _Lengthof operator Alejandro Colomar
                     ` (17 preceding siblings ...)
  2024-08-31 14:56   ` [PATCH v12 0/4] " Alejandro Colomar
@ 2024-10-02  9:41   ` Alejandro Colomar
  2024-10-02  9:41     ` [PATCH v13 1/4] contrib/: Add support for Cc: and Link: tags Alejandro Colomar
                       ` (4 more replies)
  2024-10-08  9:11   ` [PATCH v14 0/4] c: Add __countof__ operator Alejandro Colomar
                     ` (9 subsequent siblings)
  28 siblings, 5 replies; 318+ messages in thread
From: Alejandro Colomar @ 2024-10-02  9:41 UTC (permalink / raw)
  To: gcc-patches
  Cc: Alejandro Colomar, Gabriel Ravier, Jakub Jelinek, Kees Cook,
	Qing Zhao, Jens Gustedt, David Brown, Florian Weimer,
	Andreas Schwab, Timm Baeder, Daniel Plakosh, A. Jiang,
	Eugene Zelenko, Aaron Ballman, Paul Koning, Daniel Lundin,
	Nikolaos Strimpas, JeanHeyd Meneide, Fernando Borretti,
	Jonathan Protzenko, Chris Bazley, Ville Voutilainen,
	Alex Celeste, Jakub Łukasiewicz, Douglas McIlroy,
	Jason Merrill, Xavier Del Campo Romero, Siddhesh Poyarekar,
	DJ Delorie, Carlos O'Donell, Stephen Coady, Robert Seacord

[-- Attachment #1: Type: text/plain, Size: 36282 bytes --]

Hi!

This operator is as voted in a WG14 meeting yesterday, with the only
difference that we name it __lengthof__ instead of _Lengthof, to be able
to add it without being bound by ISO bureaucracy.

No semantic changes since v12; only the rename, according to what WG14
preferred.  WG14 agreed on the semantic changes of the operator as I
implemented them in v12.

Changes since v12:

-  Rename s/__nelementsof__/__lengthof__/
-  Fix typo in documentation.

Below is a range diff against v12.

Have a lovely day!
Alex


Alejandro Colomar (4):
  contrib/: Add support for Cc: and Link: tags
  gcc/: Rename array_type_nelts() => array_type_nelts_minus_one()
  Merge definitions of array_type_nelts_top()
  c: Add __lengthof__ operator

 contrib/gcc-changelog/git_commit.py        |   5 +-
 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                            |  32 +++--
 gcc/c/c-fold.cc                            |   7 +-
 gcc/c/c-parser.cc                          |  62 +++++++--
 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                        |  30 +++++
 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/nelementsof-compile.c | 115 ++++++++++++++++
 gcc/testsuite/gcc.dg/nelementsof-vla.c     |  46 +++++++
 gcc/testsuite/gcc.dg/nelementsof.c         | 150 +++++++++++++++++++++
 gcc/tree.cc                                |  17 ++-
 gcc/tree.h                                 |   3 +-
 29 files changed, 604 insertions(+), 80 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/nelementsof-compile.c
 create mode 100644 gcc/testsuite/gcc.dg/nelementsof-vla.c
 create mode 100644 gcc/testsuite/gcc.dg/nelementsof.c

Range-diff against v12:
1:  d7fca49888a = 1:  d7fca49888a contrib/: Add support for Cc: and Link: tags
2:  e65245ac294 = 2:  e65245ac294 gcc/: Rename array_type_nelts() => array_type_nelts_minus_one()
3:  03de2d67bb1 = 3:  03de2d67bb1 Merge definitions of array_type_nelts_top()
4:  4373c48205d ! 4:  f635871da1f c: Add __nelementsof__ operator
    @@ Metadata
     Author: Alejandro Colomar <alx@kernel.org>
     
      ## Commit message ##
    -    c: Add __nelementsof__ operator
    +    c: Add __lengthof__ operator
     
         This operator is similar to sizeof but can only be applied to an array,
         and returns its number of elements.
    @@ Commit message
     
         gcc/ChangeLog:
     
    -            * doc/extend.texi: Document __nelementsof__ operator.
    -            * target.h (enum type_context_kind): Add __nelementsof__ operator.
    +            * 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_nelementsof_type): Add __nelementsof__ operator.
    +            * c-common.cc (c_lengthof_type): Add __lengthof__ operator.
     
         gcc/c/ChangeLog:
     
                 * c-tree.h
    -            (c_expr_nelementsof_expr, c_expr_nelementsof_type)
    +            (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_nelementsof_expression)
    -            (c_parser_sizeof_or_nelementsof_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_nelementsof_expr, c_expr_nelementsof_type):
    -            Add __nelementsof__operator.
    +            (c_expr_lengthof_expr, c_expr_lengthof_type):
    +            Add __lengthof__operator.
     
         gcc/cp/ChangeLog:
     
    -            * operators.def: Add __nelementsof__ operator.
    +            * operators.def: Add __lengthof__ operator.
     
         gcc/testsuite/ChangeLog:
     
    -            * gcc.dg/nelementsof-compile.c
    -            * gcc.dg/nelementsof-vla.c
    -            * gcc.dg/nelementsof.c: Add tests for __nelementsof__ operator.
    +            * 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/n3313.pdf>
         Link: <https://inbox.sourceware.org/gcc/M8S4oQy--3-2@tutanota.com/T/>
    @@ gcc/c-family/c-common.cc: const struct c_common_resword c_common_reswords[] =
        { "__inline",		RID_INLINE,	0 },
        { "__inline__",	RID_INLINE,	0 },
        { "__label__",	RID_LABEL,	0 },
    -+  { "__nelementsof__",	RID_NELEMENTSOF, 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 the number of elements of an array.  */
     +
     +tree
    -+c_nelementsof_type (location_t loc, tree type)
    ++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 %<nelementsof%> to type %qT", 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 %<nelementsof%> to incomplete type %qT",
    ++		"invalid application of %<lengthof%> to incomplete 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 'nelementsof' expression.  */
    -+DEFTREECODE (NELEMENTSOF_EXPR, "nelementsof_expr", tcc_expression, 1)
    ++/* 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.  */
    @@ gcc/c-family/c-common.h: enum rid
      
        /* C extensions */
        RID_ASM,       RID_TYPEOF,   RID_TYPEOF_UNQUAL, RID_ALIGNOF,  RID_ATTRIBUTE,
    -+  RID_NELEMENTSOF,
    ++  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,
    @@ gcc/c-family/c-common.h: extern tree c_common_truthvalue_conversion (location_t,
      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_nelementsof_type (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);
    @@ gcc/c/c-decl.cc: start_struct (location_t loc, enum tree_code code, tree name,
           sizeof anyhow.  */
     -  if (warn_cxx_compat && (in_sizeof || in_typeof || in_alignof))
     +  if (warn_cxx_compat
    -+      && (in_sizeof || in_typeof || in_alignof || in_nelementsof))
    ++      && (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
    @@ gcc/c/c-decl.cc: start_struct (location_t loc, enum tree_code code, tree name,
     +		    ? "typeof"
     +		    : (in_alignof
     +		       ? "alignof"
    -+		       : "nelementsof"))));
    ++		       : "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 att
            if (warn_cxx_compat
      	  && struct_parse_info != NULL
     -	  && !in_sizeof && !in_typeof && !in_alignof)
    -+	  && !in_sizeof && !in_typeof && !in_alignof && !in_nelementsof)
    ++	  && !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, t
           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_nelementsof))
    ++      && (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
    @@ gcc/c/c-decl.cc: start_enum (location_t loc, struct c_enum_contents *the_enum, t
     +		    ? "typeof"
     +		    : (in_alignof
     +		       ? "alignof"
    -+		       : "nelementsof"))));
    ++		       : "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)
        if (warn_cxx_compat
            && struct_parse_info != NULL
     -      && !in_sizeof && !in_typeof && !in_alignof)
    -+      && !in_sizeof && !in_typeof && !in_alignof && !in_nelementsof)
    ++      && !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: along with GCC; see the file COPYING3.  If not see
     +\f
     +#define c_parser_sizeof_expression(parser)                                    \
     +(                                                                             \
    -+  c_parser_sizeof_or_nelementsof_expression (parser, RID_SIZEOF)              \
    ++  c_parser_sizeof_or_lengthof_expression (parser, RID_SIZEOF)                 \
     +)
      
    -+#define c_parser_nelementsof_expression(parser)                               \
    ++#define c_parser_lengthof_expression(parser)                                  \
     +(                                                                             \
    -+  c_parser_sizeof_or_nelementsof_expression (parser, RID_NELEMENTSOF)         \
    ++  c_parser_sizeof_or_lengthof_expression (parser, RID_LENGTHOF)               \
     +)
     +\f
      /* We need to walk over decls with incomplete struct/union/enum types
    @@ gcc/c/c-parser.cc: static struct c_expr c_parser_binary_expression (c_parser *,
      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_nelementsof_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 *);
    @@ gcc/c/c-parser.cc: c_parser_unary_expression (c_parser *parser)
          case CPP_KEYWORD:
            switch (c_parser_peek_token (parser)->keyword)
      	{
    -+	case RID_NELEMENTSOF:
    -+	  return c_parser_nelementsof_expression (parser);
    ++	case RID_LENGTHOF:
    ++	  return c_parser_lengthof_expression (parser);
      	case RID_SIZEOF:
      	  return c_parser_sizeof_expression (parser);
      	case RID_ALIGNOF:
    @@ gcc/c/c-parser.cc: c_parser_unary_expression (c_parser *parser)
      
      static struct c_expr
     -c_parser_sizeof_expression (c_parser *parser)
    -+c_parser_sizeof_or_nelementsof_expression (c_parser *parser, enum rid rid)
    ++c_parser_sizeof_or_lengthof_expression (c_parser *parser, enum rid rid)
      {
    -+  const char *op_name = (rid == RID_NELEMENTSOF) ? "nelementsof" : "sizeof";
    ++  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_sizeof_expression (c_parser *parser)
        c_parser_consume_token (parser);
        c_inhibit_evaluation_warnings++;
     -  in_sizeof++;
    -+  if (rid == RID_NELEMENTSOF)
    -+    in_nelementsof++;
    ++  if (rid == RID_LENGTHOF)
    ++    in_lengthof++;
     +  else
     +    in_sizeof++;
        if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)
    @@ 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_NELEMENTSOF)
    -+	    in_nelementsof--;
    ++	  if (rid == RID_LENGTHOF)
    ++	    in_lengthof--;
     +	  else
     +	    in_sizeof--;
      	  ret.set_error ();
    @@ gcc/c/c-parser.cc: c_parser_sizeof_expression (c_parser *parser)
            c_inhibit_evaluation_warnings--;
     -      in_sizeof--;
     -      result = c_expr_sizeof_type (expr_loc, type_name);
    -+      if (rid == RID_NELEMENTSOF)
    ++      if (rid == RID_LENGTHOF)
     +	{
    -+	  in_nelementsof--;
    -+	  result = c_expr_nelementsof_type (expr_loc, type_name);
    ++	  in_lengthof--;
    ++	  result = c_expr_lengthof_type (expr_loc, type_name);
     +	}
     +      else
     +	{
    @@ gcc/c/c-parser.cc: c_parser_sizeof_expression (c_parser *parser)
     +    Xof_expr:
            c_inhibit_evaluation_warnings--;
     -      in_sizeof--;
    -+      if (rid == RID_NELEMENTSOF)
    -+	in_nelementsof--;
    ++      if (rid == RID_LENGTHOF)
    ++	in_lengthof--;
     +      else
     +	in_sizeof--;
            mark_exp_read (expr.value);
    @@ gcc/c/c-parser.cc: c_parser_sizeof_expression (c_parser *parser)
     -	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_NELEMENTSOF)
    -+	result = c_expr_nelementsof_expr (expr_loc, expr);
    ++      if (rid == RID_LENGTHOF)
    ++	result = c_expr_lengthof_expr (expr_loc, expr);
     +      else
     +	result = c_expr_sizeof_expr (expr_loc, expr);
          }
    @@ gcc/c/c-tree.h: extern int c_type_dwarf_attribute (const_tree, int);
      /* in c-typeck.cc */
      extern int in_alignof;
      extern int in_sizeof;
    -+extern int in_nelementsof;
    ++extern int in_lengthof;
      extern int in_typeof;
      extern bool c_in_omp_for;
      extern bool c_omp_array_section_p;
    @@ gcc/c/c-tree.h: 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_nelementsof_expr (location_t, struct c_expr);
    -+extern struct c_expr c_expr_nelementsof_type (location_t loc,
    ++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);
    @@ gcc/c/c-typeck.cc: int in_alignof;
      /* The level of nesting inside "sizeof".  */
      int in_sizeof;
      
    -+/* The level of nesting inside "nelementsof".  */
    -+int in_nelementsof;
    ++/* The level of nesting inside "lengthof".  */
    ++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 *
        if (TREE_CODE (ref) == FUNCTION_DECL && !in_alignof)
          {
     -      if (!in_sizeof && !in_typeof)
    -+      if (!in_sizeof && !in_typeof && !in_nelementsof)
    ++      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_nelementsof).  */
    ++  /* 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_nelementsof;
    ++  t->level = in_sizeof + in_typeof + in_lengthof;
        t->next = maybe_used_decls;
        maybe_used_decls = t;
      }
    @@ gcc/c/c-typeck.cc: void
      {
        struct maybe_used_decl *p = maybe_used_decls;
     -  int cur_level = in_sizeof + in_typeof;
    -+  int cur_level = in_sizeof + in_typeof + in_nelementsof;
    ++  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 var;
     +}
     +
    -+/* Return the result of nelementsof applied to EXPR.  */
    ++/* Return the result of lengthof applied to EXPR.  */
     +
     +struct c_expr
    -+c_expr_nelementsof_expr (location_t loc, struct c_expr expr)
    ++c_expr_lengthof_expr (location_t loc, struct c_expr expr)
     +{
     +  struct c_expr ret;
     +  if (expr.value == error_mark_node)
    @@ gcc/c/c-typeck.cc: c_expr_sizeof_type (location_t loc, struct c_type_name *t)
     +
     +      tree folded_expr = c_fully_fold (expr.value, require_constant_value,
     +				       &expr_const_operands);
    -+      ret.value = c_nelementsof_type (loc, TREE_TYPE (folded_expr));
    ++      ret.value = c_lengthof_type (loc, TREE_TYPE (folded_expr));
     +      c_last_sizeof_arg = expr.value;
     +      c_last_sizeof_loc = loc;
    -+      ret.original_code = NELEMENTSOF_EXPR;
    ++      ret.original_code = LENGTHOF_EXPR;
     +      ret.original_type = NULL;
     +      ret.m_decimal = 0;
     +      if (is_top_array_vla (TREE_TYPE (folded_expr)))
     +	{
    -+	  /* nelementsof 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 nelementsof applied to T, a structure for the type
    -+   name passed to nelementsof (rather than the type itself).  LOC is the
    ++/* 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_nelementsof_type (location_t loc, struct c_type_name *t)
    ++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_nelementsof_type (loc, type);
    ++  ret.value = c_lengthof_type (loc, type);
     +  c_last_sizeof_arg = type;
     +  c_last_sizeof_loc = loc;
    -+  ret.original_code = NELEMENTSOF_EXPR;
    ++  ret.original_code = LENGTHOF_EXPR;
     +  ret.original_type = NULL;
     +  ret.m_decimal = 0;
     +  if (type == error_mark_node)
    @@ 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 nelementsof 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 nelementsof 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 ("__nelementsof__", NELEMENTSOF_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/doc/extend.texi: If the operand of the @code{__alignof__} expression is a fu
      the expression evaluates to the alignment of the function which may
      be specified by attribute @code{aligned} (@pxref{Common Function Attributes}).
      
    -+@node nelementsof
    ++@node lengthof
     +@section Determining the Number of Elements of Arrays
    -+@cindex nelementsof
    ++@cindex lengthof
     +@cindex number of elements
     +
    -+The keyword @code{__elemetsf__} determines the length of an array operand,
    ++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
    @@ gcc/doc/extend.texi: If the operand of the @code{__alignof__} expression is a fu
     +
     +@smallexample
     +int a[n];
    -+__elemetsf__ (a);  // returns n
    -+__elemetsf__ (int [7][3]);  // returns 7
    ++__lengthof__ (a);  // returns n
    ++__lengthof__ (int [7][3]);  // returns 7
     +@end smallexample
     +
     +The result of this operator is an integer constant expression,
    @@ gcc/doc/extend.texi: If the operand of the @code{__alignof__} expression is a fu
     +For example:
     +
     +@smallexample
    -+__elemetsf__ (int [7][n++]);  // integer constant expression
    -+__elemetsf__ (int [n++][7]);  // run-time value; n++ is evaluated
    ++__lengthof__ (int [7][n++]);  // integer constant expression
    ++__lengthof__ (int [n++][7]);  // run-time value; n++ is evaluated
     +@end smallexample
     +
      @node Inline
    @@ gcc/target.h: enum type_context_kind {
        TCTX_ALIGNOF,
      
     +  /* Directly measuring the number of elements of array T.  */
    -+  TCTX_NELEMENTSOF,
    ++  TCTX_LENGTHOF,
     +
        /* Creating objects of type T with static storage duration.  */
        TCTX_STATIC_STORAGE,
    @@ gcc/testsuite/gcc.dg/nelementsof-compile.c (new)
     +static int w[] = {1, 2, 3};
     +
     +static int z[0];
    -+static int y[__nelementsof__(z)];
    ++static int y[__lengthof__(z)];
     +
     +void
     +automatic(void)
     +{
    -+  __nelementsof__ (w);
    ++  __lengthof__ (w);
     +}
     +
     +void
     +incomplete (int p[])
     +{
    -+  __nelementsof__ (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.  */
    -+  __nelementsof__ (p);  /* { dg-error "invalid" } */
    ++  __lengthof__ (p);  /* { dg-error "invalid" } */
     +}
     +
     +void
    @@ gcc/testsuite/gcc.dg/nelementsof-compile.c (new)
     +    int fam[];
     +  } s;
     +
    -+  __nelementsof__ (s.fam); /* { dg-error "incomplete" } */
    ++  __lengthof__ (s.fam); /* { dg-error "incomplete" } */
     +}
     +
    -+void fix_fix (int i, char (*a)[3][5], int (*x)[__nelementsof__ (*a)]);
    -+void fix_var (int i, char (*a)[3][i], int (*x)[__nelementsof__ (*a)]);
    -+void fix_uns (int i, char (*a)[3][*], int (*x)[__nelementsof__ (*a)]);
    ++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)
    @@ gcc/testsuite/gcc.dg/nelementsof-compile.c (new)
     +    int x[3];
     +  } s;
     +
    -+  __nelementsof__ (x); /* { dg-error "invalid" } */
    -+  __nelementsof__ (int); /* { dg-error "invalid" } */
    -+  __nelementsof__ (s); /* { dg-error "invalid" } */
    -+  __nelementsof__ (struct s); /* { dg-error "invalid" } */
    -+  __nelementsof__ (&x); /* { dg-error "invalid" } */
    -+  __nelementsof__ (p); /* { dg-error "invalid" } */
    -+  __nelementsof__ (int *); /* { dg-error "invalid" } */
    -+  __nelementsof__ (&s.x); /* { dg-error "invalid" } */
    -+  __nelementsof__ (int (*)[3]); /* { dg-error "invalid" } */
    ++  __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();
    @@ gcc/testsuite/gcc.dg/nelementsof-compile.c (new)
     +{
     +  int b[n][n];
     +
    -+  __nelementsof__ (a[f1()]);
    -+  __nelementsof__ (b[f2()]);
    ++  __lengthof__ (a[f1()]);
    ++  __lengthof__ (b[f2()]);
     +}
     +
     +void
     +no_parens(void)
     +{
    -+  __nelementsof__ a;
    -+  __nelementsof__ *a;
    -+  __nelementsof__ (int [3]) {};
    ++  __lengthof__ a;
    ++  __lengthof__ *a;
    ++  __lengthof__ (int [3]) {};
     +
    -+  __nelementsof__ int [3]; /* { dg-error "expected expression before" } */
    ++  __lengthof__ int [3]; /* { dg-error "expected expression before" } */
     +}
     +
     +void
    @@ gcc/testsuite/gcc.dg/nelementsof-compile.c (new)
     +{
     +  int n = 7;
     +
    -+  _Static_assert (__nelementsof__ (int [3][n]) == 3);
    -+  _Static_assert (__nelementsof__ (int [n][3]) == 7); /* { dg-error "not constant" } */
    -+  _Static_assert (__nelementsof__ (int [0][3]) == 0);
    -+  _Static_assert (__nelementsof__ (int [0]) == 0);
    ++  _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: nelementsof(int [0][n]) should result in a constant expression.  */
    -+  _Static_assert (__nelementsof__ (int [0][n]) == 0); /* { dg-error "not constant" } */
    ++  /* FIXME: lengthof(int [0][n]) should result in a constant expression.  */
    ++  _Static_assert (__lengthof__ (int [0][n]) == 0); /* { dg-error "not constant" } */
     +}
     
      ## gcc/testsuite/gcc.dg/nelementsof-vla.c (new) ##
    @@ gcc/testsuite/gcc.dg/nelementsof-vla.c (new)
     +
     +void fix_fix (int i,
     +	      char (*a)[3][5],
    -+	      int (*x)[__nelementsof__ (*a)]);
    ++	      int (*x)[__lengthof__ (*a)]);
     +void fix_var (int i,
     +	      char (*a)[3][i], /* dg-warn "variable" */
    -+	      int (*x)[__nelementsof__ (*a)]);
    ++	      int (*x)[__lengthof__ (*a)]);
     +void fix_uns (int i,
     +	      char (*a)[3][*],
    -+	      int (*x)[__nelementsof__ (*a)]);
    ++	      int (*x)[__lengthof__ (*a)]);
     +
     +void zro_fix (int i,
     +	      char (*a)[0][5],
    -+	      int (*x)[__nelementsof__ (*a)]);
    ++	      int (*x)[__lengthof__ (*a)]);
     +void zro_var (int i,
     +	      char (*a)[0][i], /* dg-warn "variable" */
    -+	      int (*x)[__nelementsof__ (*a)]);
    ++	      int (*x)[__lengthof__ (*a)]);
     +void zro_uns (int i,
     +	      char (*a)[0][*],
    -+	      int (*x)[__nelementsof__ (*a)]);
    ++	      int (*x)[__lengthof__ (*a)]);
     +
     +void var_fix (int i,
     +	      char (*a)[i][5], /* dg-warn "variable" */
    -+	      int (*x)[__nelementsof__ (*a)]); /* dg-warn "variable" */
    ++	      int (*x)[__lengthof__ (*a)]); /* dg-warn "variable" */
     +void var_var (int i,
     +	      char (*a)[i][i], /* dg-warn "variable" */
    -+	      int (*x)[__nelementsof__ (*a)]); /* dg-warn "variable" */
    ++	      int (*x)[__lengthof__ (*a)]); /* dg-warn "variable" */
     +void var_uns (int i,
     +	      char (*a)[i][*], /* dg-warn "variable" */
    -+	      int (*x)[__nelementsof__ (*a)]); /* dg-warn "variable" */
    ++	      int (*x)[__lengthof__ (*a)]); /* dg-warn "variable" */
     +
     +void uns_fix (int i,
     +	      char (*a)[*][5],
    -+	      int (*x)[__nelementsof__ (*a)]);
    ++	      int (*x)[__lengthof__ (*a)]);
     +void uns_var (int i,
     +	      char (*a)[*][i], /* dg-warn "variable" */
    -+	      int (*x)[__nelementsof__ (*a)]);
    ++	      int (*x)[__lengthof__ (*a)]);
     +void uns_uns (int i,
     +	      char (*a)[*][*],
    -+	      int (*x)[__nelementsof__ (*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[__nelementsof__(z2)];
    ++//static int y2[__lengthof__(z2)];
     
      ## gcc/testsuite/gcc.dg/nelementsof.c (new) ##
     @@
    @@ gcc/testsuite/gcc.dg/nelementsof.c (new)
     +{
     +  short a[7];
     +
    -+  static_assert (__nelementsof__ (a) == 7);
    -+  static_assert (__nelementsof__ (long [0]) == 0);
    -+  static_assert (__nelementsof__ (unsigned [99]) == 99);
    ++  static_assert (__lengthof__ (a) == 7);
    ++  static_assert (__lengthof__ (long [0]) == 0);
    ++  static_assert (__lengthof__ (unsigned [99]) == 99);
     +}
     +
     +void
    @@ gcc/testsuite/gcc.dg/nelementsof.c (new)
     +  int a[] = {1, 2, 3};
     +  int z[] = {};
     +
    -+  static_assert (__nelementsof__ (a) == 3);
    -+  static_assert (__nelementsof__ (z) == 0);
    ++  static_assert (__lengthof__ (a) == 3);
    ++  static_assert (__lengthof__ (z) == 0);
     +}
     +
     +void
    @@ gcc/testsuite/gcc.dg/nelementsof.c (new)
     +  unsigned n;
     +
     +  n = 99;
    -+  assert (__nelementsof__ (short [n - 10]) == 99 - 10);
    ++  assert (__lengthof__ (short [n - 10]) == 99 - 10);
     +
     +  int v[n / 2];
    -+  assert (__nelementsof__ (v) == 99 / 2);
    ++  assert (__lengthof__ (v) == 99 / 2);
     +
     +  n = 0;
     +  int z[n];
    -+  assert (__nelementsof__ (z) == 0);
    ++  assert (__lengthof__ (z) == 0);
     +}
     +
     +void
    @@ gcc/testsuite/gcc.dg/nelementsof.c (new)
     +    int a[8];
     +  } s;
     +
    -+  static_assert (__nelementsof__ (s.a) == 8);
    ++  static_assert (__lengthof__ (s.a) == 8);
     +}
     +
     +void
    @@ gcc/testsuite/gcc.dg/nelementsof.c (new)
     +  int i;
     +
     +  i = 7;
    -+  assert (__nelementsof__ (struct {int x;}[i++]) == 7);
    ++  assert (__lengthof__ (struct {int x;}[i++]) == 7);
     +  assert (i == 7 + 1);
     +
     +  int v[i];
     +  int (*p)[i];
     +  p = &v;
    -+  assert (__nelementsof__ (*p++) == i);
    ++  assert (__lengthof__ (*p++) == i);
     +  assert (p - 1 == &v);
     +}
     +
    @@ gcc/testsuite/gcc.dg/nelementsof.c (new)
     +  int i;
     +
     +  i = 3;
    -+  static_assert (__nelementsof__ (struct {int x[i++];}[3]) == 3);
    ++  static_assert (__lengthof__ (struct {int x[i++];}[3]) == 3);
     +  assert (i == 3);
     +}
     +
    @@ gcc/testsuite/gcc.dg/nelementsof.c (new)
     +array_noeval (void)
     +{
     +  long a[5];
    -+  long (*p)[__nelementsof__ (a)];
    ++  long (*p)[__lengthof__ (a)];
     +
     +  p = &a;
    -+  static_assert (__nelementsof__ (*p++) == 5);
    ++  static_assert (__lengthof__ (*p++) == 5);
     +  assert (p == &a);
     +}
     +
    @@ gcc/testsuite/gcc.dg/nelementsof.c (new)
     +{
     +  int i;
     +
    -+  static_assert (__nelementsof__ (int [0][4]) == 0);
    ++  static_assert (__lengthof__ (int [0][4]) == 0);
     +  i = 3;
    -+  assert (__nelementsof__ (int [0][i]) == 0);
    ++  assert (__lengthof__ (int [0][i]) == 0);
     +}
     +
     +void
    @@ gcc/testsuite/gcc.dg/nelementsof.c (new)
     +{
     +  int i;
     +
    -+  static_assert (__nelementsof__ (int [7][4]) == 7);
    ++  static_assert (__lengthof__ (int [7][4]) == 7);
     +  i = 3;
    -+  static_assert (__nelementsof__ (int [7][i]) == 7);
    ++  static_assert (__lengthof__ (int [7][i]) == 7);
     +}
     +
     +void
    @@ gcc/testsuite/gcc.dg/nelementsof.c (new)
     +  int i, j;
     +
     +  i = 7;
    -+  assert (__nelementsof__ (int [i++][4]) == 7);
    ++  assert (__lengthof__ (int [i++][4]) == 7);
     +  assert (i == 7 + 1);
     +
     +  i = 9;
     +  j = 3;
    -+  assert (__nelementsof__ (int [i++][j]) == 9);
    ++  assert (__lengthof__ (int [i++][j]) == 9);
     +  assert (i == 9 + 1);
     +}
     +
    @@ gcc/testsuite/gcc.dg/nelementsof.c (new)
     +  int a[7];
     +  int v[n];
     +
    -+  static_assert (__nelementsof__ a == 7); 
    -+  assert (__nelementsof__ v == 3); 
    ++  static_assert (__lengthof__ a == 7); 
    ++  assert (__lengthof__ v == 3); 
     +}
     +
     +int

-- 
2.45.2


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 318+ messages in thread

* [PATCH v13 1/4] contrib/: Add support for Cc: and Link: tags
  2024-10-02  9:41   ` [PATCH v13 0/4] c: Add __lengthof__ operator Alejandro Colomar
@ 2024-10-02  9:41     ` Alejandro Colomar
  2024-10-02  9:41     ` [PATCH v13 2/4] gcc/: Rename array_type_nelts() => array_type_nelts_minus_one() Alejandro Colomar
                       ` (3 subsequent siblings)
  4 siblings, 0 replies; 318+ messages in thread
From: Alejandro Colomar @ 2024-10-02  9:41 UTC (permalink / raw)
  To: gcc-patches
  Cc: Alejandro Colomar, Gabriel Ravier, Jakub Jelinek, Kees Cook,
	Qing Zhao, Jens Gustedt, David Brown, Florian Weimer,
	Andreas Schwab, Timm Baeder, Daniel Plakosh, A. Jiang,
	Eugene Zelenko, Aaron Ballman, Paul Koning, Daniel Lundin,
	Nikolaos Strimpas, JeanHeyd Meneide, Fernando Borretti,
	Jonathan Protzenko, Chris Bazley, Ville Voutilainen,
	Alex Celeste, Jakub Łukasiewicz, Douglas McIlroy,
	Jason Merrill, Xavier Del Campo Romero, Siddhesh Poyarekar,
	DJ Delorie, Carlos O'Donell, Stephen Coady, Robert Seacord

[-- Attachment #1: Type: text/plain, Size: 1258 bytes --]

contrib/ChangeLog:

	* gcc-changelog/git_commit.py (GitCommit):
	Add support for 'Cc: ' and 'Link: ' tags.

Cc: Jason Merrill <jason@redhat.com>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
---
 contrib/gcc-changelog/git_commit.py | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/contrib/gcc-changelog/git_commit.py b/contrib/gcc-changelog/git_commit.py
index 87ecb9e1a17..64fb986b74c 100755
--- a/contrib/gcc-changelog/git_commit.py
+++ b/contrib/gcc-changelog/git_commit.py
@@ -182,7 +182,8 @@ CO_AUTHORED_BY_PREFIX = 'co-authored-by: '
 
 REVIEW_PREFIXES = ('reviewed-by: ', 'reviewed-on: ', 'signed-off-by: ',
                    'acked-by: ', 'tested-by: ', 'reported-by: ',
-                   'suggested-by: ')
+                   'suggested-by: ', 'cc: ')
+LINK_PREFIXES = ('link: ')
 DATE_FORMAT = '%Y-%m-%d'
 
 
@@ -524,6 +525,8 @@ class GitCommit:
                     continue
                 elif lowered_line.startswith(REVIEW_PREFIXES):
                     continue
+                elif lowered_line.startswith(LINK_PREFIXES):
+                    continue
                 else:
                     m = cherry_pick_regex.search(line)
                     if m:
-- 
2.45.2


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 318+ messages in thread

* [PATCH v13 2/4] gcc/: Rename array_type_nelts() => array_type_nelts_minus_one()
  2024-10-02  9:41   ` [PATCH v13 0/4] c: Add __lengthof__ operator Alejandro Colomar
  2024-10-02  9:41     ` [PATCH v13 1/4] contrib/: Add support for Cc: and Link: tags Alejandro Colomar
@ 2024-10-02  9:41     ` Alejandro Colomar
  2024-10-02  9:41     ` [PATCH v13 3/4] Merge definitions of array_type_nelts_top() Alejandro Colomar
                       ` (2 subsequent siblings)
  4 siblings, 0 replies; 318+ messages in thread
From: Alejandro Colomar @ 2024-10-02  9:41 UTC (permalink / raw)
  To: gcc-patches
  Cc: Alejandro Colomar, Gabriel Ravier, Jakub Jelinek, Kees Cook,
	Qing Zhao, Jens Gustedt, David Brown, Florian Weimer,
	Andreas Schwab, Timm Baeder, Daniel Plakosh, A. Jiang,
	Eugene Zelenko, Aaron Ballman, Paul Koning, Daniel Lundin,
	Nikolaos Strimpas, JeanHeyd Meneide, Fernando Borretti,
	Jonathan Protzenko, Chris Bazley, Ville Voutilainen,
	Alex Celeste, Jakub Łukasiewicz, Douglas McIlroy,
	Jason Merrill, Xavier Del Campo Romero, Siddhesh Poyarekar,
	DJ Delorie, Carlos O'Donell, Stephen Coady, Robert Seacord,
	Martin Uecker, Joseph Myers, Richard Biener

[-- Attachment #1: Type: text/plain, Size: 12749 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>

gcc/ChangeLog:

	* tree.cc (array_type_nelts, array_type_nelts_minus_one)
	* tree.h (array_type_nelts, array_type_nelts_minus_one)
	* expr.cc (count_type_elements)
	* config/aarch64/aarch64.cc
	(pure_scalable_type_info::analyze_array)
	* config/i386/i386.cc (ix86_canonical_va_list_type):
	Rename array_type_nelts() => array_type_nelts_minus_one()
	The old name was misleading.

gcc/c/ChangeLog:

	* c-decl.cc (one_element_array_type_p, get_parm_array_spec)
	* c-fold.cc (c_fold_array_ref):
	Rename array_type_nelts() => array_type_nelts_minus_one()

gcc/cp/ChangeLog:

	* decl.cc (reshape_init_array)
	* init.cc
	(build_zero_init_1)
	(build_value_init_noctor)
	(build_vec_init)
	(build_delete)
	* lambda.cc (add_capture)
	* tree.cc (array_type_nelts_top):
	Rename array_type_nelts() => array_type_nelts_minus_one()

gcc/fortran/ChangeLog:

	* trans-array.cc (structure_alloc_comps)
	* trans-openmp.cc
	(gfc_walk_alloc_comps)
	(gfc_omp_clause_linear_ctor):
	Rename array_type_nelts() => array_type_nelts_minus_one()

gcc/rust/ChangeLog:

	* backend/rust-tree.cc (array_type_nelts_top):
	Rename array_type_nelts() => array_type_nelts_minus_one()

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>
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 aa7f69d1b7b..c73d3107efb 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -5358,7 +5358,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]".  */
@@ -6306,15 +6306,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 27e24ba70ab..21606701725 100644
--- a/gcc/config/aarch64/aarch64.cc
+++ b/gcc/config/aarch64/aarch64.cc
@@ -1084,7 +1084,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 546c964d2a4..c6407843fc5 100644
--- a/gcc/config/i386/i386.cc
+++ b/gcc/config/i386/i386.cc
@@ -24393,7 +24393,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 6458e96bded..98133894c48 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -6908,7 +6908,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 320be8b17a1..803da754be1 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 8c35926436d..22ac3c1a5f3 100644
--- a/gcc/fortran/trans-array.cc
+++ b/gcc/fortran/trans-array.cc
@@ -9640,7 +9640,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 b14cfbe7929..7439777f307 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;
 
@@ -14789,7 +14789,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 93aa7d22d6f..4e29544a36c 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] 318+ messages in thread

* [PATCH v13 3/4] Merge definitions of array_type_nelts_top()
  2024-10-02  9:41   ` [PATCH v13 0/4] c: Add __lengthof__ operator Alejandro Colomar
  2024-10-02  9:41     ` [PATCH v13 1/4] contrib/: Add support for Cc: and Link: tags Alejandro Colomar
  2024-10-02  9:41     ` [PATCH v13 2/4] gcc/: Rename array_type_nelts() => array_type_nelts_minus_one() Alejandro Colomar
@ 2024-10-02  9:41     ` Alejandro Colomar
  2024-10-02  9:41     ` [PATCH v13 4/4] c: Add __lengthof__ operator Alejandro Colomar
  2024-10-07 17:35     ` [PATCH v13 0/4] " Joseph Myers
  4 siblings, 0 replies; 318+ messages in thread
From: Alejandro Colomar @ 2024-10-02  9:41 UTC (permalink / raw)
  To: gcc-patches
  Cc: Alejandro Colomar, Gabriel Ravier, Jakub Jelinek, Kees Cook,
	Qing Zhao, Jens Gustedt, David Brown, Florian Weimer,
	Andreas Schwab, Timm Baeder, Daniel Plakosh, A. Jiang,
	Eugene Zelenko, Aaron Ballman, Paul Koning, Daniel Lundin,
	Nikolaos Strimpas, JeanHeyd Meneide, Fernando Borretti,
	Jonathan Protzenko, Chris Bazley, Ville Voutilainen,
	Alex Celeste, Jakub Łukasiewicz, Douglas McIlroy,
	Jason Merrill, Xavier Del Campo Romero, Siddhesh Poyarekar,
	DJ Delorie, Carlos O'Donell, Stephen Coady, Robert Seacord

[-- Attachment #1: Type: text/plain, Size: 4880 bytes --]

There were two identical definitions, and none of them are available
where they are needed for implementing __nelementsof__.  Merge them, and
provide the single definition in gcc/tree.{h,cc}, where it's available
for __nelementsof__, 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 2eeb5e3e8b1..6913175c3ce 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -8108,7 +8108,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 7439777f307..d0a7156d982 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 4e29544a36c..372f4dd71da 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] 318+ messages in thread

* [PATCH v13 4/4] c: Add __lengthof__ operator
  2024-10-02  9:41   ` [PATCH v13 0/4] c: Add __lengthof__ operator Alejandro Colomar
                       ` (2 preceding siblings ...)
  2024-10-02  9:41     ` [PATCH v13 3/4] Merge definitions of array_type_nelts_top() Alejandro Colomar
@ 2024-10-02  9:41     ` Alejandro Colomar
  2024-10-07 17:35     ` [PATCH v13 0/4] " Joseph Myers
  4 siblings, 0 replies; 318+ messages in thread
From: Alejandro Colomar @ 2024-10-02  9:41 UTC (permalink / raw)
  To: gcc-patches
  Cc: Alejandro Colomar, Gabriel Ravier, Jakub Jelinek, Kees Cook,
	Qing Zhao, Jens Gustedt, David Brown, Florian Weimer,
	Andreas Schwab, Timm Baeder, Daniel Plakosh, A. Jiang,
	Eugene Zelenko, Aaron Ballman, Paul Koning, Daniel Lundin,
	Nikolaos Strimpas, JeanHeyd Meneide, Fernando Borretti,
	Jonathan Protzenko, Chris Bazley, Ville Voutilainen,
	Alex Celeste, Jakub Łukasiewicz, Douglas McIlroy,
	Jason Merrill, Xavier Del Campo Romero, Siddhesh Poyarekar,
	DJ Delorie, Carlos O'Donell, Stephen Coady, Robert Seacord,
	Joseph Myers, Martin Uecker

[-- Attachment #1: Type: text/plain, Size: 30549 bytes --]

This operator is similar to sizeof but can only be applied to an array,
and returns its number of elements.

FUTURE DIRECTIONS:

-  We should make it work with array parameters to functions,
   and somehow magically return the number of elements of the array,
   regardless of it being really a pointer.

-  Fix support for [0].

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/n3313.pdf>
Link: <https://inbox.sourceware.org/gcc/M8S4oQy--3-2@tutanota.com/T/>
Link: <https://github.com/llvm/llvm-project/issues/102836>
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>
Cc: Daniel Plakosh <dplakosh@cert.org>
Cc: "A. Jiang" <de34@live.cn>
Cc: Eugene Zelenko <eugene.zelenko@gmail.com>
Cc: Aaron Ballman <aaron.ballman@intel.com>
Cc: Paul Koning <paulkoning@comcast.net>
Cc: Daniel Lundin <daniel.lundin.mail@gmail.com>
Cc: Nikolaos Strimpas <Strnik86@protonmail.com>
Cc: JeanHeyd Meneide <phdofthehouse@gmail.com>
Cc: Fernando Borretti <fernando@borretti.me>
Cc: Jonathan Protzenko <jonathan.protzenko@ens-lyon.org>
Cc: Chris Bazley <Chris.Bazley@arm.com>
Cc: Ville Voutilainen <ville.voutilainen@gmail.com>
Cc: Alex Celeste <alexg.nvfp@gmail.com>
Cc: Jakub Łukasiewicz <jakublukasiewicz@outlook.com>
Cc: Douglas McIlroy <douglas.mcilroy@dartmouth.edu>
Cc: Jason Merrill <jason@redhat.com>
Suggested-by: Xavier Del Campo Romero <xavi.dcr@tutanota.com>
Co-authored-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                            |  22 ++-
 gcc/c/c-parser.cc                          |  62 +++++++--
 gcc/c/c-tree.h                             |   4 +
 gcc/c/c-typeck.cc                          | 118 +++++++++++++++-
 gcc/cp/operators.def                       |   1 +
 gcc/doc/extend.texi                        |  30 +++++
 gcc/target.h                               |   3 +
 gcc/testsuite/gcc.dg/nelementsof-compile.c | 115 ++++++++++++++++
 gcc/testsuite/gcc.dg/nelementsof-vla.c     |  46 +++++++
 gcc/testsuite/gcc.dg/nelementsof.c         | 150 +++++++++++++++++++++
 13 files changed, 558 insertions(+), 24 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/nelementsof-compile.c
 create mode 100644 gcc/testsuite/gcc.dg/nelementsof-vla.c
 create mode 100644 gcc/testsuite/gcc.dg/nelementsof.c

diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
index e7e371fd26f..13704a55669 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 lementsof keyword:
+   Return the number of elements of an 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 d3827573a36..d35ff337f64 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,
@@ -887,6 +888,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 c73d3107efb..82de20df675 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -8992,12 +8992,17 @@ 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);
@@ -9957,7 +9962,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);
      }
 
@@ -10131,12 +10136,17 @@ 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",
@@ -10330,7 +10340,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 aff5af17430..4256e154db9 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,8 @@ 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 *,
@@ -9910,6 +9921,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:
@@ -9949,12 +9962,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;
@@ -9963,7 +9977,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)))
     {
@@ -9982,7 +9999,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;
@@ -9994,31 +10014,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 57befb94c08..bb1dc1cfad3 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..7f87b68c6ef 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 5845bcedf6e..3a2515b85c2 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -10544,6 +10544,36 @@ 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 lengthof
+@section Determining the Number of Elements of Arrays
+@cindex lengthof
+@cindex number of elements
+
+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 parenthesized complete array type name
+or an expression of such a type.
+For example:
+
+@smallexample
+int a[n];
+__lengthof__ (a);  // returns n
+__lengthof__ (int [7][3]);  // returns 7
+@end smallexample
+
+The result of this operator is an integer constant expression,
+unless the top-level array is a variable-length array.
+The operand is only evaluated
+if the top-level array is a variable-length array.
+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..d7434a95128 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 number of elements of array T.  */
+  TCTX_LENGTHOF,
+
   /* Creating objects of type T with static storage duration.  */
   TCTX_STATIC_STORAGE,
 
diff --git a/gcc/testsuite/gcc.dg/nelementsof-compile.c b/gcc/testsuite/gcc.dg/nelementsof-compile.c
new file mode 100644
index 00000000000..297ffe75f60
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/nelementsof-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: lengthof(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/nelementsof-vla.c b/gcc/testsuite/gcc.dg/nelementsof-vla.c
new file mode 100644
index 00000000000..f415fcf5a89
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/nelementsof-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/nelementsof.c b/gcc/testsuite/gcc.dg/nelementsof.c
new file mode 100644
index 00000000000..86a530d613f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/nelementsof.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] 318+ messages in thread

* Re: [PATCH v13 0/4] c: Add __lengthof__ operator
  2024-10-02  9:41   ` [PATCH v13 0/4] c: Add __lengthof__ operator Alejandro Colomar
                       ` (3 preceding siblings ...)
  2024-10-02  9:41     ` [PATCH v13 4/4] c: Add __lengthof__ operator Alejandro Colomar
@ 2024-10-07 17:35     ` Joseph Myers
  2024-10-08  0:04       ` Alejandro Colomar
  2024-10-08  8:25       ` Jakub Łukasiewicz
  4 siblings, 2 replies; 318+ messages in thread
From: Joseph Myers @ 2024-10-07 17:35 UTC (permalink / raw)
  To: Alejandro Colomar
  Cc: gcc-patches, Gabriel Ravier, Jakub Jelinek, Kees Cook, Qing Zhao,
	Jens Gustedt, David Brown, Florian Weimer, Andreas Schwab,
	Timm Baeder, Daniel Plakosh, A. Jiang, Eugene Zelenko,
	Aaron Ballman, Paul Koning, Daniel Lundin, Nikolaos Strimpas,
	JeanHeyd Meneide, Fernando Borretti, Jonathan Protzenko,
	Chris Bazley, Ville Voutilainen, Alex Celeste,
	Jakub Łukasiewicz, Douglas McIlroy, Jason Merrill,
	Xavier Del Campo Romero, Siddhesh Poyarekar, DJ Delorie,
	Carlos O'Donell, Stephen Coady, Robert Seacord

Patches 1, 2 and 3 are logically nothing to do with this feature.  I'll 
wait for them to be reviewed so that we only have a single-patch series, 
before doing final review of the main patch.

Since the feature was accepted as _Lengthof, that's the form that should 
be added to GCC; no __lengthof__ variant needed.  In general in GCC, 
although not strictly required by the standard in this case, we use 
pedwarn_c23 (pass OPT_Wpedantic as the option) to diagnose the use of a 
new C2Y feature that's not in C23 (if -pedantic with a pre-C2Y standard, 
or -Wc23-c2y-compat even in C2Y mode), with appropriate testcases to 
verify this (error with -std=c23 -pedantic-errors, warning with -std=c23 
-pedantic, no diagnostic with -std=c23 -pedantic-errors 
-Wno-c23-c2y-compat, no diagnostic with -std=c2y -pedantic-errors, warning 
with -std=c2y -pedantic-errors -Wc23-c2y-compat).  (pedwarn_c23 handles 
that logic, you just need the pedwarn_c23 call and the tests for those 
various cases.)

-- 
Joseph S. Myers
josmyers@redhat.com


^ permalink raw reply	[flat|nested] 318+ messages in thread

* Re: [PATCH v13 0/4] c: Add __lengthof__ operator
  2024-10-07 17:35     ` [PATCH v13 0/4] " Joseph Myers
@ 2024-10-08  0:04       ` Alejandro Colomar
  2024-10-08  0:09         ` Alejandro Colomar
  2024-10-08 13:19         ` Joseph Myers
  2024-10-08  8:25       ` Jakub Łukasiewicz
  1 sibling, 2 replies; 318+ messages in thread
From: Alejandro Colomar @ 2024-10-08  0:04 UTC (permalink / raw)
  To: Joseph Myers
  Cc: gcc-patches, Gabriel Ravier, Jakub Jelinek, Kees Cook, Qing Zhao,
	Jens Gustedt, David Brown, Florian Weimer, Andreas Schwab,
	Timm Baeder, Daniel Plakosh, A. Jiang, Eugene Zelenko,
	Aaron Ballman, Paul Koning, Daniel Lundin, Nikolaos Strimpas,
	JeanHeyd Meneide, Fernando Borretti, Jonathan Protzenko,
	Chris Bazley, Ville Voutilainen, Alex Celeste,
	Jakub Łukasiewicz, Douglas McIlroy, Jason Merrill,
	Xavier Del Campo Romero, Siddhesh Poyarekar, DJ Delorie,
	Carlos O'Donell, Stephen Coady, Robert Seacord

[-- Attachment #1: Type: text/plain, Size: 1884 bytes --]

Hi Joseph,

On Mon, Oct 07, 2024 at 05:35:16PM GMT, Joseph Myers wrote:
> Patches 1, 2 and 3 are logically nothing to do with this feature.  I'll 
> wait for them to be reviewed so that we only have a single-patch series, 
> before doing final review of the main patch.

I do not fully understand.  Who has to review patches 1,2,3?  Also, do
you want to merge them, then I resend patch 4 as a single patch, and
then you review that one?  If so, that looks like a good plan to me.

Thanks!

> Since the feature was accepted as _Lengthof, that's the form that should 
> be added to GCC; no __lengthof__ variant needed.

Okay, I'm indiferent to choosing between both of those names; since they
are equally harmful.  ;)

On the other hand, I'm tempted to propose a different name, and force
ISO to reconsider and follow.  The discussion on this list was more
thorough than the short discussion at WG14, which didn't really take
into consideration the dangers of harmful and error-prone nomenclature.

> In general in GCC, 
> although not strictly required by the standard in this case, we use 
> pedwarn_c23 (pass OPT_Wpedantic as the option) to diagnose the use of a 
> new C2Y feature that's not in C23

Thanks; will do.

Have a lovely night!
Alex

> (if -pedantic with a pre-C2Y standard, 
> or -Wc23-c2y-compat even in C2Y mode), with appropriate testcases to 
> verify this (error with -std=c23 -pedantic-errors, warning with -std=c23 
> -pedantic, no diagnostic with -std=c23 -pedantic-errors 
> -Wno-c23-c2y-compat, no diagnostic with -std=c2y -pedantic-errors, warning 
> with -std=c2y -pedantic-errors -Wc23-c2y-compat).  (pedwarn_c23 handles 
> that logic, you just need the pedwarn_c23 call and the tests for those 
> various cases.)
> 
> -- 
> 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] 318+ messages in thread

* Re: [PATCH v13 0/4] c: Add __lengthof__ operator
  2024-10-08  0:04       ` Alejandro Colomar
@ 2024-10-08  0:09         ` Alejandro Colomar
  2024-10-08  6:45           ` Jakub Jelinek
  2024-10-08 13:19         ` Joseph Myers
  1 sibling, 1 reply; 318+ messages in thread
From: Alejandro Colomar @ 2024-10-08  0:09 UTC (permalink / raw)
  To: Joseph Myers
  Cc: gcc-patches, Gabriel Ravier, Jakub Jelinek, Kees Cook, Qing Zhao,
	Jens Gustedt, David Brown, Florian Weimer, Andreas Schwab,
	Timm Baeder, Daniel Plakosh, A. Jiang, Eugene Zelenko,
	Aaron Ballman, Paul Koning, Daniel Lundin, Nikolaos Strimpas,
	JeanHeyd Meneide, Fernando Borretti, Jonathan Protzenko,
	Chris Bazley, Ville Voutilainen, Alex Celeste,
	Jakub Łukasiewicz, Douglas McIlroy, Jason Merrill,
	Xavier Del Campo Romero, Siddhesh Poyarekar, DJ Delorie,
	Carlos O'Donell, Stephen Coady, Robert Seacord

[-- Attachment #1: Type: text/plain, Size: 2239 bytes --]

On Tue, Oct 08, 2024 at 02:04:39AM GMT, Alejandro Colomar wrote:
> Hi Joseph,
> 
> On Mon, Oct 07, 2024 at 05:35:16PM GMT, Joseph Myers wrote:
> > Patches 1, 2 and 3 are logically nothing to do with this feature.  I'll 
> > wait for them to be reviewed so that we only have a single-patch series, 
> > before doing final review of the main patch.
> 
> I do not fully understand.  Who has to review patches 1,2,3?  Also, do
> you want to merge them, then I resend patch 4 as a single patch, and
> then you review that one?  If so, that looks like a good plan to me.
> 
> Thanks!
> 
> > Since the feature was accepted as _Lengthof, that's the form that should 
> > be added to GCC; no __lengthof__ variant needed.
> 
> Okay, I'm indiferent to choosing between both of those names; since they
> are equally harmful.  ;)
> 
> On the other hand, I'm tempted to propose a different name, and force
> ISO to reconsider and follow.  The discussion on this list was more
> thorough than the short discussion at WG14, which didn't really take
> into consideration the dangers of harmful and error-prone nomenclature.
> 
> > In general in GCC, 
> > although not strictly required by the standard in this case, we use 
> > pedwarn_c23 (pass OPT_Wpedantic as the option) to diagnose the use of a 
> > new C2Y feature that's not in C23
> 
> Thanks; will do.

On the other hand, should we provide a version of the operator that is
free from pedantic warnings?  A GNU extension?

Cheers,
Alex

> 
> Have a lovely night!
> Alex
> 
> > (if -pedantic with a pre-C2Y standard, 
> > or -Wc23-c2y-compat even in C2Y mode), with appropriate testcases to 
> > verify this (error with -std=c23 -pedantic-errors, warning with -std=c23 
> > -pedantic, no diagnostic with -std=c23 -pedantic-errors 
> > -Wno-c23-c2y-compat, no diagnostic with -std=c2y -pedantic-errors, warning 
> > with -std=c2y -pedantic-errors -Wc23-c2y-compat).  (pedwarn_c23 handles 
> > that logic, you just need the pedwarn_c23 call and the tests for those 
> > various cases.)
> > 
> > -- 
> > Joseph S. Myers
> > josmyers@redhat.com
> > 
> 
> -- 
> <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] 318+ messages in thread

* Re: [PATCH v13 0/4] c: Add __lengthof__ operator
  2024-10-08  0:09         ` Alejandro Colomar
@ 2024-10-08  6:45           ` Jakub Jelinek
  2024-10-08  8:11             ` Alejandro Colomar
  0 siblings, 1 reply; 318+ messages in thread
From: Jakub Jelinek @ 2024-10-08  6:45 UTC (permalink / raw)
  To: Alejandro Colomar
  Cc: Joseph Myers, gcc-patches, Gabriel Ravier, Kees Cook, Qing Zhao,
	Jens Gustedt, David Brown, Florian Weimer, Andreas Schwab,
	Timm Baeder, Daniel Plakosh, A. Jiang, Eugene Zelenko,
	Aaron Ballman, Paul Koning, Daniel Lundin, Nikolaos Strimpas,
	JeanHeyd Meneide, Fernando Borretti, Jonathan Protzenko,
	Chris Bazley, Ville Voutilainen, Alex Celeste,
	Jakub Łukasiewicz, Douglas McIlroy, Jason Merrill,
	Xavier Del Campo Romero, Siddhesh Poyarekar, DJ Delorie,
	Carlos O'Donell, Stephen Coady, Robert Seacord

On Tue, Oct 08, 2024 at 02:09:52AM +0200, Alejandro Colomar wrote:
> On the other hand, should we provide a version of the operator that is
> free from pedantic warnings?  A GNU extension?

No, why?  One can always use (__extension__ _Lengthof (...)).

	Jakub


^ permalink raw reply	[flat|nested] 318+ messages in thread

* Re: [PATCH v13 0/4] c: Add __lengthof__ operator
  2024-10-08  6:45           ` Jakub Jelinek
@ 2024-10-08  8:11             ` Alejandro Colomar
  0 siblings, 0 replies; 318+ messages in thread
From: Alejandro Colomar @ 2024-10-08  8:11 UTC (permalink / raw)
  To: Jakub Jelinek
  Cc: Joseph Myers, gcc-patches, Gabriel Ravier, Kees Cook, Qing Zhao,
	Jens Gustedt, David Brown, Florian Weimer, Andreas Schwab,
	Timm Baeder, Daniel Plakosh, A. Jiang, Eugene Zelenko,
	Aaron Ballman, Paul Koning, Daniel Lundin, Nikolaos Strimpas,
	JeanHeyd Meneide, Fernando Borretti, Jonathan Protzenko,
	Chris Bazley, Ville Voutilainen, Alex Celeste,
	Jakub Łukasiewicz, Douglas McIlroy, Jason Merrill,
	Xavier Del Campo Romero, Siddhesh Poyarekar, DJ Delorie,
	Carlos O'Donell, Stephen Coady, Robert Seacord

[-- Attachment #1: Type: text/plain, Size: 499 bytes --]

On Tue, Oct 08, 2024 at 08:45:48AM GMT, Jakub Jelinek wrote:
> On Tue, Oct 08, 2024 at 02:09:52AM +0200, Alejandro Colomar wrote:
> > On the other hand, should we provide a version of the operator that is
> > free from pedantic warnings?  A GNU extension?
> 
> No, why?  One can always use (__extension__ _Lengthof (...)).

Just wondering if we should do it for symmetry with __alignof__.  But
yeah, no need.

Cheers,
Alex

> 
> 	Jakub
> 

-- 
<https://www.alejandro-colomar.es/>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 318+ messages in thread

* Re: [PATCH v13 0/4] c: Add __lengthof__ operator
  2024-10-07 17:35     ` [PATCH v13 0/4] " Joseph Myers
  2024-10-08  0:04       ` Alejandro Colomar
@ 2024-10-08  8:25       ` Jakub Łukasiewicz
  2024-10-08  8:33         ` Alejandro Colomar
  1 sibling, 1 reply; 318+ messages in thread
From: Jakub Łukasiewicz @ 2024-10-08  8:25 UTC (permalink / raw)
  To: Joseph Myers, Alejandro Colomar
  Cc: WG14, gcc-patches, Gabriel Ravier, Jakub Jelinek, Kees Cook,
	Qing Zhao, Jens Gustedt, David Brown, Florian Weimer,
	Andreas Schwab, Timm Baeder, Daniel Plakosh, A. Jiang,
	Eugene Zelenko, Paul Koning, Daniel Lundin, Nikolaos Strimpas,
	Fernando Borretti, Jonathan Protzenko, Douglas McIlroy,
	Jason Merrill, Xavier Del Campo Romero, Siddhesh Poyarekar,
	DJ Delorie, Carlos O'Donell, Stephen Coady

I think it would be beneficial to have different syntax/spelling for 
features still in development. That way we, as a committee, can tweak 
it as we please, while mitigating effect on early adopters.

If what ends in final document is exactly the same as in early phrases, 
then great, all users are left to do is simple find and replace.

Warning about using an experimental feature that is prone to changes 
is obviously useful, but it disappears after upgrade to latest 
standard. If there were diverges between early and final versions, 
it would be nice to have warnings about that too.

~ J.Ł.

On 2024-10-07 19:35 CEST, Joseph Myers <josmyers@redhat.com> wrote:
> Patches 1, 2 and 3 are logically nothing to do with this feature.  I'll 
> wait for them to be reviewed so that we only have a single-patch series, 
> before doing final review of the main patch.
>
> Since the feature was accepted as _Lengthof, that's the form that should 
> be added to GCC; no __lengthof__ variant needed.  In general in GCC, 
> although not strictly required by the standard in this case, we use 
> pedwarn_c23 (pass OPT_Wpedantic as the option) to diagnose the use of a 
> new C2Y feature that's not in C23 (if -pedantic with a pre-C2Y standard, 
> or -Wc23-c2y-compat even in C2Y mode), with appropriate testcases to 
> verify this (error with -std=c23 -pedantic-errors, warning with -std=c23 
> -pedantic, no diagnostic with -std=c23 -pedantic-errors 
> -Wno-c23-c2y-compat, no diagnostic with -std=c2y -pedantic-errors, warning 
> with -std=c2y -pedantic-errors -Wc23-c2y-compat).  (pedwarn_c23 handles 
> that logic, you just need the pedwarn_c23 call and the tests for those 
> various cases.)

^ permalink raw reply	[flat|nested] 318+ messages in thread

* Re: [PATCH v13 0/4] c: Add __lengthof__ operator
  2024-10-08  8:25       ` Jakub Łukasiewicz
@ 2024-10-08  8:33         ` Alejandro Colomar
  2024-10-08  8:59           ` Jakub Łukasiewicz
  2024-10-08 13:23           ` Joseph Myers
  0 siblings, 2 replies; 318+ messages in thread
From: Alejandro Colomar @ 2024-10-08  8:33 UTC (permalink / raw)
  To: Jakub Łukasiewicz
  Cc: Joseph Myers, WG14, gcc-patches, Gabriel Ravier, Jakub Jelinek,
	Kees Cook, Qing Zhao, Jens Gustedt, David Brown, Florian Weimer,
	Andreas Schwab, Timm Baeder, Daniel Plakosh, A. Jiang,
	Eugene Zelenko, Paul Koning, Daniel Lundin, Nikolaos Strimpas,
	Fernando Borretti, Jonathan Protzenko, Douglas McIlroy,
	Jason Merrill, Xavier Del Campo Romero, Siddhesh Poyarekar,
	DJ Delorie, Carlos O'Donell, Stephen Coady

[-- Attachment #1: Type: text/plain, Size: 2099 bytes --]

Hi Jakub,

On Tue, Oct 08, 2024 at 10:25:24AM GMT, Jakub Łukasiewicz wrote:
> I think it would be beneficial to have different syntax/spelling for
> features still in development. That way we, as a committee, can tweak it as
> we please, while mitigating effect on early adopters.
> 
> If what ends in final document is exactly the same as in early phrases, then
> great, all users are left to do is simple find and replace.
> 
> Warning about using an experimental feature that is prone to changes is
> obviously useful, but it disappears after upgrade to latest standard. If
> there were diverges between early and final versions, it would be nice to
> have warnings about that too.

How about adding the __lower__ version now as a GNU extension with
compatible semantics, and when it's closer to an ISO C2y release add the
_Upper one?

That gives us more freedom.

Cheers,
Alex

> 
> ~ J.Ł.
> 
> On 2024-10-07 19:35 CEST, Joseph Myers <josmyers@redhat.com> wrote:
> > Patches 1, 2 and 3 are logically nothing to do with this feature.  I'll
> > wait for them to be reviewed so that we only have a single-patch series,
> > before doing final review of the main patch.
> > 
> > Since the feature was accepted as _Lengthof, that's the form that should
> > be added to GCC; no __lengthof__ variant needed.  In general in GCC,
> > although not strictly required by the standard in this case, we use
> > pedwarn_c23 (pass OPT_Wpedantic as the option) to diagnose the use of a
> > new C2Y feature that's not in C23 (if -pedantic with a pre-C2Y standard,
> > or -Wc23-c2y-compat even in C2Y mode), with appropriate testcases to
> > verify this (error with -std=c23 -pedantic-errors, warning with -std=c23
> > -pedantic, no diagnostic with -std=c23 -pedantic-errors
> > -Wno-c23-c2y-compat, no diagnostic with -std=c2y -pedantic-errors,
> > warning with -std=c2y -pedantic-errors -Wc23-c2y-compat).  (pedwarn_c23
> > handles that logic, you just need the pedwarn_c23 call and the tests for
> > those various cases.)

-- 
<https://www.alejandro-colomar.es/>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 318+ messages in thread

* Re: [PATCH v13 0/4] c: Add __lengthof__ operator
  2024-10-08  8:33         ` Alejandro Colomar
@ 2024-10-08  8:59           ` Jakub Łukasiewicz
  2024-10-08 13:23           ` Joseph Myers
  1 sibling, 0 replies; 318+ messages in thread
From: Jakub Łukasiewicz @ 2024-10-08  8:59 UTC (permalink / raw)
  To: Alejandro Colomar
  Cc: Joseph Myers, WG14, gcc-patches, Gabriel Ravier, Jakub Jelinek,
	Kees Cook, Qing Zhao, Jens Gustedt, David Brown, Florian Weimer,
	Andreas Schwab, Timm Baeder, Daniel Plakosh, A. Jiang,
	Eugene Zelenko, Paul Koning, Daniel Lundin, Nikolaos Strimpas,
	Fernando Borretti, Jonathan Protzenko, Douglas McIlroy,
	Jason Merrill, Xavier Del Campo Romero, Siddhesh Poyarekar,
	DJ Delorie, Carlos O'Donell, Stephen Coady

Yup :)
For example that

~ J.Ł.

On 2024-10-08 10:33 CEST, Alejandro Colomar <alx@kernel.org> wrote:
> Hi Jakub,
>
> On Tue, Oct 08, 2024 at 10:25:24AM GMT, Jakub Łukasiewicz wrote:
> > I think it would be beneficial to have different syntax/spelling for
> > features still in development. That way we, as a committee, can tweak it as
> > we please, while mitigating effect on early adopters.
> > 
> > If what ends in final document is exactly the same as in early phrases, then
> > great, all users are left to do is simple find and replace.
> > 
> > Warning about using an experimental feature that is prone to changes is
> > obviously useful, but it disappears after upgrade to latest standard. If
> > there were diverges between early and final versions, it would be nice to
> > have warnings about that too.
>
> How about adding the __lower__ version now as a GNU extension with
> compatible semantics, and when it's closer to an ISO C2y release add the
> _Upper one?
>
> That gives us more freedom.
>
> Cheers,
> Alex
>
> > 
> > ~ J.Ł.
> > 
> > On 2024-10-07 19:35 CEST, Joseph Myers <josmyers@redhat.com> wrote:
> > > Patches 1, 2 and 3 are logically nothing to do with this feature.  I'll
> > > wait for them to be reviewed so that we only have a single-patch series,
> > > before doing final review of the main patch.
> > > 
> > > Since the feature was accepted as _Lengthof, that's the form that should
> > > be added to GCC; no __lengthof__ variant needed.  In general in GCC,
> > > although not strictly required by the standard in this case, we use
> > > pedwarn_c23 (pass OPT_Wpedantic as the option) to diagnose the use of a
> > > new C2Y feature that's not in C23 (if -pedantic with a pre-C2Y standard,
> > > or -Wc23-c2y-compat even in C2Y mode), with appropriate testcases to
> > > verify this (error with -std=c23 -pedantic-errors, warning with -std=c23
> > > -pedantic, no diagnostic with -std=c23 -pedantic-errors
> > > -Wno-c23-c2y-compat, no diagnostic with -std=c2y -pedantic-errors,
> > > warning with -std=c2y -pedantic-errors -Wc23-c2y-compat).  (pedwarn_c23
> > > handles that logic, you just need the pedwarn_c23 call and the tests for
> > > those various cases.)


^ permalink raw reply	[flat|nested] 318+ messages in thread

* [PATCH v14 0/4] c: Add __countof__ operator
  2024-07-28 14:15 ` [RFC v1 0/2] c: Add _Lengthof operator Alejandro Colomar
                     ` (18 preceding siblings ...)
  2024-10-02  9:41   ` [PATCH v13 0/4] c: Add __lengthof__ operator Alejandro Colomar
@ 2024-10-08  9:11   ` Alejandro Colomar
  2024-10-08  9:11     ` [PATCH v14 1/4] contrib/: Add support for Cc: and Link: tags Alejandro Colomar
                       ` (3 more replies)
  2024-10-16 10:13   ` [PATCH v15 0/4] " Alejandro Colomar
                     ` (8 subsequent siblings)
  28 siblings, 4 replies; 318+ messages in thread
From: Alejandro Colomar @ 2024-10-08  9:11 UTC (permalink / raw)
  To: gcc-patches
  Cc: Alejandro Colomar, Gabriel Ravier, Jakub Jelinek, Kees Cook,
	Qing Zhao, Jens Gustedt, David Brown, Florian Weimer,
	Andreas Schwab, Timm Baeder, Daniel Plakosh, A. Jiang,
	Eugene Zelenko, Aaron Ballman, Paul Koning, Daniel Lundin,
	Nikolaos Strimpas, JeanHeyd Meneide, Fernando Borretti,
	Jonathan Protzenko, Chris Bazley, Ville Voutilainen,
	Alex Celeste, Jakub Łukasiewicz, Douglas McIlroy,
	Jason Merrill, Xavier Del Campo Romero, Siddhesh Poyarekar,
	DJ Delorie, Carlos O'Donell, Stephen, Coady, Joseph Myers,
	Martin Uecker, Gustavo A. R. Silva, Patrizia Kaye, Ori Bernstein,
	Robert Seacord

[-- Attachment #1: Type: text/plain, Size: 39522 bytes --]

Hi!

Here's v14 with some changes:

A)  Rename s/__lengthof__/__countof__/  (rationale(s) below).
B)  Remove the concept "top-level array" from the docs (rationale below).

At the bottom of this email is a range diff comparing to v13.

A.1)

WG14 had only weak consensus for prefering lengthof over nelementsof or
countof.  And it didn't really address my concerns of overloading the
term length.  "length" is currently exclusively used in C to refer to
the number of non-zero characters in a string; at least in a consistent
manner.  In uses in the wild, 'len' rarely appears in a variable name
that refers to the number of elements of an array.  In ISO C, one may be
led to think that VLA uses the term length to refer to the number of
elements of the array; but it actually refers to the size[1].  There are
a few residual uses of length to inconsistently refer to the number of
elements of an array, but they are only colloquial uses with no major
relevance.

[1]:  <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3327.pdf>

On the other hand, there's a consistent use of 'n' as a name of a
variable to refer to the *n*umber of elements of an array.

A novel overload of the term length to refer to the number of elements
of an array would be dangerous, as it would naturally promote the use of
'len' as a variable name for holding the number of elements, which would
cause confusion with the length of strings contained in such arrays, and
cause off-by-one bugs, which would in turn result in buffer overflows.

This is a security issue that must be addressed.  lengthof cannot be a
name for this operator.

A.2)

Another argument that was used in favour of length is that other
widely used languages like Python use length to refer to the number of
elements of an array, and for consistency with those languages we should
follow.

That omits the fact that those languages don't use null-terminated
strings, and thus they don't have the security problem that C would have
by overloading length.  In Python, it would seem natural to have length
mean the number of elements of <whatever>, be it number of elements of
an array, or number of elements of a string.  It won't result in
off-by-one bugs and buffer overflows, as would in C.

A.3)

While nelementsof() was considered too long of a name by some, we can
use countof(), which is even shorter than lengthof() (by one byte), and
cannot be confused with anything else that currently exists in the
language.

Also, countof() is consistent with the similar __counted_by() attribute.

B)

C does not have multi-dimensional arrays.  It has a very generic way of
composing aggregate types that allows one to think of multidimensional
arrays, but they're not a distinct concept in the language.  I've
changed the manual to use language that is simpler, and more consistent
with how C really is.


I will present a new paper to WG14 for the next meeting, proposing
countof().

This proposal uses double underscores because C2y is too far, and even
if we used the same name as WG14 wants, we would prefer to have a name
that is under our control, in case WG14 changes anything before the
release of C2y.


Have a lovely day!
Alex


Alejandro Colomar (4):
  contrib/: Add support for Cc: and Link: tags
  gcc/: Rename array_type_nelts() => array_type_nelts_minus_one()
  Merge definitions of array_type_nelts_top()
  c: Add __countof__ operator

 contrib/gcc-changelog/git_commit.py    |   5 +-
 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                        |  32 ++++--
 gcc/c/c-fold.cc                        |   7 +-
 gcc/c/c-parser.cc                      |  62 +++++++---
 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                    |  30 +++++
 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/countof-compile.c | 115 +++++++++++++++++++
 gcc/testsuite/gcc.dg/countof-vla.c     |  46 ++++++++
 gcc/testsuite/gcc.dg/countof.c         | 150 +++++++++++++++++++++++++
 gcc/tree.cc                            |  17 ++-
 gcc/tree.h                             |   3 +-
 29 files changed, 604 insertions(+), 80 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/countof-compile.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-vla.c
 create mode 100644 gcc/testsuite/gcc.dg/countof.c

Range-diff against v13:
1:  d7fca49888a = 1:  d7fca49888a contrib/: Add support for Cc: and Link: tags
2:  e65245ac294 = 2:  e65245ac294 gcc/: Rename array_type_nelts() => array_type_nelts_minus_one()
3:  03de2d67bb1 = 3:  03de2d67bb1 Merge definitions of array_type_nelts_top()
4:  f635871da1f ! 4:  6714852dd93 c: Add __lengthof__ operator
    @@ Metadata
     Author: Alejandro Colomar <alx@kernel.org>
     
      ## Commit message ##
    -    c: Add __lengthof__ operator
    +    c: Add __countof__ operator
     
         This operator is similar to sizeof but can only be applied to an array,
         and returns its number of elements.
    @@ Commit message
     
         gcc/ChangeLog:
     
    -            * doc/extend.texi: Document __lengthof__ operator.
    -            * target.h (enum type_context_kind): Add __lengthof__ operator.
    +            * doc/extend.texi: Document __countof__ operator.
    +            * target.h (enum type_context_kind): Add __countof__ operator.
     
         gcc/c-family/ChangeLog:
     
                 * c-common.h
                 * c-common.def:
    -            * c-common.cc (c_lengthof_type): Add __lengthof__ operator.
    +            * c-common.cc (c_countof_type): Add __countof__ operator.
     
         gcc/c/ChangeLog:
     
                 * c-tree.h
    -            (c_expr_lengthof_expr, c_expr_lengthof_type)
    +            (c_expr_countof_expr, c_expr_countof_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_countof_expression)
    +            (c_parser_sizeof_or_countof_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.
    +            (c_expr_countof_expr, c_expr_countof_type):
    +            Add __countof__operator.
     
         gcc/cp/ChangeLog:
     
    -            * operators.def: Add __lengthof__ operator.
    +            * operators.def: Add __countof__ operator.
     
         gcc/testsuite/ChangeLog:
     
    -            * gcc.dg/lengthof-compile.c
    -            * gcc.dg/lengthof-vla.c
    -            * gcc.dg/lengthof.c: Add tests for __lengthof__ operator.
    +            * gcc.dg/countof-compile.c
    +            * gcc.dg/countof-vla.c
    +            * gcc.dg/countof.c: Add tests for __countof__ operator.
     
         Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3313.pdf>
    +    Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3325.pdf>
    +    Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3369.pdf>
         Link: <https://inbox.sourceware.org/gcc/M8S4oQy--3-2@tutanota.com/T/>
         Link: <https://github.com/llvm/llvm-project/issues/102836>
         Cc: Joseph Myers <josmyers@redhat.com>
    @@ gcc/c-family/c-common.cc: const struct c_common_resword c_common_reswords[] =
        { "__inline",		RID_INLINE,	0 },
        { "__inline__",	RID_INLINE,	0 },
        { "__label__",	RID_LABEL,	0 },
    -+  { "__lengthof__",	RID_LENGTHOF,	0 },
    ++  { "__countof__",	RID_COUNTOF,	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 the number of elements of an array.  */
     +
     +tree
    -+c_lengthof_type (location_t loc, tree type)
    ++c_countof_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);
    ++      error_at (loc, "invalid application of %<countof%> to type %qT", type);
     +      return error_mark_node;
     +    }
     +  if (!COMPLETE_TYPE_P (type))
     +    {
     +      error_at (loc,
    -+		"invalid application of %<lengthof%> to incomplete type %qT",
    ++		"invalid application of %<countof%> to incomplete 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 'lengthof' expression.  */
    -+DEFTREECODE (LENGTHOF_EXPR, "lengthof_expr", tcc_expression, 1)
    ++/* Represents a 'countof' expression.  */
    ++DEFTREECODE (COUNTOF_EXPR, "countof_expr", tcc_expression, 1)
     +
      /* Represents a 'sizeof' expression during C++ template expansion,
         or for the purpose of -Wsizeof-pointer-memaccess warning.  */
    @@ gcc/c-family/c-common.h: enum rid
      
        /* C extensions */
        RID_ASM,       RID_TYPEOF,   RID_TYPEOF_UNQUAL, RID_ALIGNOF,  RID_ATTRIBUTE,
    -+  RID_LENGTHOF,
    ++  RID_COUNTOF,
        RID_VA_ARG,
        RID_EXTENSION, RID_IMAGPART, RID_REALPART, RID_LABEL,    RID_CHOOSE_EXPR,
        RID_TYPES_COMPATIBLE_P,      RID_BUILTIN_COMPLEX,	   RID_BUILTIN_SHUFFLE,
    @@ gcc/c-family/c-common.h: extern tree c_common_truthvalue_conversion (location_t,
      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);
    ++extern tree c_countof_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);
    @@ gcc/c/c-decl.cc: start_struct (location_t loc, enum tree_code code, tree name,
           sizeof anyhow.  */
     -  if (warn_cxx_compat && (in_sizeof || in_typeof || in_alignof))
     +  if (warn_cxx_compat
    -+      && (in_sizeof || in_typeof || in_alignof || in_lengthof))
    ++      && (in_sizeof || in_typeof || in_alignof || in_countof))
          warning_at (loc, OPT_Wc___compat,
      		"defining type in %qs expression is invalid in C++",
      		(in_sizeof
    @@ gcc/c/c-decl.cc: start_struct (location_t loc, enum tree_code code, tree name,
     +		    ? "typeof"
     +		    : (in_alignof
     +		       ? "alignof"
    -+		       : "lengthof"))));
    ++		       : "countof"))));
      
        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 att
            if (warn_cxx_compat
      	  && struct_parse_info != NULL
     -	  && !in_sizeof && !in_typeof && !in_alignof)
    -+	  && !in_sizeof && !in_typeof && !in_alignof && !in_lengthof)
    ++	  && !in_sizeof && !in_typeof && !in_alignof && !in_countof)
      	struct_parse_info->struct_types.safe_push (t);
           }
      
    @@ gcc/c/c-decl.cc: start_enum (location_t loc, struct c_enum_contents *the_enum, t
           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))
    ++      && (in_sizeof || in_typeof || in_alignof || in_countof))
          warning_at (loc, OPT_Wc___compat,
      		"defining type in %qs expression is invalid in C++",
      		(in_sizeof
    @@ gcc/c/c-decl.cc: start_enum (location_t loc, struct c_enum_contents *the_enum, t
     +		    ? "typeof"
     +		    : (in_alignof
     +		       ? "alignof"
    -+		       : "lengthof"))));
    ++		       : "countof"))));
      
        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)
        if (warn_cxx_compat
            && struct_parse_info != NULL
     -      && !in_sizeof && !in_typeof && !in_alignof)
    -+      && !in_sizeof && !in_typeof && !in_alignof && !in_lengthof)
    ++      && !in_sizeof && !in_typeof && !in_alignof && !in_countof)
          struct_parse_info->struct_types.safe_push (enumtype);
      
        /* Check for consistency with previous definition */
    @@ gcc/c/c-parser.cc: along with GCC; see the file COPYING3.  If not see
     +\f
     +#define c_parser_sizeof_expression(parser)                                    \
     +(                                                                             \
    -+  c_parser_sizeof_or_lengthof_expression (parser, RID_SIZEOF)                 \
    ++  c_parser_sizeof_or_countof_expression (parser, RID_SIZEOF)                  \
     +)
      
    -+#define c_parser_lengthof_expression(parser)                                  \
    ++#define c_parser_countof_expression(parser)                                   \
     +(                                                                             \
    -+  c_parser_sizeof_or_lengthof_expression (parser, RID_LENGTHOF)               \
    ++  c_parser_sizeof_or_countof_expression (parser, RID_COUNTOF)                 \
     +)
     +\f
      /* We need to walk over decls with incomplete struct/union/enum types
    @@ gcc/c/c-parser.cc: static struct c_expr c_parser_binary_expression (c_parser *,
      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_sizeof_or_countof_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 *,
    @@ gcc/c/c-parser.cc: 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_COUNTOF:
    ++	  return c_parser_countof_expression (parser);
      	case RID_SIZEOF:
      	  return c_parser_sizeof_expression (parser);
      	case RID_ALIGNOF:
    @@ gcc/c/c-parser.cc: c_parser_unary_expression (c_parser *parser)
      
      static struct c_expr
     -c_parser_sizeof_expression (c_parser *parser)
    -+c_parser_sizeof_or_lengthof_expression (c_parser *parser, enum rid rid)
    ++c_parser_sizeof_or_countof_expression (c_parser *parser, enum rid rid)
      {
    -+  const char *op_name = (rid == RID_LENGTHOF) ? "lengthof" : "sizeof";
    ++  const char *op_name = (rid == RID_COUNTOF) ? "countof" : "sizeof";
        struct c_expr expr;
        struct c_expr result;
        location_t expr_loc;
    @@ 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++;
    ++  if (rid == RID_COUNTOF)
    ++    in_countof++;
     +  else
     +    in_sizeof++;
        if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)
    @@ 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--;
    ++	  if (rid == RID_COUNTOF)
    ++	    in_countof--;
     +	  else
     +	    in_sizeof--;
      	  ret.set_error ();
    @@ gcc/c/c-parser.cc: c_parser_sizeof_expression (c_parser *parser)
            c_inhibit_evaluation_warnings--;
     -      in_sizeof--;
     -      result = c_expr_sizeof_type (expr_loc, type_name);
    -+      if (rid == RID_LENGTHOF)
    ++      if (rid == RID_COUNTOF)
     +	{
    -+	  in_lengthof--;
    -+	  result = c_expr_lengthof_type (expr_loc, type_name);
    ++	  in_countof--;
    ++	  result = c_expr_countof_type (expr_loc, type_name);
     +	}
     +      else
     +	{
    @@ gcc/c/c-parser.cc: c_parser_sizeof_expression (c_parser *parser)
     +    Xof_expr:
            c_inhibit_evaluation_warnings--;
     -      in_sizeof--;
    -+      if (rid == RID_LENGTHOF)
    -+	in_lengthof--;
    ++      if (rid == RID_COUNTOF)
    ++	in_countof--;
     +      else
     +	in_sizeof--;
            mark_exp_read (expr.value);
    @@ gcc/c/c-parser.cc: c_parser_sizeof_expression (c_parser *parser)
     -	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);
    ++      if (rid == RID_COUNTOF)
    ++	result = c_expr_countof_expr (expr_loc, expr);
     +      else
     +	result = c_expr_sizeof_expr (expr_loc, expr);
          }
    @@ gcc/c/c-tree.h: 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_countof;
      extern int in_typeof;
      extern bool c_in_omp_for;
      extern bool c_omp_array_section_p;
    @@ gcc/c/c-tree.h: 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 c_expr_countof_expr (location_t, struct c_expr);
    ++extern struct c_expr c_expr_countof_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,
    @@ gcc/c/c-typeck.cc: 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 "countof".  */
    ++int in_countof;
     +
      /* 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 *
        if (TREE_CODE (ref) == FUNCTION_DECL && !in_alignof)
          {
     -      if (!in_sizeof && !in_typeof)
    -+      if (!in_sizeof && !in_typeof && !in_lengthof)
    ++      if (!in_sizeof && !in_typeof && !in_countof)
      	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).  */
    ++  /* The level seen at (in_sizeof + in_typeof + in_countof).  */
        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->level = in_sizeof + in_typeof + in_countof;
        t->next = maybe_used_decls;
        maybe_used_decls = t;
      }
    @@ gcc/c/c-typeck.cc: void
      {
        struct maybe_used_decl *p = maybe_used_decls;
     -  int cur_level = in_sizeof + in_typeof;
    -+  int cur_level = in_sizeof + in_typeof + in_lengthof;
    ++  int cur_level = in_sizeof + in_typeof + in_countof;
        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 var;
     +}
     +
    -+/* Return the result of lengthof applied to EXPR.  */
    ++/* Return the result of countof applied to EXPR.  */
     +
     +struct c_expr
    -+c_expr_lengthof_expr (location_t loc, struct c_expr expr)
    ++c_expr_countof_expr (location_t loc, struct c_expr expr)
     +{
     +  struct c_expr ret;
     +  if (expr.value == error_mark_node)
    @@ gcc/c/c-typeck.cc: c_expr_sizeof_type (location_t loc, struct c_type_name *t)
     +
     +      tree folded_expr = c_fully_fold (expr.value, require_constant_value,
     +				       &expr_const_operands);
    -+      ret.value = c_lengthof_type (loc, TREE_TYPE (folded_expr));
    ++      ret.value = c_countof_type (loc, TREE_TYPE (folded_expr));
     +      c_last_sizeof_arg = expr.value;
     +      c_last_sizeof_loc = loc;
    -+      ret.original_code = LENGTHOF_EXPR;
    ++      ret.original_code = COUNTOF_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.  */
    ++	  /* countof 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
    -+   name passed to lengthof (rather than the type itself).  LOC is the
    ++/* Return the result of countof applied to T, a structure for the type
    ++   name passed to countof (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)
    ++c_expr_countof_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);
    ++  ret.value = c_countof_type (loc, type);
     +  c_last_sizeof_arg = type;
     +  c_last_sizeof_loc = loc;
    -+  ret.original_code = LENGTHOF_EXPR;
    ++  ret.original_code = COUNTOF_EXPR;
     +  ret.original_type = NULL;
     +  ret.m_decimal = 0;
     +  if (type == error_mark_node)
    @@ 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 countof 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 countof 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 ("__countof__", COUNTOF_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/doc/extend.texi: If the operand of the @code{__alignof__} expression is a fu
      the expression evaluates to the alignment of the function which may
      be specified by attribute @code{aligned} (@pxref{Common Function Attributes}).
      
    -+@node lengthof
    ++@node countof
     +@section Determining the Number of Elements of Arrays
    -+@cindex lengthof
    ++@cindex countof
     +@cindex number of elements
     +
    -+The keyword @code{__lengthof__} determines the length of an array operand,
    ++The keyword @code{__countof__} 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
    @@ gcc/doc/extend.texi: If the operand of the @code{__alignof__} expression is a fu
     +
     +@smallexample
     +int a[n];
    -+__lengthof__ (a);  // returns n
    -+__lengthof__ (int [7][3]);  // returns 7
    ++__countof__ (a);  // returns n
    ++__countof__ (int [7][3]);  // returns 7
     +@end smallexample
     +
     +The result of this operator is an integer constant expression,
    -+unless the top-level array is a variable-length array.
    ++unless the array has a variable number of elements.
     +The operand is only evaluated
    -+if the top-level array is a variable-length array.
    ++if the array has a variable number of elements.
     +For example:
     +
     +@smallexample
    -+__lengthof__ (int [7][n++]);  // integer constant expression
    -+__lengthof__ (int [n++][7]);  // run-time value; n++ is evaluated
    ++__countof__ (int [7][n++]);  // integer constant expression
    ++__countof__ (int [n++][7]);  // run-time value; n++ is evaluated
     +@end smallexample
     +
      @node Inline
    @@ gcc/target.h: enum type_context_kind {
        TCTX_ALIGNOF,
      
     +  /* Directly measuring the number of elements of array T.  */
    -+  TCTX_LENGTHOF,
    ++  TCTX_COUNTOF,
     +
        /* Creating objects of type T with static storage duration.  */
        TCTX_STATIC_STORAGE,
      
     
    - ## gcc/testsuite/gcc.dg/nelementsof-compile.c (new) ##
    + ## gcc/testsuite/gcc.dg/countof-compile.c (new) ##
     @@
     +/* { dg-do compile } */
     +/* { dg-options "-Wno-declaration-after-statement -Wno-pedantic -Wno-vla" } */
    @@ gcc/testsuite/gcc.dg/nelementsof-compile.c (new)
     +static int w[] = {1, 2, 3};
     +
     +static int z[0];
    -+static int y[__lengthof__(z)];
    ++static int y[__countof__(z)];
     +
     +void
     +automatic(void)
     +{
    -+  __lengthof__ (w);
    ++  __countof__ (w);
     +}
     +
     +void
     +incomplete (int p[])
     +{
    -+  __lengthof__ (x);  /* { dg-error "incomplete" } */
    ++  __countof__ (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" } */
    ++  __countof__ (p);  /* { dg-error "invalid" } */
     +}
     +
     +void
    @@ gcc/testsuite/gcc.dg/nelementsof-compile.c (new)
     +    int fam[];
     +  } s;
     +
    -+  __lengthof__ (s.fam); /* { dg-error "incomplete" } */
    ++  __countof__ (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 fix_fix (int i, char (*a)[3][5], int (*x)[__countof__ (*a)]);
    ++void fix_var (int i, char (*a)[3][i], int (*x)[__countof__ (*a)]);
    ++void fix_uns (int i, char (*a)[3][*], int (*x)[__countof__ (*a)]);
     +
     +void
     +func (void)
    @@ gcc/testsuite/gcc.dg/nelementsof-compile.c (new)
     +    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" } */
    ++  __countof__ (x); /* { dg-error "invalid" } */
    ++  __countof__ (int); /* { dg-error "invalid" } */
    ++  __countof__ (s); /* { dg-error "invalid" } */
    ++  __countof__ (struct s); /* { dg-error "invalid" } */
    ++  __countof__ (&x); /* { dg-error "invalid" } */
    ++  __countof__ (p); /* { dg-error "invalid" } */
    ++  __countof__ (int *); /* { dg-error "invalid" } */
    ++  __countof__ (&s.x); /* { dg-error "invalid" } */
    ++  __countof__ (int (*)[3]); /* { dg-error "invalid" } */
     +}
     +
     +static int f1();
    @@ gcc/testsuite/gcc.dg/nelementsof-compile.c (new)
     +{
     +  int b[n][n];
     +
    -+  __lengthof__ (a[f1()]);
    -+  __lengthof__ (b[f2()]);
    ++  __countof__ (a[f1()]);
    ++  __countof__ (b[f2()]);
     +}
     +
     +void
     +no_parens(void)
     +{
    -+  __lengthof__ a;
    -+  __lengthof__ *a;
    -+  __lengthof__ (int [3]) {};
    ++  __countof__ a;
    ++  __countof__ *a;
    ++  __countof__ (int [3]) {};
     +
    -+  __lengthof__ int [3]; /* { dg-error "expected expression before" } */
    ++  __countof__ int [3]; /* { dg-error "expected expression before" } */
     +}
     +
     +void
    @@ gcc/testsuite/gcc.dg/nelementsof-compile.c (new)
     +{
     +  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);
    ++  _Static_assert (__countof__ (int [3][n]) == 3);
    ++  _Static_assert (__countof__ (int [n][3]) == 7); /* { dg-error "not constant" } */
    ++  _Static_assert (__countof__ (int [0][3]) == 0);
    ++  _Static_assert (__countof__ (int [0]) == 0);
     +
    -+  /* FIXME: lengthof(int [0][n]) should result in a constant expression.  */
    -+  _Static_assert (__lengthof__ (int [0][n]) == 0); /* { dg-error "not constant" } */
    ++  /* FIXME: countof(int [0][n]) should result in a constant expression.  */
    ++  _Static_assert (__countof__ (int [0][n]) == 0); /* { dg-error "not constant" } */
     +}
     
    - ## gcc/testsuite/gcc.dg/nelementsof-vla.c (new) ##
    + ## gcc/testsuite/gcc.dg/countof-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)]);
    ++	      int (*x)[__countof__ (*a)]);
     +void fix_var (int i,
     +	      char (*a)[3][i], /* dg-warn "variable" */
    -+	      int (*x)[__lengthof__ (*a)]);
    ++	      int (*x)[__countof__ (*a)]);
     +void fix_uns (int i,
     +	      char (*a)[3][*],
    -+	      int (*x)[__lengthof__ (*a)]);
    ++	      int (*x)[__countof__ (*a)]);
     +
     +void zro_fix (int i,
     +	      char (*a)[0][5],
    -+	      int (*x)[__lengthof__ (*a)]);
    ++	      int (*x)[__countof__ (*a)]);
     +void zro_var (int i,
     +	      char (*a)[0][i], /* dg-warn "variable" */
    -+	      int (*x)[__lengthof__ (*a)]);
    ++	      int (*x)[__countof__ (*a)]);
     +void zro_uns (int i,
     +	      char (*a)[0][*],
    -+	      int (*x)[__lengthof__ (*a)]);
    ++	      int (*x)[__countof__ (*a)]);
     +
     +void var_fix (int i,
     +	      char (*a)[i][5], /* dg-warn "variable" */
    -+	      int (*x)[__lengthof__ (*a)]); /* dg-warn "variable" */
    ++	      int (*x)[__countof__ (*a)]); /* dg-warn "variable" */
     +void var_var (int i,
     +	      char (*a)[i][i], /* dg-warn "variable" */
    -+	      int (*x)[__lengthof__ (*a)]); /* dg-warn "variable" */
    ++	      int (*x)[__countof__ (*a)]); /* dg-warn "variable" */
     +void var_uns (int i,
     +	      char (*a)[i][*], /* dg-warn "variable" */
    -+	      int (*x)[__lengthof__ (*a)]); /* dg-warn "variable" */
    ++	      int (*x)[__countof__ (*a)]); /* dg-warn "variable" */
     +
     +void uns_fix (int i,
     +	      char (*a)[*][5],
    -+	      int (*x)[__lengthof__ (*a)]);
    ++	      int (*x)[__countof__ (*a)]);
     +void uns_var (int i,
     +	      char (*a)[*][i], /* dg-warn "variable" */
    -+	      int (*x)[__lengthof__ (*a)]);
    ++	      int (*x)[__countof__ (*a)]);
     +void uns_uns (int i,
     +	      char (*a)[*][*],
    -+	      int (*x)[__lengthof__ (*a)]);
    ++	      int (*x)[__countof__ (*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)];
    ++//static int y2[__countof__(z2)];
     
    - ## gcc/testsuite/gcc.dg/nelementsof.c (new) ##
    + ## gcc/testsuite/gcc.dg/countof.c (new) ##
     @@
     +/* { dg-do run } */
     +/* { dg-options "-Wno-declaration-after-statement -Wno-pedantic -Wno-vla" } */
    @@ gcc/testsuite/gcc.dg/nelementsof.c (new)
     +{
     +  short a[7];
     +
    -+  static_assert (__lengthof__ (a) == 7);
    -+  static_assert (__lengthof__ (long [0]) == 0);
    -+  static_assert (__lengthof__ (unsigned [99]) == 99);
    ++  static_assert (__countof__ (a) == 7);
    ++  static_assert (__countof__ (long [0]) == 0);
    ++  static_assert (__countof__ (unsigned [99]) == 99);
     +}
     +
     +void
    @@ gcc/testsuite/gcc.dg/nelementsof.c (new)
     +  int a[] = {1, 2, 3};
     +  int z[] = {};
     +
    -+  static_assert (__lengthof__ (a) == 3);
    -+  static_assert (__lengthof__ (z) == 0);
    ++  static_assert (__countof__ (a) == 3);
    ++  static_assert (__countof__ (z) == 0);
     +}
     +
     +void
    @@ gcc/testsuite/gcc.dg/nelementsof.c (new)
     +  unsigned n;
     +
     +  n = 99;
    -+  assert (__lengthof__ (short [n - 10]) == 99 - 10);
    ++  assert (__countof__ (short [n - 10]) == 99 - 10);
     +
     +  int v[n / 2];
    -+  assert (__lengthof__ (v) == 99 / 2);
    ++  assert (__countof__ (v) == 99 / 2);
     +
     +  n = 0;
     +  int z[n];
    -+  assert (__lengthof__ (z) == 0);
    ++  assert (__countof__ (z) == 0);
     +}
     +
     +void
    @@ gcc/testsuite/gcc.dg/nelementsof.c (new)
     +    int a[8];
     +  } s;
     +
    -+  static_assert (__lengthof__ (s.a) == 8);
    ++  static_assert (__countof__ (s.a) == 8);
     +}
     +
     +void
    @@ gcc/testsuite/gcc.dg/nelementsof.c (new)
     +  int i;
     +
     +  i = 7;
    -+  assert (__lengthof__ (struct {int x;}[i++]) == 7);
    ++  assert (__countof__ (struct {int x;}[i++]) == 7);
     +  assert (i == 7 + 1);
     +
     +  int v[i];
     +  int (*p)[i];
     +  p = &v;
    -+  assert (__lengthof__ (*p++) == i);
    ++  assert (__countof__ (*p++) == i);
     +  assert (p - 1 == &v);
     +}
     +
    @@ gcc/testsuite/gcc.dg/nelementsof.c (new)
     +  int i;
     +
     +  i = 3;
    -+  static_assert (__lengthof__ (struct {int x[i++];}[3]) == 3);
    ++  static_assert (__countof__ (struct {int x[i++];}[3]) == 3);
     +  assert (i == 3);
     +}
     +
    @@ gcc/testsuite/gcc.dg/nelementsof.c (new)
     +array_noeval (void)
     +{
     +  long a[5];
    -+  long (*p)[__lengthof__ (a)];
    ++  long (*p)[__countof__ (a)];
     +
     +  p = &a;
    -+  static_assert (__lengthof__ (*p++) == 5);
    ++  static_assert (__countof__ (*p++) == 5);
     +  assert (p == &a);
     +}
     +
    @@ gcc/testsuite/gcc.dg/nelementsof.c (new)
     +{
     +  int i;
     +
    -+  static_assert (__lengthof__ (int [0][4]) == 0);
    ++  static_assert (__countof__ (int [0][4]) == 0);
     +  i = 3;
    -+  assert (__lengthof__ (int [0][i]) == 0);
    ++  assert (__countof__ (int [0][i]) == 0);
     +}
     +
     +void
    @@ gcc/testsuite/gcc.dg/nelementsof.c (new)
     +{
     +  int i;
     +
    -+  static_assert (__lengthof__ (int [7][4]) == 7);
    ++  static_assert (__countof__ (int [7][4]) == 7);
     +  i = 3;
    -+  static_assert (__lengthof__ (int [7][i]) == 7);
    ++  static_assert (__countof__ (int [7][i]) == 7);
     +}
     +
     +void
    @@ gcc/testsuite/gcc.dg/nelementsof.c (new)
     +  int i, j;
     +
     +  i = 7;
    -+  assert (__lengthof__ (int [i++][4]) == 7);
    ++  assert (__countof__ (int [i++][4]) == 7);
     +  assert (i == 7 + 1);
     +
     +  i = 9;
     +  j = 3;
    -+  assert (__lengthof__ (int [i++][j]) == 9);
    ++  assert (__countof__ (int [i++][j]) == 9);
     +  assert (i == 9 + 1);
     +}
     +
    @@ gcc/testsuite/gcc.dg/nelementsof.c (new)
     +  int a[7];
     +  int v[n];
     +
    -+  static_assert (__lengthof__ a == 7); 
    -+  assert (__lengthof__ v == 3); 
    ++  static_assert (__countof__ a == 7); 
    ++  assert (__countof__ v == 3); 
     +}
     +
     +int

-- 
2.45.2


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 318+ messages in thread

* [PATCH v14 1/4] contrib/: Add support for Cc: and Link: tags
  2024-10-08  9:11   ` [PATCH v14 0/4] c: Add __countof__ operator Alejandro Colomar
@ 2024-10-08  9:11     ` Alejandro Colomar
  2024-10-08  9:11     ` [PATCH v14 2/4] gcc/: Rename array_type_nelts() => array_type_nelts_minus_one() Alejandro Colomar
                       ` (2 subsequent siblings)
  3 siblings, 0 replies; 318+ messages in thread
From: Alejandro Colomar @ 2024-10-08  9:11 UTC (permalink / raw)
  To: gcc-patches
  Cc: Alejandro Colomar, Gabriel Ravier, Jakub Jelinek, Kees Cook,
	Qing Zhao, Jens Gustedt, David Brown, Florian Weimer,
	Andreas Schwab, Timm Baeder, Daniel Plakosh, A. Jiang,
	Eugene Zelenko, Aaron Ballman, Paul Koning, Daniel Lundin,
	Nikolaos Strimpas, JeanHeyd Meneide, Fernando Borretti,
	Jonathan Protzenko, Chris Bazley, Ville Voutilainen,
	Alex Celeste, Jakub Łukasiewicz, Douglas McIlroy,
	Jason Merrill, Xavier Del Campo Romero, Siddhesh Poyarekar,
	DJ Delorie, Carlos O'Donell, Stephen, Coady, Joseph Myers,
	Martin Uecker, Gustavo A. R. Silva, Patrizia Kaye, Ori Bernstein,
	Robert Seacord

[-- Attachment #1: Type: text/plain, Size: 1258 bytes --]

contrib/ChangeLog:

	* gcc-changelog/git_commit.py (GitCommit):
	Add support for 'Cc: ' and 'Link: ' tags.

Cc: Jason Merrill <jason@redhat.com>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
---
 contrib/gcc-changelog/git_commit.py | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/contrib/gcc-changelog/git_commit.py b/contrib/gcc-changelog/git_commit.py
index 87ecb9e1a17..64fb986b74c 100755
--- a/contrib/gcc-changelog/git_commit.py
+++ b/contrib/gcc-changelog/git_commit.py
@@ -182,7 +182,8 @@ CO_AUTHORED_BY_PREFIX = 'co-authored-by: '
 
 REVIEW_PREFIXES = ('reviewed-by: ', 'reviewed-on: ', 'signed-off-by: ',
                    'acked-by: ', 'tested-by: ', 'reported-by: ',
-                   'suggested-by: ')
+                   'suggested-by: ', 'cc: ')
+LINK_PREFIXES = ('link: ')
 DATE_FORMAT = '%Y-%m-%d'
 
 
@@ -524,6 +525,8 @@ class GitCommit:
                     continue
                 elif lowered_line.startswith(REVIEW_PREFIXES):
                     continue
+                elif lowered_line.startswith(LINK_PREFIXES):
+                    continue
                 else:
                     m = cherry_pick_regex.search(line)
                     if m:
-- 
2.45.2


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 318+ messages in thread

* [PATCH v14 2/4] gcc/: Rename array_type_nelts() => array_type_nelts_minus_one()
  2024-10-08  9:11   ` [PATCH v14 0/4] c: Add __countof__ operator Alejandro Colomar
  2024-10-08  9:11     ` [PATCH v14 1/4] contrib/: Add support for Cc: and Link: tags Alejandro Colomar
@ 2024-10-08  9:11     ` Alejandro Colomar
  2024-10-08  9:11     ` [PATCH v14 3/4] Merge definitions of array_type_nelts_top() Alejandro Colomar
  2024-10-08  9:11     ` [PATCH v14 4/4] c: Add __countof__ operator Alejandro Colomar
  3 siblings, 0 replies; 318+ messages in thread
From: Alejandro Colomar @ 2024-10-08  9:11 UTC (permalink / raw)
  To: gcc-patches
  Cc: Alejandro Colomar, Gabriel Ravier, Jakub Jelinek, Kees Cook,
	Qing Zhao, Jens Gustedt, David Brown, Florian Weimer,
	Andreas Schwab, Timm Baeder, Daniel Plakosh, A. Jiang,
	Eugene Zelenko, Aaron Ballman, Paul Koning, Daniel Lundin,
	Nikolaos Strimpas, JeanHeyd Meneide, Fernando Borretti,
	Jonathan Protzenko, Chris Bazley, Ville Voutilainen,
	Alex Celeste, Jakub Łukasiewicz, Douglas McIlroy,
	Jason Merrill, Xavier Del Campo Romero, Siddhesh Poyarekar,
	DJ Delorie, Carlos O'Donell, Stephen, Coady, Joseph Myers,
	Martin Uecker, Gustavo A. R. Silva, Patrizia Kaye, Ori Bernstein,
	Robert Seacord, Richard Biener

[-- Attachment #1: Type: text/plain, Size: 12749 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>

gcc/ChangeLog:

	* tree.cc (array_type_nelts, array_type_nelts_minus_one)
	* tree.h (array_type_nelts, array_type_nelts_minus_one)
	* expr.cc (count_type_elements)
	* config/aarch64/aarch64.cc
	(pure_scalable_type_info::analyze_array)
	* config/i386/i386.cc (ix86_canonical_va_list_type):
	Rename array_type_nelts() => array_type_nelts_minus_one()
	The old name was misleading.

gcc/c/ChangeLog:

	* c-decl.cc (one_element_array_type_p, get_parm_array_spec)
	* c-fold.cc (c_fold_array_ref):
	Rename array_type_nelts() => array_type_nelts_minus_one()

gcc/cp/ChangeLog:

	* decl.cc (reshape_init_array)
	* init.cc
	(build_zero_init_1)
	(build_value_init_noctor)
	(build_vec_init)
	(build_delete)
	* lambda.cc (add_capture)
	* tree.cc (array_type_nelts_top):
	Rename array_type_nelts() => array_type_nelts_minus_one()

gcc/fortran/ChangeLog:

	* trans-array.cc (structure_alloc_comps)
	* trans-openmp.cc
	(gfc_walk_alloc_comps)
	(gfc_omp_clause_linear_ctor):
	Rename array_type_nelts() => array_type_nelts_minus_one()

gcc/rust/ChangeLog:

	* backend/rust-tree.cc (array_type_nelts_top):
	Rename array_type_nelts() => array_type_nelts_minus_one()

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>
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 aa7f69d1b7b..c73d3107efb 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -5358,7 +5358,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]".  */
@@ -6306,15 +6306,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 27e24ba70ab..21606701725 100644
--- a/gcc/config/aarch64/aarch64.cc
+++ b/gcc/config/aarch64/aarch64.cc
@@ -1084,7 +1084,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 546c964d2a4..c6407843fc5 100644
--- a/gcc/config/i386/i386.cc
+++ b/gcc/config/i386/i386.cc
@@ -24393,7 +24393,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 6458e96bded..98133894c48 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -6908,7 +6908,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 320be8b17a1..803da754be1 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 8c35926436d..22ac3c1a5f3 100644
--- a/gcc/fortran/trans-array.cc
+++ b/gcc/fortran/trans-array.cc
@@ -9640,7 +9640,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 b14cfbe7929..7439777f307 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;
 
@@ -14789,7 +14789,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 93aa7d22d6f..4e29544a36c 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] 318+ messages in thread

* [PATCH v14 3/4] Merge definitions of array_type_nelts_top()
  2024-10-08  9:11   ` [PATCH v14 0/4] c: Add __countof__ operator Alejandro Colomar
  2024-10-08  9:11     ` [PATCH v14 1/4] contrib/: Add support for Cc: and Link: tags Alejandro Colomar
  2024-10-08  9:11     ` [PATCH v14 2/4] gcc/: Rename array_type_nelts() => array_type_nelts_minus_one() Alejandro Colomar
@ 2024-10-08  9:11     ` Alejandro Colomar
  2024-10-08  9:11     ` [PATCH v14 4/4] c: Add __countof__ operator Alejandro Colomar
  3 siblings, 0 replies; 318+ messages in thread
From: Alejandro Colomar @ 2024-10-08  9:11 UTC (permalink / raw)
  To: gcc-patches
  Cc: Alejandro Colomar, Gabriel Ravier, Jakub Jelinek, Kees Cook,
	Qing Zhao, Jens Gustedt, David Brown, Florian Weimer,
	Andreas Schwab, Timm Baeder, Daniel Plakosh, A. Jiang,
	Eugene Zelenko, Aaron Ballman, Paul Koning, Daniel Lundin,
	Nikolaos Strimpas, JeanHeyd Meneide, Fernando Borretti,
	Jonathan Protzenko, Chris Bazley, Ville Voutilainen,
	Alex Celeste, Jakub Łukasiewicz, Douglas McIlroy,
	Jason Merrill, Xavier Del Campo Romero, Siddhesh Poyarekar,
	DJ Delorie, Carlos O'Donell, Stephen, Coady, Joseph Myers,
	Martin Uecker, Gustavo A. R. Silva, Patrizia Kaye, Ori Bernstein,
	Robert Seacord

[-- Attachment #1: Type: text/plain, Size: 4880 bytes --]

There were two identical definitions, and none of them are available
where they are needed for implementing __nelementsof__.  Merge them, and
provide the single definition in gcc/tree.{h,cc}, where it's available
for __nelementsof__, 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 2eeb5e3e8b1..6913175c3ce 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -8108,7 +8108,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 7439777f307..d0a7156d982 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 4e29544a36c..372f4dd71da 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] 318+ messages in thread

* [PATCH v14 4/4] c: Add __countof__ operator
  2024-10-08  9:11   ` [PATCH v14 0/4] c: Add __countof__ operator Alejandro Colomar
                       ` (2 preceding siblings ...)
  2024-10-08  9:11     ` [PATCH v14 3/4] Merge definitions of array_type_nelts_top() Alejandro Colomar
@ 2024-10-08  9:11     ` Alejandro Colomar
  3 siblings, 0 replies; 318+ messages in thread
From: Alejandro Colomar @ 2024-10-08  9:11 UTC (permalink / raw)
  To: gcc-patches
  Cc: Alejandro Colomar, Gabriel Ravier, Jakub Jelinek, Kees Cook,
	Qing Zhao, Jens Gustedt, David Brown, Florian Weimer,
	Andreas Schwab, Timm Baeder, Daniel Plakosh, A. Jiang,
	Eugene Zelenko, Aaron Ballman, Paul Koning, Daniel Lundin,
	Nikolaos Strimpas, JeanHeyd Meneide, Fernando Borretti,
	Jonathan Protzenko, Chris Bazley, Ville Voutilainen,
	Alex Celeste, Jakub Łukasiewicz, Douglas McIlroy,
	Jason Merrill, Xavier Del Campo Romero, Siddhesh Poyarekar,
	DJ Delorie, Carlos O'Donell, Stephen, Coady, Joseph Myers,
	Martin Uecker, Gustavo A. R. Silva, Patrizia Kaye, Ori Bernstein,
	Robert Seacord

[-- Attachment #1: Type: text/plain, Size: 30448 bytes --]

This operator is similar to sizeof but can only be applied to an array,
and returns its number of elements.

FUTURE DIRECTIONS:

-  We should make it work with array parameters to functions,
   and somehow magically return the number of elements of the array,
   regardless of it being really a pointer.

-  Fix support for [0].

gcc/ChangeLog:

	* doc/extend.texi: Document __countof__ operator.
	* target.h (enum type_context_kind): Add __countof__ operator.

gcc/c-family/ChangeLog:

	* c-common.h
	* c-common.def:
	* c-common.cc (c_countof_type): Add __countof__ operator.

gcc/c/ChangeLog:

	* c-tree.h
	(c_expr_countof_expr, c_expr_countof_type)
	* c-decl.cc
	(start_struct, finish_struct)
	(start_enum, finish_enum)
	* c-parser.cc
	(c_parser_sizeof_expression)
	(c_parser_countof_expression)
	(c_parser_sizeof_or_countof_expression)
	(c_parser_unary_expression)
	* c-typeck.cc
	(build_external_ref)
	(record_maybe_used_decl, pop_maybe_used)
	(is_top_array_vla)
	(c_expr_countof_expr, c_expr_countof_type):
	Add __countof__operator.

gcc/cp/ChangeLog:

	* operators.def: Add __countof__ operator.

gcc/testsuite/ChangeLog:

	* gcc.dg/countof-compile.c
	* gcc.dg/countof-vla.c
	* gcc.dg/countof.c: Add tests for __countof__ operator.

Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3313.pdf>
Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3325.pdf>
Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3369.pdf>
Link: <https://inbox.sourceware.org/gcc/M8S4oQy--3-2@tutanota.com/T/>
Link: <https://github.com/llvm/llvm-project/issues/102836>
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>
Cc: Daniel Plakosh <dplakosh@cert.org>
Cc: "A. Jiang" <de34@live.cn>
Cc: Eugene Zelenko <eugene.zelenko@gmail.com>
Cc: Aaron Ballman <aaron.ballman@intel.com>
Cc: Paul Koning <paulkoning@comcast.net>
Cc: Daniel Lundin <daniel.lundin.mail@gmail.com>
Cc: Nikolaos Strimpas <Strnik86@protonmail.com>
Cc: JeanHeyd Meneide <phdofthehouse@gmail.com>
Cc: Fernando Borretti <fernando@borretti.me>
Cc: Jonathan Protzenko <jonathan.protzenko@ens-lyon.org>
Cc: Chris Bazley <Chris.Bazley@arm.com>
Cc: Ville Voutilainen <ville.voutilainen@gmail.com>
Cc: Alex Celeste <alexg.nvfp@gmail.com>
Cc: Jakub Łukasiewicz <jakublukasiewicz@outlook.com>
Cc: Douglas McIlroy <douglas.mcilroy@dartmouth.edu>
Cc: Jason Merrill <jason@redhat.com>
Suggested-by: Xavier Del Campo Romero <xavi.dcr@tutanota.com>
Co-authored-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                        |  22 +++-
 gcc/c/c-parser.cc                      |  62 +++++++---
 gcc/c/c-tree.h                         |   4 +
 gcc/c/c-typeck.cc                      | 118 ++++++++++++++++++-
 gcc/cp/operators.def                   |   1 +
 gcc/doc/extend.texi                    |  30 +++++
 gcc/target.h                           |   3 +
 gcc/testsuite/gcc.dg/countof-compile.c | 115 +++++++++++++++++++
 gcc/testsuite/gcc.dg/countof-vla.c     |  46 ++++++++
 gcc/testsuite/gcc.dg/countof.c         | 150 +++++++++++++++++++++++++
 13 files changed, 558 insertions(+), 24 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/countof-compile.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-vla.c
 create mode 100644 gcc/testsuite/gcc.dg/countof.c

diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
index e7e371fd26f..3efbac92765 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 },
+  { "__countof__",	RID_COUNTOF,	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 lementsof keyword:
+   Return the number of elements of an array.  */
+
+tree
+c_countof_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 %<countof%> to type %qT", type);
+      return error_mark_node;
+    }
+  if (!COMPLETE_TYPE_P (type))
+    {
+      error_at (loc,
+		"invalid application of %<countof%> 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..3d882e70cc0 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 'countof' expression.  */
+DEFTREECODE (COUNTOF_EXPR, "countof_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 d3827573a36..d4c8748b74a 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_COUNTOF,
   RID_VA_ARG,
   RID_EXTENSION, RID_IMAGPART, RID_REALPART, RID_LABEL,    RID_CHOOSE_EXPR,
   RID_TYPES_COMPATIBLE_P,      RID_BUILTIN_COMPLEX,	   RID_BUILTIN_SHUFFLE,
@@ -887,6 +888,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_countof_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 c73d3107efb..a258c777070 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -8992,12 +8992,17 @@ 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_countof))
     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"
+		       : "countof"))));
 
   if (in_underspecified_init)
     error_at (loc, "%qT defined in underspecified object initializer", ref);
@@ -9957,7 +9962,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_countof)
 	struct_parse_info->struct_types.safe_push (t);
      }
 
@@ -10131,12 +10136,17 @@ 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_countof))
     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"
+		       : "countof"))));
 
   if (in_underspecified_init)
     error_at (loc, "%qT defined in underspecified object initializer",
@@ -10330,7 +10340,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_countof)
     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 aff5af17430..809d74553bf 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_countof_expression (parser, RID_SIZEOF)                  \
+)
 
+#define c_parser_countof_expression(parser)                                   \
+(                                                                             \
+  c_parser_sizeof_or_countof_expression (parser, RID_COUNTOF)                 \
+)
+\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,8 @@ 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_countof_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 *,
@@ -9910,6 +9921,8 @@ c_parser_unary_expression (c_parser *parser)
     case CPP_KEYWORD:
       switch (c_parser_peek_token (parser)->keyword)
 	{
+	case RID_COUNTOF:
+	  return c_parser_countof_expression (parser);
 	case RID_SIZEOF:
 	  return c_parser_sizeof_expression (parser);
 	case RID_ALIGNOF:
@@ -9949,12 +9962,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_countof_expression (c_parser *parser, enum rid rid)
 {
+  const char *op_name = (rid == RID_COUNTOF) ? "countof" : "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;
@@ -9963,7 +9977,10 @@ c_parser_sizeof_expression (c_parser *parser)
 
   c_parser_consume_token (parser);
   c_inhibit_evaluation_warnings++;
-  in_sizeof++;
+  if (rid == RID_COUNTOF)
+    in_countof++;
+  else
+    in_sizeof++;
   if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)
       && c_token_starts_compound_literal (c_parser_peek_2nd_token (parser)))
     {
@@ -9982,7 +9999,10 @@ c_parser_sizeof_expression (c_parser *parser)
 	{
 	  struct c_expr ret;
 	  c_inhibit_evaluation_warnings--;
-	  in_sizeof--;
+	  if (rid == RID_COUNTOF)
+	    in_countof--;
+	  else
+	    in_sizeof--;
 	  ret.set_error ();
 	  ret.original_code = ERROR_MARK;
 	  ret.original_type = NULL;
@@ -9994,31 +10014,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_COUNTOF)
+	{
+	  in_countof--;
+	  result = c_expr_countof_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_COUNTOF)
+	in_countof--;
+      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_COUNTOF)
+	result = c_expr_countof_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 57befb94c08..2da074843f2 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_countof;
 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_countof_expr (location_t, struct c_expr);
+extern struct c_expr c_expr_countof_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..cb90278852b 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 "countof".  */
+int in_countof;
+
 /* 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_countof)
 	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_countof).  */
   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_countof;
   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_countof;
   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 countof applied to EXPR.  */
+
+struct c_expr
+c_expr_countof_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_countof_type (loc, TREE_TYPE (folded_expr));
+      c_last_sizeof_arg = expr.value;
+      c_last_sizeof_loc = loc;
+      ret.original_code = COUNTOF_EXPR;
+      ret.original_type = NULL;
+      ret.m_decimal = 0;
+      if (is_top_array_vla (TREE_TYPE (folded_expr)))
+	{
+	  /* countof 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 countof applied to T, a structure for the type
+   name passed to countof (rather than the type itself).  LOC is the
+   location of the original expression.  */
+
+struct c_expr
+c_expr_countof_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_countof_type (loc, type);
+  c_last_sizeof_arg = type;
+  c_last_sizeof_loc = loc;
+  ret.original_code = COUNTOF_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 countof 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 countof 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..b4db105f6b0 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 ("__countof__", COUNTOF_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 5845bcedf6e..1bcad06ce35 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -10544,6 +10544,36 @@ 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 countof
+@section Determining the Number of Elements of Arrays
+@cindex countof
+@cindex number of elements
+
+The keyword @code{__countof__} 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 parenthesized complete array type name
+or an expression of such a type.
+For example:
+
+@smallexample
+int a[n];
+__countof__ (a);  // returns n
+__countof__ (int [7][3]);  // returns 7
+@end smallexample
+
+The result of this operator is an integer constant expression,
+unless the array has a variable number of elements.
+The operand is only evaluated
+if the array has a variable number of elements.
+For example:
+
+@smallexample
+__countof__ (int [7][n++]);  // integer constant expression
+__countof__ (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..4165f632b4b 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 number of elements of array T.  */
+  TCTX_COUNTOF,
+
   /* Creating objects of type T with static storage duration.  */
   TCTX_STATIC_STORAGE,
 
diff --git a/gcc/testsuite/gcc.dg/countof-compile.c b/gcc/testsuite/gcc.dg/countof-compile.c
new file mode 100644
index 00000000000..6e2592edbb0
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/countof-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[__countof__(z)];
+
+void
+automatic(void)
+{
+  __countof__ (w);
+}
+
+void
+incomplete (int p[])
+{
+  __countof__ (x);  /* { dg-error "incomplete" } */
+
+  /* We want to support the following one in the future,
+     but for now it should fail.  */
+  __countof__ (p);  /* { dg-error "invalid" } */
+}
+
+void
+fam (void)
+{
+  struct {
+    int x;
+    int fam[];
+  } s;
+
+  __countof__ (s.fam); /* { dg-error "incomplete" } */
+}
+
+void fix_fix (int i, char (*a)[3][5], int (*x)[__countof__ (*a)]);
+void fix_var (int i, char (*a)[3][i], int (*x)[__countof__ (*a)]);
+void fix_uns (int i, char (*a)[3][*], int (*x)[__countof__ (*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;
+
+  __countof__ (x); /* { dg-error "invalid" } */
+  __countof__ (int); /* { dg-error "invalid" } */
+  __countof__ (s); /* { dg-error "invalid" } */
+  __countof__ (struct s); /* { dg-error "invalid" } */
+  __countof__ (&x); /* { dg-error "invalid" } */
+  __countof__ (p); /* { dg-error "invalid" } */
+  __countof__ (int *); /* { dg-error "invalid" } */
+  __countof__ (&s.x); /* { dg-error "invalid" } */
+  __countof__ (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];
+
+  __countof__ (a[f1()]);
+  __countof__ (b[f2()]);
+}
+
+void
+no_parens(void)
+{
+  __countof__ a;
+  __countof__ *a;
+  __countof__ (int [3]) {};
+
+  __countof__ int [3]; /* { dg-error "expected expression before" } */
+}
+
+void
+const_expr(void)
+{
+  int n = 7;
+
+  _Static_assert (__countof__ (int [3][n]) == 3);
+  _Static_assert (__countof__ (int [n][3]) == 7); /* { dg-error "not constant" } */
+  _Static_assert (__countof__ (int [0][3]) == 0);
+  _Static_assert (__countof__ (int [0]) == 0);
+
+  /* FIXME: countof(int [0][n]) should result in a constant expression.  */
+  _Static_assert (__countof__ (int [0][n]) == 0); /* { dg-error "not constant" } */
+}
diff --git a/gcc/testsuite/gcc.dg/countof-vla.c b/gcc/testsuite/gcc.dg/countof-vla.c
new file mode 100644
index 00000000000..5a82aeed782
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/countof-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)[__countof__ (*a)]);
+void fix_var (int i,
+	      char (*a)[3][i], /* dg-warn "variable" */
+	      int (*x)[__countof__ (*a)]);
+void fix_uns (int i,
+	      char (*a)[3][*],
+	      int (*x)[__countof__ (*a)]);
+
+void zro_fix (int i,
+	      char (*a)[0][5],
+	      int (*x)[__countof__ (*a)]);
+void zro_var (int i,
+	      char (*a)[0][i], /* dg-warn "variable" */
+	      int (*x)[__countof__ (*a)]);
+void zro_uns (int i,
+	      char (*a)[0][*],
+	      int (*x)[__countof__ (*a)]);
+
+void var_fix (int i,
+	      char (*a)[i][5], /* dg-warn "variable" */
+	      int (*x)[__countof__ (*a)]); /* dg-warn "variable" */
+void var_var (int i,
+	      char (*a)[i][i], /* dg-warn "variable" */
+	      int (*x)[__countof__ (*a)]); /* dg-warn "variable" */
+void var_uns (int i,
+	      char (*a)[i][*], /* dg-warn "variable" */
+	      int (*x)[__countof__ (*a)]); /* dg-warn "variable" */
+
+void uns_fix (int i,
+	      char (*a)[*][5],
+	      int (*x)[__countof__ (*a)]);
+void uns_var (int i,
+	      char (*a)[*][i], /* dg-warn "variable" */
+	      int (*x)[__countof__ (*a)]);
+void uns_uns (int i,
+	      char (*a)[*][*],
+	      int (*x)[__countof__ (*a)]);
+
+// Can't test due to bug: <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=116284>
+//static int z2[0];
+//static int y2[__countof__(z2)];
diff --git a/gcc/testsuite/gcc.dg/countof.c b/gcc/testsuite/gcc.dg/countof.c
new file mode 100644
index 00000000000..063a207fb6b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/countof.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 (__countof__ (a) == 7);
+  static_assert (__countof__ (long [0]) == 0);
+  static_assert (__countof__ (unsigned [99]) == 99);
+}
+
+void
+automatic(void)
+{
+  int a[] = {1, 2, 3};
+  int z[] = {};
+
+  static_assert (__countof__ (a) == 3);
+  static_assert (__countof__ (z) == 0);
+}
+
+void
+vla (void)
+{
+  unsigned n;
+
+  n = 99;
+  assert (__countof__ (short [n - 10]) == 99 - 10);
+
+  int v[n / 2];
+  assert (__countof__ (v) == 99 / 2);
+
+  n = 0;
+  int z[n];
+  assert (__countof__ (z) == 0);
+}
+
+void
+member (void)
+{
+  struct {
+    int a[8];
+  } s;
+
+  static_assert (__countof__ (s.a) == 8);
+}
+
+void
+vla_eval (void)
+{
+  int i;
+
+  i = 7;
+  assert (__countof__ (struct {int x;}[i++]) == 7);
+  assert (i == 7 + 1);
+
+  int v[i];
+  int (*p)[i];
+  p = &v;
+  assert (__countof__ (*p++) == i);
+  assert (p - 1 == &v);
+}
+
+void
+inner_vla_noeval (void)
+{
+  int i;
+
+  i = 3;
+  static_assert (__countof__ (struct {int x[i++];}[3]) == 3);
+  assert (i == 3);
+}
+
+void
+array_noeval (void)
+{
+  long a[5];
+  long (*p)[__countof__ (a)];
+
+  p = &a;
+  static_assert (__countof__ (*p++) == 5);
+  assert (p == &a);
+}
+
+void
+matrix_zero (void)
+{
+  int i;
+
+  static_assert (__countof__ (int [0][4]) == 0);
+  i = 3;
+  assert (__countof__ (int [0][i]) == 0);
+}
+
+void
+matrix_fixed (void)
+{
+  int i;
+
+  static_assert (__countof__ (int [7][4]) == 7);
+  i = 3;
+  static_assert (__countof__ (int [7][i]) == 7);
+}
+
+void
+matrix_vla (void)
+{
+  int i, j;
+
+  i = 7;
+  assert (__countof__ (int [i++][4]) == 7);
+  assert (i == 7 + 1);
+
+  i = 9;
+  j = 3;
+  assert (__countof__ (int [i++][j]) == 9);
+  assert (i == 9 + 1);
+}
+
+void
+no_parens(void)
+{
+  int n = 3;
+  int a[7];
+  int v[n];
+
+  static_assert (__countof__ a == 7); 
+  assert (__countof__ 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] 318+ messages in thread

* Re: [PATCH v13 0/4] c: Add __lengthof__ operator
  2024-10-08  0:04       ` Alejandro Colomar
  2024-10-08  0:09         ` Alejandro Colomar
@ 2024-10-08 13:19         ` Joseph Myers
  2024-10-08 13:28           ` Alejandro Colomar
  1 sibling, 1 reply; 318+ messages in thread
From: Joseph Myers @ 2024-10-08 13:19 UTC (permalink / raw)
  To: Alejandro Colomar
  Cc: gcc-patches, Gabriel Ravier, Jakub Jelinek, Kees Cook, Qing Zhao,
	Jens Gustedt, David Brown, Florian Weimer, Andreas Schwab,
	Timm Baeder, Daniel Plakosh, A. Jiang, Eugene Zelenko,
	Aaron Ballman, Paul Koning, Daniel Lundin, Nikolaos Strimpas,
	JeanHeyd Meneide, Fernando Borretti, Jonathan Protzenko,
	Chris Bazley, Ville Voutilainen, Alex Celeste,
	Jakub Łukasiewicz, Douglas McIlroy, Jason Merrill,
	Xavier Del Campo Romero, Siddhesh Poyarekar, DJ Delorie,
	Carlos O'Donell, Stephen Coady, Robert Seacord

On Tue, 8 Oct 2024, Alejandro Colomar wrote:

> On Mon, Oct 07, 2024 at 05:35:16PM GMT, Joseph Myers wrote:
> > Patches 1, 2 and 3 are logically nothing to do with this feature.  I'll 
> > wait for them to be reviewed so that we only have a single-patch series, 
> > before doing final review of the main patch.
> 
> I do not fully understand.  Who has to review patches 1,2,3?  Also, do

Someone who is a maintainer or reviewer of relevant parts of the compiler.  
Maybe 90% of the people CC:ed are not GCC maintainers or reviewers and 
should not be included on these patches at all.

> you want to merge them, then I resend patch 4 as a single patch, and
> then you review that one?  If so, that looks like a good plan to me.

Yes, patch 4 as a single patch.  With _Lengthof.  No other names, no 
__countof__, no __lengthof__.  _Lengthof is a perfectly good name, no need 
to be gratuitously incompatible.

-- 
Joseph S. Myers
josmyers@redhat.com


^ permalink raw reply	[flat|nested] 318+ messages in thread

* Re: [PATCH v13 0/4] c: Add __lengthof__ operator
  2024-10-08  8:33         ` Alejandro Colomar
  2024-10-08  8:59           ` Jakub Łukasiewicz
@ 2024-10-08 13:23           ` Joseph Myers
  1 sibling, 0 replies; 318+ messages in thread
From: Joseph Myers @ 2024-10-08 13:23 UTC (permalink / raw)
  To: Alejandro Colomar
  Cc: Jakub Łukasiewicz, WG14, gcc-patches, Gabriel Ravier,
	Jakub Jelinek, Kees Cook, Qing Zhao, Jens Gustedt, David Brown,
	Florian Weimer, Andreas Schwab, Timm Baeder, Daniel Plakosh,
	A. Jiang, Eugene Zelenko, Paul Koning, Daniel Lundin,
	Nikolaos Strimpas, Fernando Borretti, Jonathan Protzenko,
	Douglas McIlroy, Jason Merrill, Xavier Del Campo Romero,
	Siddhesh Poyarekar, DJ Delorie, Carlos O'Donell,
	Stephen Coady

On Tue, 8 Oct 2024, Alejandro Colomar wrote:

> How about adding the __lower__ version now as a GNU extension with
> compatible semantics, and when it's closer to an ISO C2y release add the
> _Upper one?

No, we don't need two names.  Just _Lengthof suffices.  If semantics 
change in some way during C2y development, we can update the 
implementation to match.

We have a rule that the C++ library ABI is explicitly unstable for 
features in a new standard where support is still under development, and 
only commit to a stable C++ library ABI supporting existing binaries once 
the support for that version is mature enough.  I think it's reasonable 
also to say that features from C2y (including when supported in older 
standards modes) are unstable and liable to change when the semantics in 
C2y change.  (Liable to change doesn't mean changing on a release branch 
after the first release from that branch.  But it could in some cases mean 
changing incompatibly while mainline is in regression fixes mode, to avoid 
releasing something significantly incompatible with later changes.)

-- 
Joseph S. Myers
josmyers@redhat.com


^ permalink raw reply	[flat|nested] 318+ messages in thread

* Re: [PATCH v13 0/4] c: Add __lengthof__ operator
  2024-10-08 13:19         ` Joseph Myers
@ 2024-10-08 13:28           ` Alejandro Colomar
  2024-10-08 13:40             ` Jakub Jelinek
  2024-10-08 14:04             ` [PATCH v13 0/4] c: Add __lengthof__ operator Joseph Myers
  0 siblings, 2 replies; 318+ messages in thread
From: Alejandro Colomar @ 2024-10-08 13:28 UTC (permalink / raw)
  To: Joseph Myers
  Cc: gcc-patches, Gabriel Ravier, Jakub Jelinek, Kees Cook, Qing Zhao,
	Jens Gustedt, David Brown, Florian Weimer, Andreas Schwab,
	Timm Baeder, Daniel Plakosh, A. Jiang, Eugene Zelenko,
	Aaron Ballman, Paul Koning, Daniel Lundin, Nikolaos Strimpas,
	JeanHeyd Meneide, Fernando Borretti, Jonathan Protzenko,
	Chris Bazley, Ville Voutilainen, Alex Celeste,
	Jakub Łukasiewicz, Douglas McIlroy, Jason Merrill,
	Xavier Del Campo Romero, Siddhesh Poyarekar, DJ Delorie,
	Carlos O'Donell, Stephen Coady, Robert Seacord

[-- Attachment #1: Type: text/plain, Size: 1718 bytes --]

Hi Joseph,

On Tue, Oct 08, 2024 at 01:19:06PM GMT, Joseph Myers wrote:
> On Tue, 8 Oct 2024, Alejandro Colomar wrote:
> 
> > On Mon, Oct 07, 2024 at 05:35:16PM GMT, Joseph Myers wrote:
> > > Patches 1, 2 and 3 are logically nothing to do with this feature.  I'll 
> > > wait for them to be reviewed so that we only have a single-patch series, 
> > > before doing final review of the main patch.
> > 
> > I do not fully understand.  Who has to review patches 1,2,3?  Also, do
> 
> Someone who is a maintainer or reviewer of relevant parts of the compiler.  
> Maybe 90% of the people CC:ed are not GCC maintainers or reviewers and 
> should not be included on these patches at all.

Those are people with interest in one way or another in this feature
(most of them, patch 4).  While patches 1,2,3 are irrelevant to them, I
kept them on the entire thread for simplicity.

> 
> > you want to merge them, then I resend patch 4 as a single patch, and
> > then you review that one?  If so, that looks like a good plan to me.
> 
> Yes, patch 4 as a single patch.  With _Lengthof.  No other names, no 
> __countof__, no __lengthof__.  _Lengthof is a perfectly good name, no need 
> to be gratuitously incompatible.

It is not gratuitously, IMO.  You already know my concerns about it;
please sed(1) yourself the name of the operator from these patches, and
append your signature below mine, if you want to rename it.  I won't do
that, for I think it introduces a security problem that will slowly
develop.

If you wish to wait for Graz to make sure there's no incompatibility
with ISO, that's another possibility.


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] 318+ messages in thread

* Re: [PATCH v13 0/4] c: Add __lengthof__ operator
  2024-10-08 13:28           ` Alejandro Colomar
@ 2024-10-08 13:40             ` Jakub Jelinek
  2024-10-08 14:49               ` Alejandro Colomar
  2024-10-08 14:04             ` [PATCH v13 0/4] c: Add __lengthof__ operator Joseph Myers
  1 sibling, 1 reply; 318+ messages in thread
From: Jakub Jelinek @ 2024-10-08 13:40 UTC (permalink / raw)
  To: Alejandro Colomar
  Cc: Joseph Myers, gcc-patches, Gabriel Ravier, Kees Cook, Qing Zhao,
	Jens Gustedt, David Brown, Florian Weimer, Andreas Schwab,
	Timm Baeder, Daniel Plakosh, A. Jiang, Eugene Zelenko,
	Aaron Ballman, Paul Koning, Daniel Lundin, Nikolaos Strimpas,
	JeanHeyd Meneide, Fernando Borretti, Jonathan Protzenko,
	Chris Bazley, Ville Voutilainen, Alex Celeste,
	Jakub Łukasiewicz, Douglas McIlroy, Jason Merrill,
	Xavier Del Campo Romero, Siddhesh Poyarekar, DJ Delorie,
	Carlos O'Donell, Stephen Coady, Robert Seacord

On Tue, Oct 08, 2024 at 03:28:29PM +0200, Alejandro Colomar wrote:
> On Tue, Oct 08, 2024 at 01:19:06PM GMT, Joseph Myers wrote:
> > On Tue, 8 Oct 2024, Alejandro Colomar wrote:
> > 
> > > On Mon, Oct 07, 2024 at 05:35:16PM GMT, Joseph Myers wrote:
> > > > Patches 1, 2 and 3 are logically nothing to do with this feature.  I'll 
> > > > wait for them to be reviewed so that we only have a single-patch series, 
> > > > before doing final review of the main patch.
> > > 
> > > I do not fully understand.  Who has to review patches 1,2,3?  Also, do
> > 
> > Someone who is a maintainer or reviewer of relevant parts of the compiler.  
> > Maybe 90% of the people CC:ed are not GCC maintainers or reviewers and 
> > should not be included on these patches at all.
> 
> Those are people with interest in one way or another in this feature
> (most of them, patch 4).  While patches 1,2,3 are irrelevant to them, I
> kept them on the entire thread for simplicity.

I'd just suggest posting the patch 4 alone adjusted so that it doesn't need
2,3.  Those 2 can be handled completely independently from patch 4 and for 1
there is no dependency, it is just a random unrelated patch.

> > > you want to merge them, then I resend patch 4 as a single patch, and
> > > then you review that one?  If so, that looks like a good plan to me.
> > 
> > Yes, patch 4 as a single patch.  With _Lengthof.  No other names, no 
> > __countof__, no __lengthof__.  _Lengthof is a perfectly good name, no need 
> > to be gratuitously incompatible.
> 
> It is not gratuitously, IMO.  You already know my concerns about it;
> please sed(1) yourself the name of the operator from these patches, and
> append your signature below mine, if you want to rename it.  I won't do
> that, for I think it introduces a security problem that will slowly
> develop.
> 
> If you wish to wait for Graz to make sure there's no incompatibility
> with ISO, that's another possibility.

I don't see why we'd need to wait for next WG14 meeting here, as the paper
has been voted into the next standard draft, compilers can implement the
feature, and as with anything else if the standard is changed later, it will
be adjusted to match it (or withdrawn/renamed or whatever).  That is always
a risk of using features from unreleased standards (but even features
in released standards can be tweaked with DRs later on).
It doesn't make sense to have two different operators just because we fear
it will change.
We do have some cases of different operators for the same thing if it was
first implemented as an extension and only later standardized under
different name or with different rules.
That is not the case here.

	Jakub


^ permalink raw reply	[flat|nested] 318+ messages in thread

* Re: [PATCH v13 0/4] c: Add __lengthof__ operator
  2024-10-08 13:28           ` Alejandro Colomar
  2024-10-08 13:40             ` Jakub Jelinek
@ 2024-10-08 14:04             ` Joseph Myers
  2024-10-08 14:59               ` Alejandro Colomar
  1 sibling, 1 reply; 318+ messages in thread
From: Joseph Myers @ 2024-10-08 14:04 UTC (permalink / raw)
  To: Alejandro Colomar
  Cc: gcc-patches, Gabriel Ravier, Jakub Jelinek, Kees Cook, Qing Zhao,
	Jens Gustedt, David Brown, Florian Weimer, Andreas Schwab,
	Timm Baeder, Daniel Plakosh, A. Jiang, Eugene Zelenko,
	Aaron Ballman, Paul Koning, Daniel Lundin, Nikolaos Strimpas,
	JeanHeyd Meneide, Fernando Borretti, Jonathan Protzenko,
	Chris Bazley, Ville Voutilainen, Alex Celeste,
	Jakub Łukasiewicz, Douglas McIlroy, Jason Merrill,
	Xavier Del Campo Romero, Siddhesh Poyarekar, DJ Delorie,
	Carlos O'Donell, Stephen Coady, Robert Seacord

On Tue, 8 Oct 2024, Alejandro Colomar wrote:

> If you wish to wait for Graz to make sure there's no incompatibility
> with ISO, that's another possibility.

The name could be changed in GCC after Graz (while in 
regression-fixes-only mode for GCC 15) if WG14 changes the name in Graz.  
It wouldn't be a good idea to add as a new feature while in 
regression-fixes-only mode; waiting to after Graz for that would mean only 
adding it in GCC 16.

"length" is well-understood as referring to the number of elements of an 
array even if not explicitly defined as such in the standard (cf. the noun 
"variable" being well-understood by users of C even though the standard 
always says "object").  And there was along-the-lines support in 
Strasbourg for N3187 which, among other things, would make the use of 
"length" for this consistent and explicit.  I have plenty of concerns with 
both the wording and incompatibility of various changes suggested there 
related to what's allowed as a sizeof operand and associated semantics but 
I don't think there were any concerns in that discussion about the use of 
the term "length".

-- 
Joseph S. Myers
josmyers@redhat.com


^ permalink raw reply	[flat|nested] 318+ messages in thread

* Re: [PATCH v13 0/4] c: Add __lengthof__ operator
  2024-10-08 13:40             ` Jakub Jelinek
@ 2024-10-08 14:49               ` Alejandro Colomar
  2024-10-08 15:13                 ` Chris Bazley
  0 siblings, 1 reply; 318+ messages in thread
From: Alejandro Colomar @ 2024-10-08 14:49 UTC (permalink / raw)
  To: Jakub Jelinek
  Cc: Joseph Myers, gcc-patches, Gabriel Ravier, Kees Cook, Qing Zhao,
	Jens Gustedt, David Brown, Florian Weimer, Andreas Schwab,
	Timm Baeder, Daniel Plakosh, A. Jiang, Eugene Zelenko,
	Aaron Ballman, Paul Koning, Daniel Lundin, Nikolaos Strimpas,
	JeanHeyd Meneide, Fernando Borretti, Jonathan Protzenko,
	Chris Bazley, Ville Voutilainen, Alex Celeste,
	Jakub Łukasiewicz, Douglas McIlroy, Jason Merrill,
	Xavier Del Campo Romero, Siddhesh Poyarekar, DJ Delorie,
	Carlos O'Donell, Stephen Coady, Robert Seacord

[-- Attachment #1: Type: text/plain, Size: 3611 bytes --]

On Tue, Oct 08, 2024 at 03:40:53PM GMT, Jakub Jelinek wrote:
> On Tue, Oct 08, 2024 at 03:28:29PM +0200, Alejandro Colomar wrote:
> > On Tue, Oct 08, 2024 at 01:19:06PM GMT, Joseph Myers wrote:
> > > On Tue, 8 Oct 2024, Alejandro Colomar wrote:
> > > 
> > > > On Mon, Oct 07, 2024 at 05:35:16PM GMT, Joseph Myers wrote:
> > > > > Patches 1, 2 and 3 are logically nothing to do with this feature.  I'll 
> > > > > wait for them to be reviewed so that we only have a single-patch series, 
> > > > > before doing final review of the main patch.
> > > > 
> > > > I do not fully understand.  Who has to review patches 1,2,3?  Also, do
> > > 
> > > Someone who is a maintainer or reviewer of relevant parts of the compiler.  
> > > Maybe 90% of the people CC:ed are not GCC maintainers or reviewers and 
> > > should not be included on these patches at all.
> > 
> > Those are people with interest in one way or another in this feature
> > (most of them, patch 4).  While patches 1,2,3 are irrelevant to them, I
> > kept them on the entire thread for simplicity.
> 
> I'd just suggest posting the patch 4 alone adjusted so that it doesn't need
> 2,3.  Those 2 can be handled completely independently from patch 4 and for 1
> there is no dependency, it is just a random unrelated patch.

2,3 are needed for not making 4 read horribly.
1 is needed for the commit message of 4.

I don't mind waiting for gcc-16, if that needs to happen.

> 
> > > > you want to merge them, then I resend patch 4 as a single patch, and
> > > > then you review that one?  If so, that looks like a good plan to me.
> > > 
> > > Yes, patch 4 as a single patch.  With _Lengthof.  No other names, no 
> > > __countof__, no __lengthof__.  _Lengthof is a perfectly good name, no need 
> > > to be gratuitously incompatible.
> > 
> > It is not gratuitously, IMO.  You already know my concerns about it;
> > please sed(1) yourself the name of the operator from these patches, and
> > append your signature below mine, if you want to rename it.  I won't do
> > that, for I think it introduces a security problem that will slowly
> > develop.
> > 
> > If you wish to wait for Graz to make sure there's no incompatibility
> > with ISO, that's another possibility.
> 
> I don't see why we'd need to wait for next WG14 meeting here, as the paper
> has been voted into the next standard draft, compilers can implement the
> feature,

Because I don't like the paper that has been voted into the standard.
I kind of presented that paper against my will.  I wish GCC merged the
feature with a different name, and forced the standard to reconsider
what they merged, which I consider to be a security problem.

Alternatively, I wish GCC decided to do nothing, wait for Graz, where
I'll try to convince WG14 to change what was voted.

But merging what was voted into the standard would be nefarious, IMO.


Have a lovely day!
Alex

> and as with anything else if the standard is changed later, it will
> be adjusted to match it (or withdrawn/renamed or whatever).  That is always
> a risk of using features from unreleased standards (but even features
> in released standards can be tweaked with DRs later on).
> It doesn't make sense to have two different operators just because we fear
> it will change.
> We do have some cases of different operators for the same thing if it was
> first implemented as an extension and only later standardized under
> different name or with different rules.
> That is not the case here.
> 
> 	Jakub
> 

-- 
<https://www.alejandro-colomar.es/>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 318+ messages in thread

* Re: [PATCH v13 0/4] c: Add __lengthof__ operator
  2024-10-08 14:04             ` [PATCH v13 0/4] c: Add __lengthof__ operator Joseph Myers
@ 2024-10-08 14:59               ` Alejandro Colomar
  2024-10-08 15:13                 ` Joseph Myers
  0 siblings, 1 reply; 318+ messages in thread
From: Alejandro Colomar @ 2024-10-08 14:59 UTC (permalink / raw)
  To: Joseph Myers
  Cc: gcc-patches, Gabriel Ravier, Jakub Jelinek, Kees Cook, Qing Zhao,
	Jens Gustedt, David Brown, Florian Weimer, Andreas Schwab,
	Timm Baeder, Daniel Plakosh, A. Jiang, Eugene Zelenko,
	Aaron Ballman, Paul Koning, Daniel Lundin, Nikolaos Strimpas,
	JeanHeyd Meneide, Fernando Borretti, Jonathan Protzenko,
	Chris Bazley, Ville Voutilainen, Alex Celeste,
	Jakub Łukasiewicz, Douglas McIlroy, Jason Merrill,
	Xavier Del Campo Romero, Siddhesh Poyarekar, DJ Delorie,
	Carlos O'Donell, Stephen Coady, Robert Seacord

[-- Attachment #1: Type: text/plain, Size: 2064 bytes --]

Hi Joseph,

On Tue, Oct 08, 2024 at 02:04:12PM GMT, Joseph Myers wrote:
> On Tue, 8 Oct 2024, Alejandro Colomar wrote:
> 
> > If you wish to wait for Graz to make sure there's no incompatibility
> > with ISO, that's another possibility.
> 
> The name could be changed in GCC after Graz (while in 
> regression-fixes-only mode for GCC 15) if WG14 changes the name in Graz.  
> It wouldn't be a good idea to add as a new feature while in 
> regression-fixes-only mode; waiting to after Graz for that would mean only 
> adding it in GCC 16.

I prefer waiting for Graz.  Merging _Lengthof already would provide less
incentive for WG14 to change their mind.  I don't mind having this in
GCC 16 instead of 15, if that's the only way.

Alternatively, you could consider countof for GCC 15, and optionally
rename it later if my arguments are dismissed.

Or you can merge yourself _Lengthof already, by sed(1)ing my patches, if
you wish.

> "length" is well-understood as referring to the number of elements of an 
> array even if not explicitly defined as such in the standard (cf. the noun 
> "variable" being well-understood by users of C even though the standard 
> always says "object").

> And there was along-the-lines support in 
> Strasbourg for N3187

I interpret something along the lines of n3187 to mean "we want to make
ISO C consistent with language" --which is an opinion I share--, rather
than specifically meaning that length is the only acceptable term.

> which, among other things, would make the use of 
> "length" for this consistent and explicit.

> I have plenty of concerns with 
> both the wording and incompatibility of various changes suggested there 
> related to what's allowed as a sizeof operand and associated semantics but 
> I don't think there were any concerns in that discussion about the use of 
> the term "length".

Now you've seen mine.  I will oppose to n3187 as much as I can, as long
as it offers length as the term.


Cheers,
Alex

-- 
<https://www.alejandro-colomar.es/>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 318+ messages in thread

* Re: [PATCH v13 0/4] c: Add __lengthof__ operator
  2024-10-08 14:49               ` Alejandro Colomar
@ 2024-10-08 15:13                 ` Chris Bazley
  2024-10-09 12:11                   ` Alejandro Colomar
  0 siblings, 1 reply; 318+ messages in thread
From: Chris Bazley @ 2024-10-08 15:13 UTC (permalink / raw)
  To: Alejandro Colomar, Jakub Jelinek
  Cc: Joseph Myers, gcc-patches, Gabriel Ravier, Kees Cook, Qing Zhao,
	Jens Gustedt, David Brown, Florian Weimer, Andreas Schwab,
	Timm Baeder, Daniel Plakosh, A. Jiang, Eugene Zelenko,
	Aaron Ballman, Paul Koning, Daniel Lundin, Nikolaos Strimpas,
	JeanHeyd Meneide, Fernando Borretti, Jonathan Protzenko,
	Ville Voutilainen, Alex Celeste, Jakub Łukasiewicz,
	Douglas McIlroy, Jason Merrill, Xavier Del Campo Romero,
	Siddhesh Poyarekar, DJ Delorie, Carlos O'Donell,
	Stephen Coady, Robert Seacord

[-- Attachment #1: Type: text/plain, Size: 6003 bytes --]

> ​Because I don't like the paper that has been voted into the standard.
> I kind of presented that paper against my will.  I wish GCC merged the
> feature with a different name, and forced the standard to reconsider
> what they merged, which I consider to be a security problem.
>
> Alternatively, I wish GCC decided to do nothing, wait for Graz, where
> I'll try to convince WG14 to change what was voted.
>
> But merging what was voted into the standard would be nefarious, IMO.

I don't understand this security problem that you are referring to.

The vast majority of strings use 'char' as the element type.

Existing code might look something like this:

#define A "foo"
#define B "bar"
#define STRING_LEN(s) (sizeof(s) - 1)

char *c = malloc(STRING_LEN(A) + STRING_LEN(B) + 1);
if (c) {
  strcpy(c, A);
  strcat(c, B);
}

Supposing that _Length gets support in GCC, the equivalent source code would be almost
identical and the compiled code would be identical:

#define A "foo"
#define B "bar"
#define STRING_LEN(s) (_Lengthof(s) - 1)

char *c = malloc(STRING_LEN(A) + STRING_LEN(B) + 1);
if (c) {
  strcpy(c, A);
  strcat(c, B);
}

Are you concerned that people will start writing new code that does something like the following?

#define A "foo"
#define B "bar"

char *c = malloc(_Lengthof(A) + _Lengthof(B));
if (c) {
  strcpy(c, A);
  strcat(c, B);
}

If they do, the only consequence will be that the string buffer is longer than it needs to be; not shorter.

Best regards,
--
Christopher Bazley
Staff Software Engineer, GPU team, Central Engineering Group
ARM Ltd, 110 Fulbourn Road, Cambridge, CB1 9NJ, UK.
Web:   http://www.arm.com/

________________________________
From: Alejandro Colomar
Sent: Tuesday, October 08, 2024 15:49
To: Jakub Jelinek
Cc: Joseph Myers; gcc-patches@gcc.gnu.org; Gabriel Ravier; Kees Cook; Qing Zhao; Jens Gustedt; David Brown; Florian Weimer; Andreas Schwab; Timm Baeder; Daniel Plakosh; A. Jiang; Eugene Zelenko; Aaron Ballman; Paul Koning; Daniel Lundin; Nikolaos Strimpas; JeanHeyd Meneide; Fernando Borretti; Jonathan Protzenko; Chris Bazley; Ville Voutilainen; Alex Celeste; Jakub Łukasiewicz; Douglas McIlroy; Jason Merrill; Xavier Del Campo Romero; Siddhesh Poyarekar; DJ Delorie; Carlos O'Donell; Stephen Coady; Robert Seacord
Subject: Re: [PATCH v13 0/4] c: Add __lengthof__ operator

On Tue, Oct 08, 2024 at 03:40:53PM GMT, Jakub Jelinek wrote:
> On Tue, Oct 08, 2024 at 03:28:29PM +0200, Alejandro Colomar wrote:
> > On Tue, Oct 08, 2024 at 01:19:06PM GMT, Joseph Myers wrote:
> > > On Tue, 8 Oct 2024, Alejandro Colomar wrote:
> > >
> > > > On Mon, Oct 07, 2024 at 05:35:16PM GMT, Joseph Myers wrote:
> > > > > Patches 1, 2 and 3 are logically nothing to do with this feature.  I'll
> > > > > wait for them to be reviewed so that we only have a single-patch series,
> > > > > before doing final review of the main patch.
> > > >
> > > > I do not fully understand.  Who has to review patches 1,2,3?  Also, do
> > >
> > > Someone who is a maintainer or reviewer of relevant parts of the compiler.
> > > Maybe 90% of the people CC:ed are not GCC maintainers or reviewers and
> > > should not be included on these patches at all.
> >
> > Those are people with interest in one way or another in this feature
> > (most of them, patch 4).  While patches 1,2,3 are irrelevant to them, I
> > kept them on the entire thread for simplicity.
>
> I'd just suggest posting the patch 4 alone adjusted so that it doesn't need
> 2,3.  Those 2 can be handled completely independently from patch 4 and for 1
> there is no dependency, it is just a random unrelated patch.

2,3 are needed for not making 4 read horribly.
1 is needed for the commit message of 4.

I don't mind waiting for gcc-16, if that needs to happen.

>
> > > > you want to merge them, then I resend patch 4 as a single patch, and
> > > > then you review that one?  If so, that looks like a good plan to me.
> > >
> > > Yes, patch 4 as a single patch.  With _Lengthof.  No other names, no
> > > __countof__, no __lengthof__.  _Lengthof is a perfectly good name, no need
> > > to be gratuitously incompatible.
> >
> > It is not gratuitously, IMO.  You already know my concerns about it;
> > please sed(1) yourself the name of the operator from these patches, and
> > append your signature below mine, if you want to rename it.  I won't do
> > that, for I think it introduces a security problem that will slowly
> > develop.
> >
> > If you wish to wait for Graz to make sure there's no incompatibility
> > with ISO, that's another possibility.
>
> I don't see why we'd need to wait for next WG14 meeting here, as the paper
> has been voted into the next standard draft, compilers can implement the
> feature,

Because I don't like the paper that has been voted into the standard.
I kind of presented that paper against my will.  I wish GCC merged the
feature with a different name, and forced the standard to reconsider
what they merged, which I consider to be a security problem.

Alternatively, I wish GCC decided to do nothing, wait for Graz, where
I'll try to convince WG14 to change what was voted.

But merging what was voted into the standard would be nefarious, IMO.


Have a lovely day!
Alex

> and as with anything else if the standard is changed later, it will
> be adjusted to match it (or withdrawn/renamed or whatever).  That is always
> a risk of using features from unreleased standards (but even features
> in released standards can be tweaked with DRs later on).
> It doesn't make sense to have two different operators just because we fear
> it will change.
> We do have some cases of different operators for the same thing if it was
> first implemented as an extension and only later standardized under
> different name or with different rules.
> That is not the case here.
>
>        Jakub
>

--
<https://www.alejandro-colomar.es/>

^ permalink raw reply	[flat|nested] 318+ messages in thread

* Re: [PATCH v13 0/4] c: Add __lengthof__ operator
  2024-10-08 14:59               ` Alejandro Colomar
@ 2024-10-08 15:13                 ` Joseph Myers
  2024-10-08 15:21                   ` Chris Bazley
  2024-10-08 19:14                   ` Alejandro Colomar
  0 siblings, 2 replies; 318+ messages in thread
From: Joseph Myers @ 2024-10-08 15:13 UTC (permalink / raw)
  To: Alejandro Colomar
  Cc: gcc-patches, Gabriel Ravier, Jakub Jelinek, Kees Cook, Qing Zhao,
	Jens Gustedt, David Brown, Florian Weimer, Andreas Schwab,
	Timm Baeder, Daniel Plakosh, A. Jiang, Eugene Zelenko,
	Aaron Ballman, Paul Koning, Daniel Lundin, Nikolaos Strimpas,
	JeanHeyd Meneide, Fernando Borretti, Jonathan Protzenko,
	Chris Bazley, Ville Voutilainen, Alex Celeste,
	Jakub Łukasiewicz, Douglas McIlroy, Jason Merrill,
	Xavier Del Campo Romero, Siddhesh Poyarekar, DJ Delorie,
	Carlos O'Donell, Stephen Coady, Robert Seacord

On Tue, 8 Oct 2024, Alejandro Colomar wrote:

> > I have plenty of concerns with 
> > both the wording and incompatibility of various changes suggested there 
> > related to what's allowed as a sizeof operand and associated semantics but 
> > I don't think there were any concerns in that discussion about the use of 
> > the term "length".
> 
> Now you've seen mine.  I will oppose to n3187 as much as I can, as long
> as it offers length as the term.

It's "size", not "length", that has been used more inconsistently.  Take 
for example this sentence from K&R2 (I don't have K&R1), section 4.9 
(Initialization): "When the size of the array is omitted, the compiler 
will compute the length by counting the initializers, of which there are 
12 in this case.".  Length of strings is simply array length of a 
sub-array that doesn't include the terminating null character (a case of 
the sub-object issue of exactly what object is relevant in what context, 
not anything to do with the term "length").

-- 
Joseph S. Myers
josmyers@redhat.com


^ permalink raw reply	[flat|nested] 318+ messages in thread

* Re: [PATCH v13 0/4] c: Add __lengthof__ operator
  2024-10-08 15:13                 ` Joseph Myers
@ 2024-10-08 15:21                   ` Chris Bazley
  2024-10-08 15:54                     ` Jₑₙₛ Gustedt
  2024-10-08 19:14                   ` Alejandro Colomar
  1 sibling, 1 reply; 318+ messages in thread
From: Chris Bazley @ 2024-10-08 15:21 UTC (permalink / raw)
  To: Joseph Myers, Alejandro Colomar
  Cc: gcc-patches, Gabriel Ravier, Jakub Jelinek, Kees Cook, Qing Zhao,
	Jens Gustedt, David Brown, Florian Weimer, Andreas Schwab,
	Timm Baeder, Daniel Plakosh, A. Jiang, Eugene Zelenko,
	Aaron Ballman, Paul Koning, Daniel Lundin, Nikolaos Strimpas,
	JeanHeyd Meneide, Fernando Borretti, Jonathan Protzenko,
	Ville Voutilainen, Alex Celeste, Jakub Łukasiewicz,
	Douglas McIlroy, Jason Merrill, Xavier Del Campo Romero,
	Siddhesh Poyarekar, DJ Delorie, Carlos O'Donell,
	Stephen Coady, Robert Seacord

Joseph wrote:
> Length of strings is simply array length of a
> sub-array that doesn't include the terminating null character (a case of
> the sub-object issue of exactly what object is relevant in what context,
> not anything to do with the term "length").

Exactly! This is what eventually persuaded me to stop doubting that 'length'
is the most appropriate term (and I did sincerely doubt it, for a while).

We can't eliminate such off-by-one errors from programs by choice of
terminology, and certainly not by a retroactive change in terminology.

________________________________________
From: Joseph Myers <josmyers@redhat.com>
Sent: 08 October 2024 16:13
To: Alejandro Colomar
Cc: gcc-patches@gcc.gnu.org; Gabriel Ravier; Jakub Jelinek; Kees Cook; Qing Zhao; Jens Gustedt; David Brown; Florian Weimer; Andreas Schwab; Timm Baeder; Daniel Plakosh; A. Jiang; Eugene Zelenko; Aaron Ballman; Paul Koning; Daniel Lundin; Nikolaos Strimpas; JeanHeyd Meneide; Fernando Borretti; Jonathan Protzenko; Chris Bazley; Ville Voutilainen; Alex Celeste; Jakub Łukasiewicz; Douglas McIlroy; Jason Merrill; Xavier Del Campo Romero; Siddhesh Poyarekar; DJ Delorie; Carlos O'Donell; Stephen Coady; Robert Seacord
Subject: Re: [PATCH v13 0/4] c: Add __lengthof__ operator

On Tue, 8 Oct 2024, Alejandro Colomar wrote:

> > I have plenty of concerns with
> > both the wording and incompatibility of various changes suggested there
> > related to what's allowed as a sizeof operand and associated semantics but
> > I don't think there were any concerns in that discussion about the use of
> > the term "length".
>
> Now you've seen mine.  I will oppose to n3187 as much as I can, as long
> as it offers length as the term.

It's "size", not "length", that has been used more inconsistently.  Take
for example this sentence from K&R2 (I don't have K&R1), section 4.9
(Initialization): "When the size of the array is omitted, the compiler
will compute the length by counting the initializers, of which there are
12 in this case.".  Length of strings is simply array length of a
sub-array that doesn't include the terminating null character (a case of
the sub-object issue of exactly what object is relevant in what context,
not anything to do with the term "length").

--
Joseph S. Myers
josmyers@redhat.com


^ permalink raw reply	[flat|nested] 318+ messages in thread

* Re: [PATCH v13 0/4] c: Add __lengthof__ operator
  2024-10-08 15:21                   ` Chris Bazley
@ 2024-10-08 15:54                     ` Jₑₙₛ Gustedt
  0 siblings, 0 replies; 318+ messages in thread
From: Jₑₙₛ Gustedt @ 2024-10-08 15:54 UTC (permalink / raw)
  To: Chris Bazley
  Cc: Joseph Myers, Alejandro Colomar, gcc-patches, Gabriel Ravier,
	Jakub Jelinek, Kees Cook, Qing Zhao, David Brown, Florian Weimer,
	Andreas Schwab, Timm Baeder, Daniel Plakosh, A. Jiang,
	Eugene Zelenko, Aaron Ballman, Paul Koning, Daniel Lundin,
	Nikolaos Strimpas, JeanHeyd Meneide, Fernando Borretti,
	Jonathan Protzenko, Ville Voutilainen, Alex Celeste,
	Jakub Łukasiewicz, Douglas McIlroy, Jason Merrill,
	Xavier Del Campo Romero, Siddhesh Poyarekar, DJ Delorie,
	Carlos O'Donell, Stephen Coady, Robert Seacord

Hello everybody,
can you please leave me out of this ever spinning discussion?
The discussion in Minneapolis has fulfilled my needs on this for the
next 10 years at least.

I consider forcing people to opt out of mailings as being quite rude.

Thanks
Jₑₙₛ


-- 
:: ICube :::::::::::::::::::::::::::::: deputy director ::
:: Université de Strasbourg :::::::::::::::::::::: ICPS ::
:: INRIA antenne de Strasbourg :::::::::::::::::: Camus ::
:: INRIA PIQ program Strasbourg :::::::::: piq.inria.fr ::
:: :::::::::::::::::::::::::::::::::::: ☎ +33 368854536 ::
:: https://icube-icps.unistra.fr/index.php/Jens_Gustedt ::

^ permalink raw reply	[flat|nested] 318+ messages in thread

* Re: [PATCH v13 0/4] c: Add __lengthof__ operator
  2024-10-08 15:13                 ` Joseph Myers
  2024-10-08 15:21                   ` Chris Bazley
@ 2024-10-08 19:14                   ` Alejandro Colomar
  1 sibling, 0 replies; 318+ messages in thread
From: Alejandro Colomar @ 2024-10-08 19:14 UTC (permalink / raw)
  To: Joseph Myers
  Cc: gcc-patches, Gabriel Ravier, Jakub Jelinek, Kees Cook, Qing Zhao,
	David Brown, Florian Weimer, Andreas Schwab, Timm Baeder,
	Daniel Plakosh, A. Jiang, Eugene Zelenko, Aaron Ballman,
	Paul Koning, Daniel Lundin, Nikolaos Strimpas, JeanHeyd Meneide,
	Fernando Borretti, Jonathan Protzenko, Chris Bazley,
	Ville Voutilainen, Alex Celeste, Jakub Łukasiewicz,
	Douglas McIlroy, Jason Merrill, Xavier Del Campo Romero,
	Siddhesh Poyarekar, DJ Delorie, Carlos O'Donell,
	Stephen Coady, Robert Seacord

[-- Attachment #1: Type: text/plain, Size: 2783 bytes --]

[CC -= Jens]

Hi Joseph,

On Tue, Oct 08, 2024 at 03:13:19PM GMT, Joseph Myers wrote:
> On Tue, 8 Oct 2024, Alejandro Colomar wrote:
> 
> > > I have plenty of concerns with 
> > > both the wording and incompatibility of various changes suggested there 
> > > related to what's allowed as a sizeof operand and associated semantics but 
> > > I don't think there were any concerns in that discussion about the use of 
> > > the term "length".
> > 
> > Now you've seen mine.  I will oppose to n3187 as much as I can, as long
> > as it offers length as the term.
> 
> It's "size", not "length", that has been used more inconsistently.

Completely agree.

In fact, I've always supported using NITEMS() for things like

	#define STRLCPY(d, s)  strlcpy(d, s, NITEMS(d))

<https://lore.kernel.org/all/2jxak5v6dfxlpbxhpm3ey7oup4g2lnr3ueurfbosf5wdo65dk4@srb3hsk72zwq/>

However, at least the term size doesn't result in off-by-one issues.
With char-sized elements, it's not a problem.  And with wider elements,
it's so obviously different from the size, that people know what they're
doing.

And, I don't see why the standard couldn't just standardize on "number
of elements".  I don't see a need for using "length" in ISO C.  I think
removing the phrase "number of elements" from ISO C would be negative
--yes, Jens suggested he intended to do that in an eventual revision of
his paper, which prompted me attempting to shoot it down with n3327--.

>  Take 
> for example this sentence from K&R2 (I don't have K&R1), section 4.9 
> (Initialization): "When the size of the array is omitted, the compiler 
> will compute the length by counting the initializers, of which there are 
> 12 in this case.".

Heh.  :)

>  Length of strings is simply array length of a 
> sub-array that doesn't include the terminating null character (a case of 
> the sub-object issue of exactly what object is relevant in what context, 
> not anything to do with the term "length").

I thought of that, and I temporarily tried to convince myself that the
term can be used to mean that.  However, I don't fully convince myself
that programmers won't fall into off-by-one bugs due to this.

If you believe I'm wrong, I think it's okay.  I wouldn't mind if you
want to sed(1) the name yourself from my patch.  But in good faith, I
cannot send that patch.  You'll have to add your signature, and add a
line saying you changed the name of the operator.  But please go ahead
if that's what you think is best.  After all, we've had our arguments,
and there's no clear consensus on either side, so a maintainer has to
emit the final decision.  Whatever you decide, I'll be okay with it.


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] 318+ messages in thread

* Re: [PATCH v13 0/4] c: Add __lengthof__ operator
  2024-10-08 15:13                 ` Chris Bazley
@ 2024-10-09 12:11                   ` Alejandro Colomar
  2024-10-09 17:05                     ` Joseph Myers
  0 siblings, 1 reply; 318+ messages in thread
From: Alejandro Colomar @ 2024-10-09 12:11 UTC (permalink / raw)
  To: Chris Bazley
  Cc: Jakub Jelinek, Joseph Myers, gcc-patches, Gabriel Ravier,
	Kees Cook, Qing Zhao, David Brown, Florian Weimer,
	Andreas Schwab, Timm Baeder, Daniel Plakosh, A. Jiang,
	Eugene Zelenko, Aaron Ballman, Paul Koning, Daniel Lundin,
	Nikolaos Strimpas, JeanHeyd Meneide, Fernando Borretti,
	Jonathan Protzenko, Ville Voutilainen, Alex Celeste,
	Jakub Łukasiewicz, Douglas McIlroy, Jason Merrill,
	Xavier Del Campo Romero, Siddhesh Poyarekar, DJ Delorie,
	Carlos O'Donell, Stephen Coady, Robert Seacord

[-- Attachment #1: Type: text/plain, Size: 3100 bytes --]

[CC -= Jens]

Hi Chris,

On Tue, Oct 08, 2024 at 03:13:11PM GMT, Chris Bazley wrote:
> > ​Because I don't like the paper that has been voted into the standard.
> > I kind of presented that paper against my will.  I wish GCC merged the
> > feature with a different name, and forced the standard to reconsider
> > what they merged, which I consider to be a security problem.
> >
> > Alternatively, I wish GCC decided to do nothing, wait for Graz, where
> > I'll try to convince WG14 to change what was voted.
> >
> > But merging what was voted into the standard would be nefarious, IMO.
> 
> I don't understand this security problem that you are referring to.
> 
> The vast majority of strings use 'char' as the element type.
> 
> Existing code might look something like this:
> 
> #define A "foo"
> #define B "bar"
> #define STRING_LEN(s) (sizeof(s) - 1)
> 
> char *c = malloc(STRING_LEN(A) + STRING_LEN(B) + 1);
> if (c) {
>   strcpy(c, A);
>   strcat(c, B);
> }
> 
> Supposing that _Length gets support in GCC, the equivalent source code would be almost
> identical and the compiled code would be identical:
> 
> #define A "foo"
> #define B "bar"
> #define STRING_LEN(s) (_Lengthof(s) - 1)
> 
> char *c = malloc(STRING_LEN(A) + STRING_LEN(B) + 1);
> if (c) {
>   strcpy(c, A);
>   strcat(c, B);
> }
> 
> Are you concerned that people will start writing new code that does something like the following?
> 
> #define A "foo"
> #define B "bar"
> 
> char *c = malloc(_Lengthof(A) + _Lengthof(B));
> if (c) {
>   strcpy(c, A);
>   strcat(c, B);
> }
> 
> If they do, the only consequence will be that the string buffer is longer than it needs to be; not shorter.

Yes, off-by-one bugs on the safe side are more frequent than on the
unsafe side in this case.  However, I expect unsafe off-by-ones too.
And even in the safe side, there's the chance of secondary problems like
the following:

Let's say the maximum supported size is limited by a system limit.
For example, sysconf(_SC_LOGIN_NAME_MAX) or LOGIN_NAME_MAX.  If you try
to allocate one extra byte, so sysconf(_SC_LOGIN_NAME_MAX)+1, you may
overflow something somewhere, or cause some other important issues in
your system if you manage to create a user with such a long username.
Or your program will just crash and cause a DoS.

Or another combination of events that may cause another class of bugs.
In all cases, there's an off-by-one somewhere, but will result in a
different bug type.


I'm not fabricating, BTW.  Here's a list of off-by-one bugs in login
code, precisely due to this size-length naming issue:
<https://github.com/shadow-maint/shadow/commit/6551709e96b2bc6f084fdf170ad5bcc11f0038ab>
<https://github.com/shadow-maint/shadow/commit/15882a5f904b3c277d73254a6953c1051db55df4>


Have a lovely day!
Alex

> 
> Best regards,
> --
> Christopher Bazley
> Staff Software Engineer, GPU team, Central Engineering Group
> ARM Ltd, 110 Fulbourn Road, Cambridge, CB1 9NJ, UK.
> Web:   http://www.arm.com/

-- 
<https://www.alejandro-colomar.es/>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 318+ messages in thread

* Re: [PATCH v13 0/4] c: Add __lengthof__ operator
  2024-10-09 12:11                   ` Alejandro Colomar
@ 2024-10-09 17:05                     ` Joseph Myers
  2024-10-09 18:48                       ` Alejandro Colomar
  0 siblings, 1 reply; 318+ messages in thread
From: Joseph Myers @ 2024-10-09 17:05 UTC (permalink / raw)
  To: Alejandro Colomar
  Cc: Chris Bazley, Jakub Jelinek, gcc-patches, Gabriel Ravier,
	Kees Cook, Qing Zhao, David Brown, Florian Weimer,
	Andreas Schwab, Timm Baeder, Daniel Plakosh, A. Jiang,
	Eugene Zelenko, Aaron Ballman, Paul Koning, Daniel Lundin,
	Nikolaos Strimpas, JeanHeyd Meneide, Fernando Borretti,
	Jonathan Protzenko, Ville Voutilainen, Alex Celeste,
	Jakub Łukasiewicz, Douglas McIlroy, Jason Merrill,
	Xavier Del Campo Romero, Siddhesh Poyarekar, DJ Delorie,
	Carlos O'Donell, Stephen Coady, Robert Seacord

On Wed, 9 Oct 2024, Alejandro Colomar wrote:

> I'm not fabricating, BTW.  Here's a list of off-by-one bugs in login
> code, precisely due to this size-length naming issue:
> <https://github.com/shadow-maint/shadow/commit/6551709e96b2bc6f084fdf170ad5bcc11f0038ab>
> <https://github.com/shadow-maint/shadow/commit/15882a5f904b3c277d73254a6953c1051db55df4>

Those don't look to me like they're much to do with size/length *naming* 
confusion.  It's a conceptual confusion about whether the value needed by 
a particular API includes a null terminator or not, not about what you 
call size and what you call length.  As such, a name without "length" 
wouldn't help, because if you say countof, there would still be the same 
confusion about whether the bytes you are counting are meant to include a 
null terminator or not.

You could maybe avoid some cases of such off-by-one errors by language 
features that tie an array length more closely to a pointer (such as 
.IDENTIFIER proposals where IDENTIFIER is required to be const size_t, in 
cases where a pointer-to-VLA is passed, if there were appropriate 
constraints to require a matching pair of const size_t object and pointer 
to [.IDENTIFIER] VLA to be passed from caller to callee - more general 
versions with such strict requirements about passing matching pairs would 
be less likely to ensure correct sizes everywhere, and this idea about 
ensuring matching pairs isn't in N3188, it's an idea combining things from 
multiple papers).  But I think naming is essentially orthogonal to any 
kind of language feature that might enable reliable bounded pointers.

-- 
Joseph S. Myers
josmyers@redhat.com


^ permalink raw reply	[flat|nested] 318+ messages in thread

* Re: [PATCH v13 0/4] c: Add __lengthof__ operator
  2024-10-09 17:05                     ` Joseph Myers
@ 2024-10-09 18:48                       ` Alejandro Colomar
  2024-10-09 19:31                         ` Joseph Myers
  2024-10-09 19:40                         ` Meaning of "length", "size", and "count" Jakub Łukasiewicz
  0 siblings, 2 replies; 318+ messages in thread
From: Alejandro Colomar @ 2024-10-09 18:48 UTC (permalink / raw)
  To: Joseph Myers
  Cc: Chris Bazley, Jakub Jelinek, gcc-patches, Gabriel Ravier,
	Kees Cook, Qing Zhao, David Brown, Florian Weimer,
	Andreas Schwab, Timm Baeder, Daniel Plakosh, A. Jiang,
	Eugene Zelenko, Aaron Ballman, Paul Koning, Daniel Lundin,
	Nikolaos Strimpas, JeanHeyd Meneide, Fernando Borretti,
	Jonathan Protzenko, Ville Voutilainen, Alex Celeste,
	Jakub Łukasiewicz, Douglas McIlroy, Jason Merrill,
	Xavier Del Campo Romero, Siddhesh Poyarekar, DJ Delorie,
	Carlos O'Donell, Stephen Coady, Robert Seacord

[-- Attachment #1: Type: text/plain, Size: 3755 bytes --]


Hi Joseph,

On Wed, Oct 09, 2024 at 05:05:16PM GMT, Joseph Myers wrote:
> On Wed, 9 Oct 2024, Alejandro Colomar wrote:
> 
> > I'm not fabricating, BTW.  Here's a list of off-by-one bugs in login
> > code, precisely due to this size-length naming issue:
> > <https://github.com/shadow-maint/shadow/commit/6551709e96b2bc6f084fdf170ad5bcc11f0038ab>
> > <https://github.com/shadow-maint/shadow/commit/15882a5f904b3c277d73254a6953c1051db55df4>
> 
> Those don't look to me like they're much to do with size/length *naming* 
> confusion.  It's a conceptual confusion about whether the value needed by 
> a particular API includes a null terminator or not, not about what you 
> call size and what you call length.

The documentation of an API starts by its prototype.

	void login_prompt(char *name, int len);
	void login_prompt(char *name, int size);

The former should _not_ include a NUL terminator in the argument.
The latter should.  If those names are meaningless, there are more
chances of being confused.

The bugs were introduced in
<https://github.com/shadow-maint/shadow/commit/3b7cc053872cf4ce77fd74dc037f43f34e951e83>
which changed old code that was misusing the term length for referring
to the size (or number of elements, pedantically), for code that used
the actual size.  The author of the change didn't give much meaning to
the difference between size and length, and thought they were
interchangeable, and so the bugs were introduced.

As long as one has a clear distinction, that wouldn't have happened.

>  As such, a name without "length" 
> wouldn't help, because if you say countof, there would still be the same 
> confusion about whether the bytes you are counting are meant to include a 
> null terminator or not.

There are 3 terms:

-  size:    Size in bytes of an object (possibly an array).
-  length:  Number of non-null characters in a string.
-  n:     Number of elements of an array.

When the array is of char, since sizeof(char)==1, size and n are
interchangeable, and both obviously include the NUL terminator.

If you prefer nelementsof() over countof(), I'm all-in for it.  Just ask
for it, and I'll send a patch using nelementsof().  countof() is a new
term, so it doesn't yet have a meaning (except as given by the
attribute), but it naturally fits more with number of elements.  But
from all of the terms that there are, length is the only one that
doesn't include the NUL, so count is fine.  As long as you don't use
length, it should include the NUL.

> 
> You could maybe avoid some cases of such off-by-one errors by language 
> features that tie an array length more closely to a pointer (such as 
> .IDENTIFIER proposals where IDENTIFIER is required to be const size_t, in 
> cases where a pointer-to-VLA is passed, if there were appropriate 
> constraints to require a matching pair of const size_t object and pointer 
> to [.IDENTIFIER] VLA to be passed from caller to callee - more general 
> versions with such strict requirements about passing matching pairs would 
> be less likely to ensure correct sizes everywhere, and this idea about 
> ensuring matching pairs isn't in N3188, it's an idea combining things from 
> multiple papers).

Yeah, Martin and I have the intention of moving in that direction.

countof() [or whatever the name is] will hopefully soon work on array
parameters.

>  But I think naming is essentially orthogonal to any 
> kind of language feature that might enable reliable bounded pointers.

I still think conceptual confusions like this one (two) start with API
design and documentation, which itself starts in API naming.


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] 318+ messages in thread

* Re: [PATCH v13 0/4] c: Add __lengthof__ operator
  2024-10-09 18:48                       ` Alejandro Colomar
@ 2024-10-09 19:31                         ` Joseph Myers
  2024-10-09 20:25                           ` Alejandro Colomar
  2024-10-09 19:40                         ` Meaning of "length", "size", and "count" Jakub Łukasiewicz
  1 sibling, 1 reply; 318+ messages in thread
From: Joseph Myers @ 2024-10-09 19:31 UTC (permalink / raw)
  To: Alejandro Colomar
  Cc: Chris Bazley, Jakub Jelinek, gcc-patches, Gabriel Ravier,
	Kees Cook, Qing Zhao, David Brown, Florian Weimer,
	Andreas Schwab, Timm Baeder, Daniel Plakosh, A. Jiang,
	Eugene Zelenko, Aaron Ballman, Paul Koning, Daniel Lundin,
	Nikolaos Strimpas, JeanHeyd Meneide, Fernando Borretti,
	Jonathan Protzenko, Ville Voutilainen, Alex Celeste,
	Jakub Łukasiewicz, Douglas McIlroy, Jason Merrill,
	Xavier Del Campo Romero, Siddhesh Poyarekar, DJ Delorie,
	Carlos O'Donell, Stephen Coady, Robert Seacord

On Wed, 9 Oct 2024, Alejandro Colomar wrote:

> The documentation of an API starts by its prototype.
> 
> 	void login_prompt(char *name, int len);
> 	void login_prompt(char *name, int size);
> 
> The former should _not_ include a NUL terminator in the argument.
> The latter should.  If those names are meaningless, there are more
> chances of being confused.

You need actual API *documentation*, not just expecting people to guess 
based on a name.

One of those commit messages refers to non-null-terminated utmp 
structures.  I'd say the actual error-prone antipattern seen here is the 
use of such arrays (fixed width, not necessarily null-terminated) to store 
things that might otherwise be thought of as strings, rather than anything 
to do with naming.

-- 
Joseph S. Myers
josmyers@redhat.com


^ permalink raw reply	[flat|nested] 318+ messages in thread

* Meaning of "length", "size", and "count"
  2024-10-09 18:48                       ` Alejandro Colomar
  2024-10-09 19:31                         ` Joseph Myers
@ 2024-10-09 19:40                         ` Jakub Łukasiewicz
  2024-10-09 20:31                           ` Alejandro Colomar
  1 sibling, 1 reply; 318+ messages in thread
From: Jakub Łukasiewicz @ 2024-10-09 19:40 UTC (permalink / raw)
  To: Alejandro Colomar, Joseph Myers
  Cc: WG14, gcc-patches, Jakub Jelinek, Gabriel Ravier, Kees Cook,
	Qing Zhao, David Brown, Florian Weimer, Andreas Schwab,
	Timm Baeder, A. Jiang, Eugene Zelenko, Paul Koning,
	Daniel Lundin, Nikolaos Strimpas, Fernando Borretti,
	Jonathan Protzenko, Douglas McIlroy, Jason Merrill,
	Xavier Del Campo Romero, Siddhesh Poyarekar, DJ Delorie,
	Carlos O'Donell, Stephen Coady

On 2024-10-09 20:48 CEST, Alejandro Colomar <alx@kernel.org> wrote:
> countof() is a new term, so it doesn't yet have a meaning (except 
> as given by the attribute), but it naturally fits more with number 
> of elements.

How would you call, for example, a function that returns how many 
times a value is contained in a data structure (be it array, linked 
list, or any other)?

~ J.Ł.

^ permalink raw reply	[flat|nested] 318+ messages in thread

* Re: [PATCH v13 0/4] c: Add __lengthof__ operator
  2024-10-09 19:31                         ` Joseph Myers
@ 2024-10-09 20:25                           ` Alejandro Colomar
  2024-10-09 21:11                             ` Joseph Myers
  0 siblings, 1 reply; 318+ messages in thread
From: Alejandro Colomar @ 2024-10-09 20:25 UTC (permalink / raw)
  To: Joseph Myers
  Cc: Chris Bazley, Jakub Jelinek, gcc-patches, Gabriel Ravier,
	Kees Cook, Qing Zhao, David Brown, Florian Weimer,
	Andreas Schwab, Timm Baeder, Daniel Plakosh, A. Jiang,
	Eugene Zelenko, Aaron Ballman, Paul Koning, Daniel Lundin,
	Nikolaos Strimpas, JeanHeyd Meneide, Fernando Borretti,
	Jonathan Protzenko, Ville Voutilainen, Alex Celeste,
	Jakub Łukasiewicz, Douglas McIlroy, Jason Merrill,
	Xavier Del Campo Romero, Siddhesh Poyarekar, DJ Delorie,
	Carlos O'Donell, Stephen Coady, Robert Seacord

[-- Attachment #1: Type: text/plain, Size: 1978 bytes --]

Hi Joseph,

On Wed, Oct 09, 2024 at 07:31:50PM GMT, Joseph Myers wrote:
> On Wed, 9 Oct 2024, Alejandro Colomar wrote:
> 
> > The documentation of an API starts by its prototype.
> > 
> > 	void login_prompt(char *name, int len);
> > 	void login_prompt(char *name, int size);
> > 
> > The former should _not_ include a NUL terminator in the argument.
> > The latter should.  If those names are meaningless, there are more
> > chances of being confused.
> 
> You need actual API *documentation*, not just expecting people to guess 
> based on a name.

Every little bit adds up.  Documentation is simpler if there is naming
consistency.  We have SYNOPSISes in the man pages, and they're up front,
because they constitute an important part of the documentation.

If each manual page used a different naming convention, you'd have to
carefully read each page to understand an API.  And you'd have to be
extra careful about every little detail.

If instead there's a careful consistency across the entire Linux
man-pages project (for example), including naming consistency, you can
read a new page, and have a rough idea of how it works after just a few
looks at the page; hopefully even just by having a look at the SYNOPSIS
plus the first few lines of the DESCRIPTION.  Documentation should not
be surprising, but rather confirm what you already guessed by looking at
the API itself.

> One of those commit messages refers to non-null-terminated utmp 
> structures.  I'd say the actual error-prone antipattern seen here is the 
> use of such arrays (fixed width, not necessarily null-terminated) to store 
> things that might otherwise be thought of as strings, rather than anything 
> to do with naming.

Yeah, utmp(5) didn't help either.

It's hard to quantify how much each problem contributed to the actual
bugs, but I tend to think both factors contributed.


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] 318+ messages in thread

* Re: Meaning of "length", "size", and "count"
  2024-10-09 19:40                         ` Meaning of "length", "size", and "count" Jakub Łukasiewicz
@ 2024-10-09 20:31                           ` Alejandro Colomar
  0 siblings, 0 replies; 318+ messages in thread
From: Alejandro Colomar @ 2024-10-09 20:31 UTC (permalink / raw)
  To: Jakub Łukasiewicz
  Cc: Joseph Myers, WG14, gcc-patches, Jakub Jelinek, Gabriel Ravier,
	Kees Cook, Qing Zhao, David Brown, Florian Weimer,
	Andreas Schwab, Timm Baeder, A. Jiang, Eugene Zelenko,
	Paul Koning, Daniel Lundin, Nikolaos Strimpas, Fernando Borretti,
	Jonathan Protzenko, Douglas McIlroy, Jason Merrill,
	Xavier Del Campo Romero, Siddhesh Poyarekar, DJ Delorie,
	Carlos O'Donell, Stephen Coady

[-- Attachment #1: Type: text/plain, Size: 1232 bytes --]

Hi Jakub,

On Wed, Oct 09, 2024 at 09:40:11PM GMT, Jakub Łukasiewicz wrote:
> On 2024-10-09 20:48 CEST, Alejandro Colomar <alx@kernel.org> wrote:
> > countof() is a new term, so it doesn't yet have a meaning (except as
> > given by the attribute), but it naturally fits more with number of
> > elements.
> 
> How would you call, for example, a function that returns how many times a
> value is contained in a data structure (be it array, linked list, or any
> other)?

list_count() or similar would be a good name.

It's length that's dangerous to overload because (1) it's already used
by strings, and (2) strings have the danger of the NUL terminator which
is not counted by its length.

But for example, it's not dangerous to misuse size for the number of
elements of an array, because they're so obviously different that you'll
not introduce a bug easily.  I think it's okay to say wcslcpy() gets a
size as the third parameter, even if pedantically it's a number of
elements.  So, using "count" for both arrays, and user-defined types
such as linked lists, is just fine.  The only _dangerous_ term is
length.


Have a lovely night!
Alex

> 
> ~ J.Ł.

-- 
<https://www.alejandro-colomar.es/>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 318+ messages in thread

* Re: [PATCH v13 0/4] c: Add __lengthof__ operator
  2024-10-09 20:25                           ` Alejandro Colomar
@ 2024-10-09 21:11                             ` Joseph Myers
  2024-10-09 21:20                               ` Alejandro Colomar
  2024-10-15 10:03                               ` Alejandro Colomar
  0 siblings, 2 replies; 318+ messages in thread
From: Joseph Myers @ 2024-10-09 21:11 UTC (permalink / raw)
  To: Alejandro Colomar
  Cc: Chris Bazley, Jakub Jelinek, gcc-patches, Gabriel Ravier,
	Kees Cook, Qing Zhao, David Brown, Florian Weimer,
	Andreas Schwab, Timm Baeder, Daniel Plakosh, A. Jiang,
	Eugene Zelenko, Aaron Ballman, Paul Koning, Daniel Lundin,
	Nikolaos Strimpas, JeanHeyd Meneide, Fernando Borretti,
	Jonathan Protzenko, Ville Voutilainen, Alex Celeste,
	Jakub Łukasiewicz, Douglas McIlroy, Jason Merrill,
	Xavier Del Campo Romero, Siddhesh Poyarekar, DJ Delorie,
	Carlos O'Donell, Stephen Coady, Robert Seacord

On Wed, 9 Oct 2024, Alejandro Colomar wrote:

> Every little bit adds up.  Documentation is simpler if there is naming
> consistency.  We have SYNOPSISes in the man pages, and they're up front,
> because they constitute an important part of the documentation.

We also have a convention for future standard C interfaces to put the 
length before the pointer so that a VLA parameter declaration can be used 
that makes very clear the intent for how many elements the array has, 
which seems much better for that purpose than relying on the name of a 
parameter.

-- 
Joseph S. Myers
josmyers@redhat.com


^ permalink raw reply	[flat|nested] 318+ messages in thread

* Re: [PATCH v13 0/4] c: Add __lengthof__ operator
  2024-10-09 21:11                             ` Joseph Myers
@ 2024-10-09 21:20                               ` Alejandro Colomar
  2024-10-10  4:13                                 ` Xavier Del Campo Romero
  2024-10-15 10:03                               ` Alejandro Colomar
  1 sibling, 1 reply; 318+ messages in thread
From: Alejandro Colomar @ 2024-10-09 21:20 UTC (permalink / raw)
  To: Joseph Myers
  Cc: Chris Bazley, Jakub Jelinek, gcc-patches, Gabriel Ravier,
	Kees Cook, Qing Zhao, David Brown, Florian Weimer,
	Andreas Schwab, Timm Baeder, Daniel Plakosh, A. Jiang,
	Eugene Zelenko, Aaron Ballman, Paul Koning, Daniel Lundin,
	Nikolaos Strimpas, JeanHeyd Meneide, Fernando Borretti,
	Jonathan Protzenko, Ville Voutilainen, Alex Celeste,
	Jakub Łukasiewicz, Douglas McIlroy, Jason Merrill,
	Xavier Del Campo Romero, Siddhesh Poyarekar, DJ Delorie,
	Carlos O'Donell, Stephen Coady, Robert Seacord

[-- Attachment #1: Type: text/plain, Size: 1091 bytes --]

On Wed, Oct 09, 2024 at 09:11:52PM GMT, Joseph Myers wrote:
> On Wed, 9 Oct 2024, Alejandro Colomar wrote:
> 
> > Every little bit adds up.  Documentation is simpler if there is naming
> > consistency.  We have SYNOPSISes in the man pages, and they're up front,
> > because they constitute an important part of the documentation.
> 
> We also have a convention for future standard C interfaces to put the 
> length before the pointer so that a VLA parameter declaration can be used 
> that makes very clear the intent for how many elements the array has, 
> which seems much better for that purpose than relying on the name of a 
> parameter.

I doubt that this will be doable for string functions.  Even newer
additions to <string.h> will most likely have the size as the last
element, if just for consistency with the existing APIs.  And this issue
is primarily a string issue, so it won't be solved.

[.identifier] is more likely to help with this.

Cheers,
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] 318+ messages in thread

* Re: [PATCH v13 0/4] c: Add __lengthof__ operator
  2024-10-09 21:20                               ` Alejandro Colomar
@ 2024-10-10  4:13                                 ` Xavier Del Campo Romero
  0 siblings, 0 replies; 318+ messages in thread
From: Xavier Del Campo Romero @ 2024-10-10  4:13 UTC (permalink / raw)
  To: Alejandro Colomar
  Cc: Joseph Myers, Chris Bazley, Jakub Jelinek, gcc-patches,
	Gabriel Ravier, Kees Cook, Qing Zhao, David Brown,
	Florian Weimer, Andreas Schwab, Timm Baeder, Daniel Plakosh,
	A. Jiang, Eugene Zelenko, Aaron Ballman, Paul Koning,
	Daniel Lundin, Nikolaos Strimpas, JeanHeyd Meneide,
	Fernando Borretti, Jonathan Protzenko, Ville Voutilainen,
	Alex Celeste, Jakub Łukasiewicz, Douglas McIlroy,
	Jason Merrill, Siddhesh Poyarekar, DJ Delorie,
	Carlos O'Donell, Stephen Coady, Robert Seacord

Hello,

Could you please unCC me from this discussion? Despite I originally made this proposal, I no longer have an opinion on the subject and there is not much I can add to the discussion anyway.

Thank you all very much for your efforts into improving C.

Best regards,
--
Xavier Del Campo Romero



9 Oct 2024, 23:20 by alx@kernel.org:

> On Wed, Oct 09, 2024 at 09:11:52PM GMT, Joseph Myers wrote:
>
>> On Wed, 9 Oct 2024, Alejandro Colomar wrote:
>>
>> > Every little bit adds up.  Documentation is simpler if there is naming
>> > consistency.  We have SYNOPSISes in the man pages, and they're up front,
>> > because they constitute an important part of the documentation.
>>
>> We also have a convention for future standard C interfaces to put the 
>> length before the pointer so that a VLA parameter declaration can be used 
>> that makes very clear the intent for how many elements the array has, 
>> which seems much better for that purpose than relying on the name of a 
>> parameter.
>>
>
> I doubt that this will be doable for string functions.  Even newer
> additions to <string.h> will most likely have the size as the last
> element, if just for consistency with the existing APIs.  And this issue
> is primarily a string issue, so it won't be solved.
>
> [.identifier] is more likely to help with this.
>
> Cheers,
> Alex
>
>>
>> -- 
>> Joseph S. Myers
>> josmyers@redhat.com
>>
>
> -- 
> <https://www.alejandro-colomar.es/>
>

^ permalink raw reply	[flat|nested] 318+ messages in thread

* Re: [PATCH v13 0/4] c: Add __lengthof__ operator
  2024-10-09 21:11                             ` Joseph Myers
  2024-10-09 21:20                               ` Alejandro Colomar
@ 2024-10-15 10:03                               ` Alejandro Colomar
  1 sibling, 0 replies; 318+ messages in thread
From: Alejandro Colomar @ 2024-10-15 10:03 UTC (permalink / raw)
  To: Joseph Myers
  Cc: Chris Bazley, Jakub Jelinek, gcc-patches, Gabriel Ravier,
	Kees Cook, Qing Zhao, David Brown, Florian Weimer,
	Andreas Schwab, Timm Baeder, Daniel Plakosh, A. Jiang,
	Eugene Zelenko, Aaron Ballman, Paul Koning, Daniel Lundin,
	Nikolaos Strimpas, JeanHeyd Meneide, Fernando Borretti,
	Jonathan Protzenko, Ville Voutilainen, Alex Celeste,
	Jakub Łukasiewicz, Douglas McIlroy, Jason Merrill,
	Siddhesh Poyarekar, DJ Delorie, Carlos O'Donell,
	Stephen Coady, Robert Seacord

[-- Attachment #1: Type: text/plain, Size: 1591 bytes --]

Hi Joseph,

On Wed, Oct 09, 2024 at 09:11:52PM GMT, Joseph Myers wrote:
> On Wed, 9 Oct 2024, Alejandro Colomar wrote:
> 
> > Every little bit adds up.  Documentation is simpler if there is naming
> > consistency.  We have SYNOPSISes in the man pages, and they're up front,
> > because they constitute an important part of the documentation.
> 
> We also have a convention for future standard C interfaces to put the 
> length before the pointer so that a VLA parameter declaration can be used 
> that makes very clear the intent for how many elements the array has, 
> which seems much better for that purpose than relying on the name of a 
> parameter.

Just as a confirmation of what I already said: none of the arguments
convince me.  They seem mitigations to the damage that overloading the
term length can do.

I stand on my proposal of either __nelementsof__(), __countof__() (with
no preference), any derivative of those, or almost anything that doesn't
derive from "length" (well, I also veto "dimension", "extent", and
"range", for different reasons, but anything else is fair game).

If you want _Lengthof, please sed(1) it yourself and sign the patch
below my signature.  I don't think you (or myself) can convince me of
changing my mind, so it's up to you to decide what you want to do.

I think it would be good to have this in GCC 15, so if you're convinced
of _Lengthof(), please go ahead already.  I don't think delaying this
further will change the mind of any of us.


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] 318+ messages in thread

* [PATCH v15 0/4] c: Add __countof__ operator
  2024-07-28 14:15 ` [RFC v1 0/2] c: Add _Lengthof operator Alejandro Colomar
                     ` (19 preceding siblings ...)
  2024-10-08  9:11   ` [PATCH v14 0/4] c: Add __countof__ operator Alejandro Colomar
@ 2024-10-16 10:13   ` Alejandro Colomar
  2024-10-16 10:13     ` [PATCH v15 1/4] contrib/: Add support for Cc: and Link: tags Alejandro Colomar
                       ` (3 more replies)
  2024-10-22 18:48   ` [PATCH v17 0/2] " Alejandro Colomar
                     ` (7 subsequent siblings)
  28 siblings, 4 replies; 318+ messages in thread
From: Alejandro Colomar @ 2024-10-16 10:13 UTC (permalink / raw)
  To: gcc-patches; +Cc: Richard Biener

[-- Attachment #1: Type: text/plain, Size: 9718 bytes --]

v15 changes:

-  Rebase.

-  Remove (unused) changes under <gcc/cp/*> and <gcc/target.h>.  It was
   dead code.

-  Fix typos in comments.

-  Make format of changelog more consistent.

-  Add some links and CCs to the commit message.

-  Add Acked-by James K. Lowden.  Quoting him:

	> Just to say, [...], you're absolutely right.  "Size" has a meaning.
	> "Count" has a meaning.  They're equal only if the unit size is 1.
	>
	> "Length" is ambiguous.  Often, it means "size within capacity", as
	> strlen(3).  I cannot think of a single example in C++ where "length"
	> means "number of elements allocated".  The STL uses size to mean count,
	> including std::size, afaik.
	>
	> It is said that in 1956, someone once told Adlai Stevenson,
	> the Democratic presidential candidate, ?Every thinking person in America
	> will vote for you.? Stevenson supposed replied, "That's not enough.
	> I need a majority.?
	>
	> 'Twas always thus.

	> I would go with __countof__().  It's short and unambiguous.

-  Remove some remanent uses of length in documentation and comments.

Alejandro Colomar (4):
  contrib/: Add support for Cc: and Link: tags
  gcc/: Rename array_type_nelts() => array_type_nelts_minus_one()
  Merge definitions of array_type_nelts_top()
  c: Add __countof__ operator

 contrib/gcc-changelog/git_commit.py    |   5 +-
 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                        |  32 ++++--
 gcc/c/c-fold.cc                        |   7 +-
 gcc/c/c-parser.cc                      |  62 +++++++---
 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/tree.cc                         |  13 ---
 gcc/doc/extend.texi                    |  30 +++++
 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/testsuite/gcc.dg/countof-compile.c | 115 +++++++++++++++++++
 gcc/testsuite/gcc.dg/countof-vla.c     |  46 ++++++++
 gcc/testsuite/gcc.dg/countof.c         | 150 +++++++++++++++++++++++++
 gcc/tree.cc                            |  17 ++-
 gcc/tree.h                             |   3 +-
 27 files changed, 600 insertions(+), 80 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/countof-compile.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-vla.c
 create mode 100644 gcc/testsuite/gcc.dg/countof.c

Range-diff against v14:
1:  d7fca49888a = 1:  b6da2185675 contrib/: Add support for Cc: and Link: tags
2:  e65245ac294 = 2:  a0fa3f139f9 gcc/: Rename array_type_nelts() => array_type_nelts_minus_one()
3:  03de2d67bb1 = 3:  43a2e18c6a2 Merge definitions of array_type_nelts_top()
4:  6714852dd93 ! 4:  8a6959d2d38 c: Add __countof__ operator
    @@ Commit message
         gcc/ChangeLog:
     
                 * doc/extend.texi: Document __countof__ operator.
    -            * target.h (enum type_context_kind): Add __countof__ operator.
     
         gcc/c-family/ChangeLog:
     
                 * c-common.h
    -            * c-common.def:
    +            * c-common.def
                 * c-common.cc (c_countof_type): Add __countof__ operator.
     
         gcc/c/ChangeLog:
    @@ Commit message
                 (c_parser_unary_expression)
                 * c-typeck.cc
                 (build_external_ref)
    -            (record_maybe_used_decl, pop_maybe_used)
    +            (record_maybe_used_decl)
    +            (pop_maybe_used)
                 (is_top_array_vla)
                 (c_expr_countof_expr, c_expr_countof_type):
                 Add __countof__operator.
     
    -    gcc/cp/ChangeLog:
    -
    -            * operators.def: Add __countof__ operator.
    -
         gcc/testsuite/ChangeLog:
     
                 * gcc.dg/countof-compile.c
                 * gcc.dg/countof-vla.c
                 * gcc.dg/countof.c: Add tests for __countof__ operator.
     
    +    Link: <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117025>
    +    Link: <https://inbox.sourceware.org/gcc/M8S4oQy--3-2@tutanota.com/T/>
    +    Link: <https://inbox.sourceware.org/gcc-patches/20240728141547.302478-1-alx@kernel.org/T/#t>
         Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3313.pdf>
         Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3325.pdf>
         Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3369.pdf>
    -    Link: <https://inbox.sourceware.org/gcc/M8S4oQy--3-2@tutanota.com/T/>
         Link: <https://github.com/llvm/llvm-project/issues/102836>
    +    Link: <https://stackoverflow.com/questions/37538/#57537491>
    +    Suggested-by: Xavier Del Campo Romero <xavi.dcr@tutanota.com>
    +    Co-authored-by: Martin Uecker <uecker@tugraz.at>
    +    Acked-by: "James K. Lowden" <jklowden@schemamania.org>
         Cc: Joseph Myers <josmyers@redhat.com>
         Cc: Gabriel Ravier <gabravier@gmail.com>
         Cc: Jakub Jelinek <jakub@redhat.com>
    @@ Commit message
         Cc: Jakub Łukasiewicz <jakublukasiewicz@outlook.com>
         Cc: Douglas McIlroy <douglas.mcilroy@dartmouth.edu>
         Cc: Jason Merrill <jason@redhat.com>
    -    Suggested-by: Xavier Del Campo Romero <xavi.dcr@tutanota.com>
    -    Co-authored-by: Martin Uecker <uecker@tugraz.at>
    +    Cc: "Gustavo A. R. Silva" <gustavoars@kernel.org>
    +    Cc: Patrizia Kaye <patrizia@ethernull.org>
    +    Cc: Ori Bernstein <ori@eigenstate.org>
    +    Cc: Robert Seacord <rcseacord@gmail.com>
    +    Cc: Marek Polacek <mpolacek@gcc.gnu.org>
    +    Cc: Sam James <sam@gentoo.org>
         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)
        return fold_convert_loc (loc, size_type_node, t);
      }
     +
    -+/* Implement the lementsof keyword:
    ++/* Implement the countof keyword:
     +   Return the number of elements of an array.  */
     +
     +tree
    @@ 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 countof 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 countof call is inside
    -+	 another array declarator.  */
    ++	 c_fully_fold, because if the number of elements is evaluated
    ++	 the result is not constant and so
    ++	 constraints on zero or negative size arrays must not be applied
    ++	 when this countof 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),
    @@ gcc/c/c-typeck.cc: c_expr_sizeof_type (location_t loc, struct c_type_name *t)
         The function call is at LOC.
         PARAMS is a list--a chain of TREE_LIST nodes--in which the
     
    - ## gcc/cp/operators.def ##
    -@@ gcc/cp/operators.def: 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 ("__countof__", COUNTOF_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/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
    @@ gcc/doc/extend.texi: If the operand of the @code{__alignof__} expression is a fu
     +@cindex countof
     +@cindex number of elements
     +
    -+The keyword @code{__countof__} determines the length of an array operand,
    -+that is, the number of elements in the array.
    ++The keyword @code{__countof__} determines
    ++the number of elements of an array operand.
     +Its syntax is similar to @code{sizeof}.
     +The operand must be
     +a parenthesized complete array type name
    @@ gcc/doc/extend.texi: If the operand of the @code{__alignof__} expression is a fu
      @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.  */
    -   TCTX_ALIGNOF,
    - 
    -+  /* Directly measuring the number of elements of array T.  */
    -+  TCTX_COUNTOF,
    -+
    -   /* Creating objects of type T with static storage duration.  */
    -   TCTX_STATIC_STORAGE,
    - 
    -
      ## gcc/testsuite/gcc.dg/countof-compile.c (new) ##
     @@
     +/* { dg-do compile } */

base-commit: 9cbcf8d1de159e6113fafb5dc2feb4a7e467a302
-- 
2.45.2


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 318+ messages in thread

* [PATCH v15 1/4] contrib/: Add support for Cc: and Link: tags
  2024-10-16 10:13   ` [PATCH v15 0/4] " Alejandro Colomar
@ 2024-10-16 10:13     ` Alejandro Colomar
  2024-10-16 10:13     ` [PATCH v15 2/4] gcc/: Rename array_type_nelts() => array_type_nelts_minus_one() Alejandro Colomar
                       ` (2 subsequent siblings)
  3 siblings, 0 replies; 318+ messages in thread
From: Alejandro Colomar @ 2024-10-16 10:13 UTC (permalink / raw)
  To: gcc-patches; +Cc: Richard Biener

[-- Attachment #1: Type: text/plain, Size: 1258 bytes --]

contrib/ChangeLog:

	* gcc-changelog/git_commit.py (GitCommit):
	Add support for 'Cc: ' and 'Link: ' tags.

Cc: Jason Merrill <jason@redhat.com>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
---
 contrib/gcc-changelog/git_commit.py | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/contrib/gcc-changelog/git_commit.py b/contrib/gcc-changelog/git_commit.py
index 87ecb9e1a17..64fb986b74c 100755
--- a/contrib/gcc-changelog/git_commit.py
+++ b/contrib/gcc-changelog/git_commit.py
@@ -182,7 +182,8 @@ CO_AUTHORED_BY_PREFIX = 'co-authored-by: '
 
 REVIEW_PREFIXES = ('reviewed-by: ', 'reviewed-on: ', 'signed-off-by: ',
                    'acked-by: ', 'tested-by: ', 'reported-by: ',
-                   'suggested-by: ')
+                   'suggested-by: ', 'cc: ')
+LINK_PREFIXES = ('link: ')
 DATE_FORMAT = '%Y-%m-%d'
 
 
@@ -524,6 +525,8 @@ class GitCommit:
                     continue
                 elif lowered_line.startswith(REVIEW_PREFIXES):
                     continue
+                elif lowered_line.startswith(LINK_PREFIXES):
+                    continue
                 else:
                     m = cherry_pick_regex.search(line)
                     if m:
-- 
2.45.2


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 318+ messages in thread

* [PATCH v15 2/4] gcc/: Rename array_type_nelts() => array_type_nelts_minus_one()
  2024-10-16 10:13   ` [PATCH v15 0/4] " Alejandro Colomar
  2024-10-16 10:13     ` [PATCH v15 1/4] contrib/: Add support for Cc: and Link: tags Alejandro Colomar
@ 2024-10-16 10:13     ` Alejandro Colomar
  2024-10-16 10:34       ` Joseph Myers
  2024-10-16 10:13     ` [PATCH v15 3/4] Merge definitions of array_type_nelts_top() Alejandro Colomar
  2024-10-16 10:13     ` [PATCH v15 4/4] c: Add __countof__ operator Alejandro Colomar
  3 siblings, 1 reply; 318+ messages in thread
From: Alejandro Colomar @ 2024-10-16 10:13 UTC (permalink / raw)
  To: gcc-patches; +Cc: Richard Biener

[-- Attachment #1: Type: text/plain, Size: 12749 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>

gcc/ChangeLog:

	* tree.cc (array_type_nelts, array_type_nelts_minus_one)
	* tree.h (array_type_nelts, array_type_nelts_minus_one)
	* expr.cc (count_type_elements)
	* config/aarch64/aarch64.cc
	(pure_scalable_type_info::analyze_array)
	* config/i386/i386.cc (ix86_canonical_va_list_type):
	Rename array_type_nelts() => array_type_nelts_minus_one()
	The old name was misleading.

gcc/c/ChangeLog:

	* c-decl.cc (one_element_array_type_p, get_parm_array_spec)
	* c-fold.cc (c_fold_array_ref):
	Rename array_type_nelts() => array_type_nelts_minus_one()

gcc/cp/ChangeLog:

	* decl.cc (reshape_init_array)
	* init.cc
	(build_zero_init_1)
	(build_value_init_noctor)
	(build_vec_init)
	(build_delete)
	* lambda.cc (add_capture)
	* tree.cc (array_type_nelts_top):
	Rename array_type_nelts() => array_type_nelts_minus_one()

gcc/fortran/ChangeLog:

	* trans-array.cc (structure_alloc_comps)
	* trans-openmp.cc
	(gfc_walk_alloc_comps)
	(gfc_omp_clause_linear_ctor):
	Rename array_type_nelts() => array_type_nelts_minus_one()

gcc/rust/ChangeLog:

	* backend/rust-tree.cc (array_type_nelts_top):
	Rename array_type_nelts() => array_type_nelts_minus_one()

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>
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 224c015cd6d..a03f756bf33 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -5358,7 +5358,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]".  */
@@ -6306,15 +6306,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 102680a0efc..443e0525f6f 100644
--- a/gcc/config/aarch64/aarch64.cc
+++ b/gcc/config/aarch64/aarch64.cc
@@ -1081,7 +1081,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 ab0ade3790f..97ebf193b8b 100644
--- a/gcc/config/i386/i386.cc
+++ b/gcc/config/i386/i386.cc
@@ -24629,7 +24629,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 0c5b5c06a12..7281818be8f 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -6956,7 +6956,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 f785015e477..10b83efa850 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.  */
@@ -4526,7 +4526,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;
@@ -5191,7 +5191,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 e17c00217b2..d51b513f0fa 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 0a7a56cc6e2..3cac8ac4df1 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -3085,7 +3085,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 7a471f20e79..9bc1f58e178 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 0b8ef0b5e01..160a543bda2 100644
--- a/gcc/fortran/trans-array.cc
+++ b/gcc/fortran/trans-array.cc
@@ -9695,7 +9695,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 3a335ade0f7..e994cad81d8 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 095c02c5474..582368934ef 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;
 
@@ -14788,7 +14788,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 75efc760a16..921c3f61da8 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] 318+ messages in thread

* [PATCH v15 3/4] Merge definitions of array_type_nelts_top()
  2024-10-16 10:13   ` [PATCH v15 0/4] " Alejandro Colomar
  2024-10-16 10:13     ` [PATCH v15 1/4] contrib/: Add support for Cc: and Link: tags Alejandro Colomar
  2024-10-16 10:13     ` [PATCH v15 2/4] gcc/: Rename array_type_nelts() => array_type_nelts_minus_one() Alejandro Colomar
@ 2024-10-16 10:13     ` Alejandro Colomar
  2024-10-16 10:13     ` [PATCH v15 4/4] c: Add __countof__ operator Alejandro Colomar
  3 siblings, 0 replies; 318+ messages in thread
From: Alejandro Colomar @ 2024-10-16 10:13 UTC (permalink / raw)
  To: gcc-patches; +Cc: Richard Biener

[-- Attachment #1: Type: text/plain, Size: 4880 bytes --]

There were two identical definitions, and none of them are available
where they are needed for implementing __nelementsof__.  Merge them, and
provide the single definition in gcc/tree.{h,cc}, where it's available
for __nelementsof__, 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 dc153a97dc4..c89f5ea905a 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -8120,7 +8120,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 3cac8ac4df1..c80ee068958 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -3076,19 +3076,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 582368934ef..aef8e19ec67 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 921c3f61da8..d8203f1c7d1 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] 318+ messages in thread

* [PATCH v15 4/4] c: Add __countof__ operator
  2024-10-16 10:13   ` [PATCH v15 0/4] " Alejandro Colomar
                       ` (2 preceding siblings ...)
  2024-10-16 10:13     ` [PATCH v15 3/4] Merge definitions of array_type_nelts_top() Alejandro Colomar
@ 2024-10-16 10:13     ` Alejandro Colomar
  2024-10-16 10:30       ` Joseph Myers
  3 siblings, 1 reply; 318+ messages in thread
From: Alejandro Colomar @ 2024-10-16 10:13 UTC (permalink / raw)
  To: gcc-patches; +Cc: Richard Biener

[-- Attachment #1: Type: text/plain, Size: 29733 bytes --]

This operator is similar to sizeof but can only be applied to an array,
and returns its number of elements.

FUTURE DIRECTIONS:

-  We should make it work with array parameters to functions,
   and somehow magically return the number of elements of the array,
   regardless of it being really a pointer.

-  Fix support for [0].

gcc/ChangeLog:

	* doc/extend.texi: Document __countof__ operator.

gcc/c-family/ChangeLog:

	* c-common.h
	* c-common.def
	* c-common.cc (c_countof_type): Add __countof__ operator.

gcc/c/ChangeLog:

	* c-tree.h
	(c_expr_countof_expr, c_expr_countof_type)
	* c-decl.cc
	(start_struct, finish_struct)
	(start_enum, finish_enum)
	* c-parser.cc
	(c_parser_sizeof_expression)
	(c_parser_countof_expression)
	(c_parser_sizeof_or_countof_expression)
	(c_parser_unary_expression)
	* c-typeck.cc
	(build_external_ref)
	(record_maybe_used_decl)
	(pop_maybe_used)
	(is_top_array_vla)
	(c_expr_countof_expr, c_expr_countof_type):
	Add __countof__operator.

gcc/testsuite/ChangeLog:

	* gcc.dg/countof-compile.c
	* gcc.dg/countof-vla.c
	* gcc.dg/countof.c: Add tests for __countof__ operator.

Link: <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117025>
Link: <https://inbox.sourceware.org/gcc/M8S4oQy--3-2@tutanota.com/T/>
Link: <https://inbox.sourceware.org/gcc-patches/20240728141547.302478-1-alx@kernel.org/T/#t>
Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3313.pdf>
Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3325.pdf>
Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3369.pdf>
Link: <https://github.com/llvm/llvm-project/issues/102836>
Link: <https://stackoverflow.com/questions/37538/#57537491>
Suggested-by: Xavier Del Campo Romero <xavi.dcr@tutanota.com>
Co-authored-by: Martin Uecker <uecker@tugraz.at>
Acked-by: "James K. Lowden" <jklowden@schemamania.org>
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>
Cc: Daniel Plakosh <dplakosh@cert.org>
Cc: "A. Jiang" <de34@live.cn>
Cc: Eugene Zelenko <eugene.zelenko@gmail.com>
Cc: Aaron Ballman <aaron.ballman@intel.com>
Cc: Paul Koning <paulkoning@comcast.net>
Cc: Daniel Lundin <daniel.lundin.mail@gmail.com>
Cc: Nikolaos Strimpas <Strnik86@protonmail.com>
Cc: JeanHeyd Meneide <phdofthehouse@gmail.com>
Cc: Fernando Borretti <fernando@borretti.me>
Cc: Jonathan Protzenko <jonathan.protzenko@ens-lyon.org>
Cc: Chris Bazley <Chris.Bazley@arm.com>
Cc: Ville Voutilainen <ville.voutilainen@gmail.com>
Cc: Alex Celeste <alexg.nvfp@gmail.com>
Cc: Jakub Łukasiewicz <jakublukasiewicz@outlook.com>
Cc: Douglas McIlroy <douglas.mcilroy@dartmouth.edu>
Cc: Jason Merrill <jason@redhat.com>
Cc: "Gustavo A. R. Silva" <gustavoars@kernel.org>
Cc: Patrizia Kaye <patrizia@ethernull.org>
Cc: Ori Bernstein <ori@eigenstate.org>
Cc: Robert Seacord <rcseacord@gmail.com>
Cc: Marek Polacek <mpolacek@gcc.gnu.org>
Cc: Sam James <sam@gentoo.org>
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                        |  22 +++-
 gcc/c/c-parser.cc                      |  62 +++++++---
 gcc/c/c-tree.h                         |   4 +
 gcc/c/c-typeck.cc                      | 118 ++++++++++++++++++-
 gcc/doc/extend.texi                    |  30 +++++
 gcc/testsuite/gcc.dg/countof-compile.c | 115 +++++++++++++++++++
 gcc/testsuite/gcc.dg/countof-vla.c     |  46 ++++++++
 gcc/testsuite/gcc.dg/countof.c         | 150 +++++++++++++++++++++++++
 11 files changed, 554 insertions(+), 24 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/countof-compile.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-vla.c
 create mode 100644 gcc/testsuite/gcc.dg/countof.c

diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
index ec6a5da892d..5e374d56a87 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 },
+  { "__countof__",	RID_COUNTOF,	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 countof keyword:
+   Return the number of elements of an array.  */
+
+tree
+c_countof_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 %<countof%> to type %qT", type);
+      return error_mark_node;
+    }
+  if (!COMPLETE_TYPE_P (type))
+    {
+      error_at (loc,
+		"invalid application of %<countof%> 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..3d882e70cc0 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 'countof' expression.  */
+DEFTREECODE (COUNTOF_EXPR, "countof_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 027f077d51b..5d2cb158d54 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_COUNTOF,
   RID_VA_ARG,
   RID_EXTENSION, RID_IMAGPART, RID_REALPART, RID_LABEL,    RID_CHOOSE_EXPR,
   RID_TYPES_COMPATIBLE_P,      RID_BUILTIN_COMPLEX,	   RID_BUILTIN_SHUFFLE,
@@ -888,6 +889,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_countof_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 a03f756bf33..3733966d51b 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -8992,12 +8992,17 @@ 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_countof))
     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"
+		       : "countof"))));
 
   if (in_underspecified_init)
     error_at (loc, "%qT defined in underspecified object initializer", ref);
@@ -9961,7 +9966,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_countof)
 	struct_parse_info->struct_types.safe_push (t);
      }
 
@@ -10135,12 +10140,17 @@ 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_countof))
     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"
+		       : "countof"))));
 
   if (in_underspecified_init)
     error_at (loc, "%qT defined in underspecified object initializer",
@@ -10334,7 +10344,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_countof)
     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 fe01f955e21..ffd8d6eafe7 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_countof_expression (parser, RID_SIZEOF)                  \
+)
 
+#define c_parser_countof_expression(parser)                                   \
+(                                                                             \
+  c_parser_sizeof_or_countof_expression (parser, RID_COUNTOF)                 \
+)
+\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,8 @@ 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_countof_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 *,
@@ -9910,6 +9921,8 @@ c_parser_unary_expression (c_parser *parser)
     case CPP_KEYWORD:
       switch (c_parser_peek_token (parser)->keyword)
 	{
+	case RID_COUNTOF:
+	  return c_parser_countof_expression (parser);
 	case RID_SIZEOF:
 	  return c_parser_sizeof_expression (parser);
 	case RID_ALIGNOF:
@@ -9949,12 +9962,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_countof_expression (c_parser *parser, enum rid rid)
 {
+  const char *op_name = (rid == RID_COUNTOF) ? "countof" : "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;
@@ -9963,7 +9977,10 @@ c_parser_sizeof_expression (c_parser *parser)
 
   c_parser_consume_token (parser);
   c_inhibit_evaluation_warnings++;
-  in_sizeof++;
+  if (rid == RID_COUNTOF)
+    in_countof++;
+  else
+    in_sizeof++;
   if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)
       && c_token_starts_compound_literal (c_parser_peek_2nd_token (parser)))
     {
@@ -9982,7 +9999,10 @@ c_parser_sizeof_expression (c_parser *parser)
 	{
 	  struct c_expr ret;
 	  c_inhibit_evaluation_warnings--;
-	  in_sizeof--;
+	  if (rid == RID_COUNTOF)
+	    in_countof--;
+	  else
+	    in_sizeof--;
 	  ret.set_error ();
 	  ret.original_code = ERROR_MARK;
 	  ret.original_type = NULL;
@@ -9994,31 +10014,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_COUNTOF)
+	{
+	  in_countof--;
+	  result = c_expr_countof_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_COUNTOF)
+	in_countof--;
+      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_COUNTOF)
+	result = c_expr_countof_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 b3e7bb013b6..22d289c2db6 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_countof;
 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_countof_expr (location_t, struct c_expr);
+extern struct c_expr c_expr_countof_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 ba6d96d26b2..ad7d71031a4 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 "countof".  */
+int in_countof;
+
 /* The level of nesting inside "typeof".  */
 int in_typeof;
 
@@ -3258,7 +3261,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_countof)
 	C_DECL_USED (ref) = 1;
       else if (DECL_INITIAL (ref) == NULL_TREE
 	       && DECL_EXTERNAL (ref)
@@ -3314,7 +3317,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_countof).  */
   int level;
   /* The next one at this level or above, or NULL.  */
   struct maybe_used_decl *next;
@@ -3332,7 +3335,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_countof;
   t->next = maybe_used_decls;
   maybe_used_decls = t;
 }
@@ -3346,7 +3349,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_countof;
   while (p && p->level > cur_level)
     {
       if (used)
@@ -3456,6 +3459,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 countof applied to EXPR.  */
+
+struct c_expr
+c_expr_countof_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_countof_type (loc, TREE_TYPE (folded_expr));
+      c_last_sizeof_arg = expr.value;
+      c_last_sizeof_loc = loc;
+      ret.original_code = COUNTOF_EXPR;
+      ret.original_type = NULL;
+      ret.m_decimal = 0;
+      if (is_top_array_vla (TREE_TYPE (folded_expr)))
+	{
+	  /* countof 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 countof applied to T, a structure for the type
+   name passed to countof (rather than the type itself).  LOC is the
+   location of the original expression.  */
+
+struct c_expr
+c_expr_countof_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_countof_type (loc, type);
+  c_last_sizeof_arg = type;
+  c_last_sizeof_loc = loc;
+  ret.original_code = COUNTOF_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 countof does not get folded to a constant by
+	 c_fully_fold, because if the number of elements is evaluated
+	 the result is not constant and so
+	 constraints on zero or negative size arrays must not be applied
+	 when this countof 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/doc/extend.texi b/gcc/doc/extend.texi
index 302c3299ede..82f31668e37 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -10555,6 +10555,36 @@ 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 countof
+@section Determining the Number of Elements of Arrays
+@cindex countof
+@cindex number of elements
+
+The keyword @code{__countof__} determines
+the number of elements of an array operand.
+Its syntax is similar to @code{sizeof}.
+The operand must be
+a parenthesized complete array type name
+or an expression of such a type.
+For example:
+
+@smallexample
+int a[n];
+__countof__ (a);  // returns n
+__countof__ (int [7][3]);  // returns 7
+@end smallexample
+
+The result of this operator is an integer constant expression,
+unless the array has a variable number of elements.
+The operand is only evaluated
+if the array has a variable number of elements.
+For example:
+
+@smallexample
+__countof__ (int [7][n++]);  // integer constant expression
+__countof__ (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/testsuite/gcc.dg/countof-compile.c b/gcc/testsuite/gcc.dg/countof-compile.c
new file mode 100644
index 00000000000..6e2592edbb0
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/countof-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[__countof__(z)];
+
+void
+automatic(void)
+{
+  __countof__ (w);
+}
+
+void
+incomplete (int p[])
+{
+  __countof__ (x);  /* { dg-error "incomplete" } */
+
+  /* We want to support the following one in the future,
+     but for now it should fail.  */
+  __countof__ (p);  /* { dg-error "invalid" } */
+}
+
+void
+fam (void)
+{
+  struct {
+    int x;
+    int fam[];
+  } s;
+
+  __countof__ (s.fam); /* { dg-error "incomplete" } */
+}
+
+void fix_fix (int i, char (*a)[3][5], int (*x)[__countof__ (*a)]);
+void fix_var (int i, char (*a)[3][i], int (*x)[__countof__ (*a)]);
+void fix_uns (int i, char (*a)[3][*], int (*x)[__countof__ (*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;
+
+  __countof__ (x); /* { dg-error "invalid" } */
+  __countof__ (int); /* { dg-error "invalid" } */
+  __countof__ (s); /* { dg-error "invalid" } */
+  __countof__ (struct s); /* { dg-error "invalid" } */
+  __countof__ (&x); /* { dg-error "invalid" } */
+  __countof__ (p); /* { dg-error "invalid" } */
+  __countof__ (int *); /* { dg-error "invalid" } */
+  __countof__ (&s.x); /* { dg-error "invalid" } */
+  __countof__ (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];
+
+  __countof__ (a[f1()]);
+  __countof__ (b[f2()]);
+}
+
+void
+no_parens(void)
+{
+  __countof__ a;
+  __countof__ *a;
+  __countof__ (int [3]) {};
+
+  __countof__ int [3]; /* { dg-error "expected expression before" } */
+}
+
+void
+const_expr(void)
+{
+  int n = 7;
+
+  _Static_assert (__countof__ (int [3][n]) == 3);
+  _Static_assert (__countof__ (int [n][3]) == 7); /* { dg-error "not constant" } */
+  _Static_assert (__countof__ (int [0][3]) == 0);
+  _Static_assert (__countof__ (int [0]) == 0);
+
+  /* FIXME: countof(int [0][n]) should result in a constant expression.  */
+  _Static_assert (__countof__ (int [0][n]) == 0); /* { dg-error "not constant" } */
+}
diff --git a/gcc/testsuite/gcc.dg/countof-vla.c b/gcc/testsuite/gcc.dg/countof-vla.c
new file mode 100644
index 00000000000..5a82aeed782
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/countof-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)[__countof__ (*a)]);
+void fix_var (int i,
+	      char (*a)[3][i], /* dg-warn "variable" */
+	      int (*x)[__countof__ (*a)]);
+void fix_uns (int i,
+	      char (*a)[3][*],
+	      int (*x)[__countof__ (*a)]);
+
+void zro_fix (int i,
+	      char (*a)[0][5],
+	      int (*x)[__countof__ (*a)]);
+void zro_var (int i,
+	      char (*a)[0][i], /* dg-warn "variable" */
+	      int (*x)[__countof__ (*a)]);
+void zro_uns (int i,
+	      char (*a)[0][*],
+	      int (*x)[__countof__ (*a)]);
+
+void var_fix (int i,
+	      char (*a)[i][5], /* dg-warn "variable" */
+	      int (*x)[__countof__ (*a)]); /* dg-warn "variable" */
+void var_var (int i,
+	      char (*a)[i][i], /* dg-warn "variable" */
+	      int (*x)[__countof__ (*a)]); /* dg-warn "variable" */
+void var_uns (int i,
+	      char (*a)[i][*], /* dg-warn "variable" */
+	      int (*x)[__countof__ (*a)]); /* dg-warn "variable" */
+
+void uns_fix (int i,
+	      char (*a)[*][5],
+	      int (*x)[__countof__ (*a)]);
+void uns_var (int i,
+	      char (*a)[*][i], /* dg-warn "variable" */
+	      int (*x)[__countof__ (*a)]);
+void uns_uns (int i,
+	      char (*a)[*][*],
+	      int (*x)[__countof__ (*a)]);
+
+// Can't test due to bug: <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=116284>
+//static int z2[0];
+//static int y2[__countof__(z2)];
diff --git a/gcc/testsuite/gcc.dg/countof.c b/gcc/testsuite/gcc.dg/countof.c
new file mode 100644
index 00000000000..063a207fb6b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/countof.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 (__countof__ (a) == 7);
+  static_assert (__countof__ (long [0]) == 0);
+  static_assert (__countof__ (unsigned [99]) == 99);
+}
+
+void
+automatic(void)
+{
+  int a[] = {1, 2, 3};
+  int z[] = {};
+
+  static_assert (__countof__ (a) == 3);
+  static_assert (__countof__ (z) == 0);
+}
+
+void
+vla (void)
+{
+  unsigned n;
+
+  n = 99;
+  assert (__countof__ (short [n - 10]) == 99 - 10);
+
+  int v[n / 2];
+  assert (__countof__ (v) == 99 / 2);
+
+  n = 0;
+  int z[n];
+  assert (__countof__ (z) == 0);
+}
+
+void
+member (void)
+{
+  struct {
+    int a[8];
+  } s;
+
+  static_assert (__countof__ (s.a) == 8);
+}
+
+void
+vla_eval (void)
+{
+  int i;
+
+  i = 7;
+  assert (__countof__ (struct {int x;}[i++]) == 7);
+  assert (i == 7 + 1);
+
+  int v[i];
+  int (*p)[i];
+  p = &v;
+  assert (__countof__ (*p++) == i);
+  assert (p - 1 == &v);
+}
+
+void
+inner_vla_noeval (void)
+{
+  int i;
+
+  i = 3;
+  static_assert (__countof__ (struct {int x[i++];}[3]) == 3);
+  assert (i == 3);
+}
+
+void
+array_noeval (void)
+{
+  long a[5];
+  long (*p)[__countof__ (a)];
+
+  p = &a;
+  static_assert (__countof__ (*p++) == 5);
+  assert (p == &a);
+}
+
+void
+matrix_zero (void)
+{
+  int i;
+
+  static_assert (__countof__ (int [0][4]) == 0);
+  i = 3;
+  assert (__countof__ (int [0][i]) == 0);
+}
+
+void
+matrix_fixed (void)
+{
+  int i;
+
+  static_assert (__countof__ (int [7][4]) == 7);
+  i = 3;
+  static_assert (__countof__ (int [7][i]) == 7);
+}
+
+void
+matrix_vla (void)
+{
+  int i, j;
+
+  i = 7;
+  assert (__countof__ (int [i++][4]) == 7);
+  assert (i == 7 + 1);
+
+  i = 9;
+  j = 3;
+  assert (__countof__ (int [i++][j]) == 9);
+  assert (i == 9 + 1);
+}
+
+void
+no_parens(void)
+{
+  int n = 3;
+  int a[7];
+  int v[n];
+
+  static_assert (__countof__ a == 7); 
+  assert (__countof__ 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] 318+ messages in thread

* Re: [PATCH v15 4/4] c: Add __countof__ operator
  2024-10-16 10:13     ` [PATCH v15 4/4] c: Add __countof__ operator Alejandro Colomar
@ 2024-10-16 10:30       ` Joseph Myers
  2024-10-16 10:46         ` Alejandro Colomar
  0 siblings, 1 reply; 318+ messages in thread
From: Joseph Myers @ 2024-10-16 10:30 UTC (permalink / raw)
  To: Alejandro Colomar; +Cc: gcc-patches, Richard Biener

On Wed, 16 Oct 2024, Alejandro Colomar wrote:

> +  if (type_code != ARRAY_TYPE)
> +    {
> +      error_at (loc, "invalid application of %<countof%> to type %qT", type);
> +      return error_mark_node;
> +    }
> +  if (!COMPLETE_TYPE_P (type))
> +    {
> +      error_at (loc,
> +		"invalid application of %<countof%> to incomplete type %qT",

It is never appropriate, regardless of the actual operator naming, for a 
diagnostic to refer to an operator name that doesn't exist at all (such as 
countof instead of __countof__ in this patch).

> @@ -8992,12 +8992,17 @@ 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_countof))
>      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"
> +		       : "countof"))));

Likewise.

> @@ -10135,12 +10140,17 @@ 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_countof))
>      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"
> +		       : "countof"))));

Likewise.

>  static struct c_expr
> -c_parser_sizeof_expression (c_parser *parser)
> +c_parser_sizeof_or_countof_expression (c_parser *parser, enum rid rid)
>  {
> +  const char *op_name = (rid == RID_COUNTOF) ? "countof" : "sizeof";

Likewise.

> diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
> index 302c3299ede..82f31668e37 100644
> --- a/gcc/doc/extend.texi
> +++ b/gcc/doc/extend.texi
> @@ -10555,6 +10555,36 @@ 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 countof
> +@section Determining the Number of Elements of Arrays
> +@cindex countof
> +@cindex number of elements

Likewise, for node name and index entry.

-- 
Joseph S. Myers
josmyers@redhat.com


^ permalink raw reply	[flat|nested] 318+ messages in thread

* Re: [PATCH v15 2/4] gcc/: Rename array_type_nelts() => array_type_nelts_minus_one()
  2024-10-16 10:13     ` [PATCH v15 2/4] gcc/: Rename array_type_nelts() => array_type_nelts_minus_one() Alejandro Colomar
@ 2024-10-16 10:34       ` Joseph Myers
  2024-10-16 10:45         ` Alejandro Colomar
  2024-10-16 10:53         ` Alejandro Colomar
  0 siblings, 2 replies; 318+ messages in thread
From: Joseph Myers @ 2024-10-16 10:34 UTC (permalink / raw)
  To: Alejandro Colomar; +Cc: gcc-patches, Richard Biener

On Wed, 16 Oct 2024, Alejandro Colomar wrote:

> The old name was misleading.
> 
> While at it, also rename some temporary variables that are used with
> this function, for consistency.

This patch is OK.  Note that in ChangeLog entries as in other 
documentation, a function is referred to just as function_name, not as 
function_name().

-- 
Joseph S. Myers
josmyers@redhat.com


^ permalink raw reply	[flat|nested] 318+ messages in thread

* Re: [PATCH v15 2/4] gcc/: Rename array_type_nelts() => array_type_nelts_minus_one()
  2024-10-16 10:34       ` Joseph Myers
@ 2024-10-16 10:45         ` Alejandro Colomar
  2024-10-16 10:53         ` Alejandro Colomar
  1 sibling, 0 replies; 318+ messages in thread
From: Alejandro Colomar @ 2024-10-16 10:45 UTC (permalink / raw)
  To: Joseph Myers; +Cc: gcc-patches, Richard Biener

[-- Attachment #1: Type: text/plain, Size: 539 bytes --]

Hi Joseph,

On Wed, Oct 16, 2024 at 10:34:21AM GMT, Joseph Myers wrote:
> On Wed, 16 Oct 2024, Alejandro Colomar wrote:
> 
> > The old name was misleading.
> > 
> > While at it, also rename some temporary variables that are used with
> > this function, for consistency.
> 
> This patch is OK.  Note that in ChangeLog entries as in other 
> documentation, a function is referred to just as function_name, not as 
> function_name().

Thanks!  I'll fix that in v16.

Cheers,
Alex

-- 
<https://www.alejandro-colomar.es/>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 318+ messages in thread

* Re: [PATCH v15 4/4] c: Add __countof__ operator
  2024-10-16 10:30       ` Joseph Myers
@ 2024-10-16 10:46         ` Alejandro Colomar
  0 siblings, 0 replies; 318+ messages in thread
From: Alejandro Colomar @ 2024-10-16 10:46 UTC (permalink / raw)
  To: Joseph Myers; +Cc: gcc-patches, Richard Biener

[-- Attachment #1: Type: text/plain, Size: 3307 bytes --]

Hi Joseph,

On Wed, Oct 16, 2024 at 10:30:36AM GMT, Joseph Myers wrote:
> On Wed, 16 Oct 2024, Alejandro Colomar wrote:
> 
> > +  if (type_code != ARRAY_TYPE)
> > +    {
> > +      error_at (loc, "invalid application of %<countof%> to type %qT", type);
> > +      return error_mark_node;
> > +    }
> > +  if (!COMPLETE_TYPE_P (type))
> > +    {
> > +      error_at (loc,
> > +		"invalid application of %<countof%> to incomplete type %qT",
> 
> It is never appropriate, regardless of the actual operator naming, for a 
> diagnostic to refer to an operator name that doesn't exist at all (such as 
> countof instead of __countof__ in this patch).

Thanks.  I'll fix that.

Cheers,
Alex

> 
> > @@ -8992,12 +8992,17 @@ 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_countof))
> >      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"
> > +		       : "countof"))));
> 
> Likewise.
> 
> > @@ -10135,12 +10140,17 @@ 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_countof))
> >      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"
> > +		       : "countof"))));
> 
> Likewise.
> 
> >  static struct c_expr
> > -c_parser_sizeof_expression (c_parser *parser)
> > +c_parser_sizeof_or_countof_expression (c_parser *parser, enum rid rid)
> >  {
> > +  const char *op_name = (rid == RID_COUNTOF) ? "countof" : "sizeof";
> 
> Likewise.
> 
> > diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
> > index 302c3299ede..82f31668e37 100644
> > --- a/gcc/doc/extend.texi
> > +++ b/gcc/doc/extend.texi
> > @@ -10555,6 +10555,36 @@ 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 countof
> > +@section Determining the Number of Elements of Arrays
> > +@cindex countof
> > +@cindex number of elements
> 
> Likewise, for node name and index entry.
> 
> -- 
> 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] 318+ messages in thread

* Re: [PATCH v15 2/4] gcc/: Rename array_type_nelts() => array_type_nelts_minus_one()
  2024-10-16 10:34       ` Joseph Myers
  2024-10-16 10:45         ` Alejandro Colomar
@ 2024-10-16 10:53         ` Alejandro Colomar
  2024-10-16 11:08           ` Joseph Myers
  1 sibling, 1 reply; 318+ messages in thread
From: Alejandro Colomar @ 2024-10-16 10:53 UTC (permalink / raw)
  To: Joseph Myers; +Cc: gcc-patches, Richard Biener

[-- Attachment #1: Type: text/plain, Size: 603 bytes --]

On Wed, Oct 16, 2024 at 10:34:21AM GMT, Joseph Myers wrote:
> On Wed, 16 Oct 2024, Alejandro Colomar wrote:
> 
> > The old name was misleading.
> > 
> > While at it, also rename some temporary variables that are used with
> > this function, for consistency.
> 
> This patch is OK.  Note that in ChangeLog entries as in other 
> documentation, a function is referred to just as function_name, not as 
> function_name().

Should I also change the Subject (1st line of the commit message)?

> 
> -- 
> 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] 318+ messages in thread

* Re: [PATCH v15 2/4] gcc/: Rename array_type_nelts() => array_type_nelts_minus_one()
  2024-10-16 10:53         ` Alejandro Colomar
@ 2024-10-16 11:08           ` Joseph Myers
  0 siblings, 0 replies; 318+ messages in thread
From: Joseph Myers @ 2024-10-16 11:08 UTC (permalink / raw)
  To: Alejandro Colomar; +Cc: gcc-patches, Richard Biener

On Wed, 16 Oct 2024, Alejandro Colomar wrote:

> On Wed, Oct 16, 2024 at 10:34:21AM GMT, Joseph Myers wrote:
> > On Wed, 16 Oct 2024, Alejandro Colomar wrote:
> > 
> > > The old name was misleading.
> > > 
> > > While at it, also rename some temporary variables that are used with
> > > this function, for consistency.
> > 
> > This patch is OK.  Note that in ChangeLog entries as in other 
> > documentation, a function is referred to just as function_name, not as 
> > function_name().
> 
> Should I also change the Subject (1st line of the commit message)?

Yes.

-- 
Joseph S. Myers
josmyers@redhat.com


^ permalink raw reply	[flat|nested] 318+ messages in thread

* [PATCH v16b 0/4] c: Add __countof__ operator
@ 2024-10-16 12:09 Alejandro Colomar
  2024-07-28 14:15 ` [RFC v1 0/2] c: Add _Lengthof operator Alejandro Colomar
                   ` (5 more replies)
  0 siblings, 6 replies; 318+ messages in thread
From: Alejandro Colomar @ 2024-10-16 12:09 UTC (permalink / raw)
  To: gcc-patches, Joseph Myers
  Cc: Alejandro Colomar, Gabriel Ravier, Jakub Jelinek, Kees Cook,
	Qing Zhao, David Brown, Florian Weimer, Andreas Schwab,
	Timm Baeder, Daniel Plakosh, A. Jiang, Eugene Zelenko,
	Aaron Ballman, Paul Koning, Daniel Lundin, Nikolaos Strimpas,
	JeanHeyd Meneide, Fernando Borretti, Jonathan Protzenko,
	Chris Bazley, Ville Voutilainen, Alex Celeste,
	Jakub Łukasiewicz, Douglas McIlroy, Jason Merrill,
	Siddhesh Poyarekar, DJ Delorie, Carlos O'Donell,
	Martin Uecker, Gustavo A. R. Silva, Patrizia Kaye, Ori Bernstein,
	Robert Seacord, James K. Lowden, Marek Polacek, Sam James,
	corentinjabot, Richard Biener

[-- Attachment #1: Type: text/plain, Size: 96585 bytes --]

Hi!

v16 changes:

-  Remove () from commit messages in function names.  [Joseph]
-  Use __countof__ (name of the actual operator) in diagnostic messages.
   [Joseph]
-  Add CC (sorry for not CCing the patches to most people in v15; I
   accidentally suppressed most of them while sending).

v16b is a resend, since I accidentally didn't send them to the mailing
list.

Have a lovely day!
Alex

Alejandro Colomar (4):
  contrib/: Add support for Cc: and Link: tags
  gcc/: Rename array_type_nelts => array_type_nelts_minus_one
  gcc/: Merge definitions of array_type_nelts_top
  c: Add __countof__ operator

 contrib/gcc-changelog/git_commit.py    |   5 +-
 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                        |  32 ++++--
 gcc/c/c-fold.cc                        |   7 +-
 gcc/c/c-parser.cc                      |  62 +++++++---
 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/tree.cc                         |  13 ---
 gcc/doc/extend.texi                    |  30 +++++
 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/testsuite/gcc.dg/countof-compile.c | 115 +++++++++++++++++++
 gcc/testsuite/gcc.dg/countof-vla.c     |  46 ++++++++
 gcc/testsuite/gcc.dg/countof.c         | 150 +++++++++++++++++++++++++
 gcc/tree.cc                            |  17 ++-
 gcc/tree.h                             |   3 +-
 27 files changed, 600 insertions(+), 80 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/countof-compile.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-vla.c
 create mode 100644 gcc/testsuite/gcc.dg/countof.c

Range-diff:
1:  b6da2185675 = 1:  eac2d18d8a0 contrib/: Add support for Cc: and Link: tags
2:  a0fa3f139f9 ! 2:  7418a11fcd6 gcc/: Rename array_type_nelts() => array_type_nelts_minus_one()
    @@ Metadata
     Author: Alejandro Colomar <alx@kernel.org>
     
      ## Commit message ##
    -    gcc/: Rename array_type_nelts() => array_type_nelts_minus_one()
    +    gcc/: Rename array_type_nelts => array_type_nelts_minus_one
     
         The old name was misleading.
     
    @@ Commit message
                 * config/aarch64/aarch64.cc
                 (pure_scalable_type_info::analyze_array)
                 * config/i386/i386.cc (ix86_canonical_va_list_type):
    -            Rename array_type_nelts() => array_type_nelts_minus_one()
    +            Rename array_type_nelts => array_type_nelts_minus_one
                 The old name was misleading.
     
         gcc/c/ChangeLog:
     
                 * c-decl.cc (one_element_array_type_p, get_parm_array_spec)
                 * c-fold.cc (c_fold_array_ref):
    -            Rename array_type_nelts() => array_type_nelts_minus_one()
    +            Rename array_type_nelts => array_type_nelts_minus_one
     
         gcc/cp/ChangeLog:
     
    @@ Commit message
                 (build_delete)
                 * lambda.cc (add_capture)
                 * tree.cc (array_type_nelts_top):
    -            Rename array_type_nelts() => array_type_nelts_minus_one()
    +            Rename array_type_nelts => array_type_nelts_minus_one
     
         gcc/fortran/ChangeLog:
     
    @@ Commit message
                 * trans-openmp.cc
                 (gfc_walk_alloc_comps)
                 (gfc_omp_clause_linear_ctor):
    -            Rename array_type_nelts() => array_type_nelts_minus_one()
    +            Rename array_type_nelts => array_type_nelts_minus_one
     
         gcc/rust/ChangeLog:
     
                 * backend/rust-tree.cc (array_type_nelts_top):
    -            Rename array_type_nelts() => array_type_nelts_minus_one()
    +            Rename array_type_nelts => array_type_nelts_minus_one
     
         Cc: Gabriel Ravier <gabravier@gmail.com>
         Cc: Martin Uecker <uecker@tugraz.at>
3:  43a2e18c6a2 ! 3:  0cfae0598b3 Merge definitions of array_type_nelts_top()
    @@ Metadata
     Author: Alejandro Colomar <alx@kernel.org>
     
      ## Commit message ##
    -    Merge definitions of array_type_nelts_top()
    +    gcc/: Merge definitions of array_type_nelts_top
     
         There were two identical definitions, and none of them are available
         where they are needed for implementing __nelementsof__.  Merge them, and
4:  8a6959d2d38 ! 4:  12a30a2a6fd c: Add __countof__ operator
    @@ Commit message
                 (pop_maybe_used)
                 (is_top_array_vla)
                 (c_expr_countof_expr, c_expr_countof_type):
    -            Add __countof__operator.
    +            Add __countof__ operator.
     
         gcc/testsuite/ChangeLog:
     
    @@ Commit message
         Cc: Robert Seacord <rcseacord@gmail.com>
         Cc: Marek Polacek <mpolacek@gcc.gnu.org>
         Cc: Sam James <sam@gentoo.org>
    +    Cc: Richard Biener <richard.guenther@gmail.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)
     +  type_code = TREE_CODE (type);
     +  if (type_code != ARRAY_TYPE)
     +    {
    -+      error_at (loc, "invalid application of %<countof%> to type %qT", type);
    ++      error_at (loc, "invalid application of %<__countof__%> to type %qT", type);
     +      return error_mark_node;
     +    }
     +  if (!COMPLETE_TYPE_P (type))
     +    {
     +      error_at (loc,
    -+		"invalid application of %<countof%> to incomplete type %qT",
    ++		"invalid application of %<__countof__%> to incomplete type %qT",
     +		type);
     +      return error_mark_node;
     +    }
    @@ gcc/c/c-decl.cc: start_struct (location_t loc, enum tree_code code, tree name,
     +		    ? "typeof"
     +		    : (in_alignof
     +		       ? "alignof"
    -+		       : "countof"))));
    ++		       : "__countof__"))));
      
        if (in_underspecified_init)
          error_at (loc, "%qT defined in underspecified object initializer", ref);
    @@ gcc/c/c-decl.cc: start_enum (location_t loc, struct c_enum_contents *the_enum, t
     +		    ? "typeof"
     +		    : (in_alignof
     +		       ? "alignof"
    -+		       : "countof"))));
    ++		       : "__countof__"))));
      
        if (in_underspecified_init)
          error_at (loc, "%qT defined in underspecified object initializer",
    @@ gcc/c/c-parser.cc: c_parser_unary_expression (c_parser *parser)
     -c_parser_sizeof_expression (c_parser *parser)
     +c_parser_sizeof_or_countof_expression (c_parser *parser, enum rid rid)
      {
    -+  const char *op_name = (rid == RID_COUNTOF) ? "countof" : "sizeof";
    ++  const char *op_name = (rid == RID_COUNTOF) ? "__countof__" : "sizeof";
        struct c_expr expr;
        struct c_expr result;
        location_t expr_loc;
    @@ gcc/doc/extend.texi: If the operand of the @code{__alignof__} expression is a fu
      the expression evaluates to the alignment of the function which may
      be specified by attribute @code{aligned} (@pxref{Common Function Attributes}).
      
    -+@node countof
    ++@node __countof__
     +@section Determining the Number of Elements of Arrays
    -+@cindex countof
    ++@cindex __countof__
     +@cindex number of elements
     +
     +The keyword @code{__countof__} determines

base-commit: 9cbcf8d1de159e6113fafb5dc2feb4a7e467a302
prerequisite-patch-id: 3bb58e302e54b35e987452de2e3cb6da7f6917ce
prerequisite-patch-id: 090612df745c5ed878a75175606ce1deabf61cb0
prerequisite-patch-id: c3a80d94c326f7402bdf46049c434e809a9f376e
prerequisite-patch-id: 883007acf6a47f51128798dc952895854b40e1ff
prerequisite-patch-id: 93e211483ce2b939ce5e549de78e9ac4606bb114
prerequisite-patch-id: 008f55a1dc4b0a2551e4682b3319a3b0df86c72e
prerequisite-patch-id: be6ecc95f5fcf2fe9ac44263e6eae8a69068ee53
prerequisite-patch-id: e64a9e239738ff1af9753893372bb0fff907d8e6
prerequisite-patch-id: 22cc97d05ab08735db2341f5062c737f9cff9209
prerequisite-patch-id: 9e9756ca0458d4f6f162229e5ffe5923ffceb9d7
prerequisite-patch-id: 9d64d075010c059eaceb2fb2326d48f6a8798950
prerequisite-patch-id: be2e5a5deb6836b4715e4715cddd03018d2f3346
prerequisite-patch-id: a627d18e62fc98b7ccf11b31b0dc885a52994795
prerequisite-patch-id: 39aea8b15f043ab5e2804a6e127d2fe5108d814b
prerequisite-patch-id: 8cb26809cc4de24fe408e71a468fbc278241faab
prerequisite-patch-id: 1b0dd932c7637d953a7b7086aa5625287df6c79a
prerequisite-patch-id: 0bb1888a37e3537ba48e69ac378b7b3e41453949
prerequisite-patch-id: 79657c31c616c9bf477ec015a4ccb94f298193c0
prerequisite-patch-id: 2506a44e9d695cffa4c710176092c30392037103
prerequisite-patch-id: da4a114bc9bef4aafb816328f1674b5f85818753
prerequisite-patch-id: f4a32714d46e022356759a3fb305a8827ef565e9
prerequisite-patch-id: 08a6388b590804ab3f8da8c03d953e88428228e9
prerequisite-patch-id: 37fb8203174274fa9e3054ba0d83ff41dd9ba206
prerequisite-patch-id: 5a6559b661dd999abf5d5b0a40309636faa3504e
prerequisite-patch-id: a66c0ace262f24e19546e0669fecd0bbb6c4b4bf
prerequisite-patch-id: de6b8f05d41b61f29fc517883fafdf89aada7de9
prerequisite-patch-id: 4412c0ef6909608fc761b86cfb22722d862d61d0
prerequisite-patch-id: ad452759de17adaaf82c9f30e556fb477e3b1941
prerequisite-patch-id: 7b8615c4ad8e6c825ee192c8225e7b8f673aaeb4
prerequisite-patch-id: 7f806ab2c8bac5b2a79fad8eef55c4190ec33d44
prerequisite-patch-id: 84d3e86a4b573228dab7d37c3d89845ec1989723
prerequisite-patch-id: 293a69cf606ea42badcc678f43b53f2e47aded19
prerequisite-patch-id: 1a871a86b6c1b147ed731970f999b5d102444d1d
prerequisite-patch-id: 7798a8ca79c1f13268e3762d47861ff94d8eba02
prerequisite-patch-id: ea12050f12ad6e1278b695f5fe345ca9bc842b1f
prerequisite-patch-id: 775ec83e6019784675e3412125ae6215b4bf045d
prerequisite-patch-id: 8cc5a6f94523c8120086dcb2217ba8168b045a3e
prerequisite-patch-id: ee9fa7eb9352555ff989551e0af040359671f3d7
prerequisite-patch-id: 02737f65218d4b0c2766cfcf8c0fcde24ca93ac2
prerequisite-patch-id: 4649eac88f8eb70f79e7777b7cebff4460d8cfc7
prerequisite-patch-id: 6cba96eb4bee2e8b3b47e0bf6b21ec9fa8639480
prerequisite-patch-id: 67691213e43b5776c999e8c0927df69be8689e14
prerequisite-patch-id: c92d8f4dab324c8f42605d626035999cd990a18e
prerequisite-patch-id: f0a10e37287f97e915eb245d6394ad8e1115905a
prerequisite-patch-id: f67343a2b854a5f51d75200d56715b2cd10ddc9c
prerequisite-patch-id: 0d42c83260a2a02de43ad5066f76b4483703f155
prerequisite-patch-id: 71fc9c326b88271512ee65320dcb3b3454326472
prerequisite-patch-id: 5770267c01d4e5b5d0187445d31ee87b662fa61d
prerequisite-patch-id: 999d706f78ac4f85adbfad63adc3df03615ce716
prerequisite-patch-id: a3a7f88920dcaec397cdce89680dd341da6b7d50
prerequisite-patch-id: 74495be2707634e339b90ed5ad3a4c375f6b9ec2
prerequisite-patch-id: 7be19bb7867585445b6119f6357b69f5f8baa5b8
prerequisite-patch-id: 03efabd23ba77ba8141aa0a8f19b04f0fa6c97f1
prerequisite-patch-id: 04a4ddcad10e249f4e8cd96ade03c16997e8f83f
prerequisite-patch-id: b0b8243418ae865a61a5f92d1da80fdbed6d23d4
prerequisite-patch-id: 349842ef44ddca54066bdbb26d634ac24e076710
prerequisite-patch-id: d15d4d8c4c0b6843118774fee0c8231e948779cf
prerequisite-patch-id: eff8d7df797afdd2ba6b14c1d8ec9dbdc58b5c3d
prerequisite-patch-id: 18ae20d67e1f01478d4b01981488e0a3d6864ad2
prerequisite-patch-id: b6c162640de66eeaf8f2b470801dc3cec9d1141e
prerequisite-patch-id: fccd6815aa703114b7ea3e61b3971621316a8706
prerequisite-patch-id: ec894a0480c8c523b9f895eea7b809b68998bbfe
prerequisite-patch-id: a408ede8ac2c69f821dd06cdad368652784e975f
prerequisite-patch-id: 31f81b5fce5e577e66c09784d24727fadce0b71b
prerequisite-patch-id: 0fa06efe4a2349a00a6e1d7ed3fcb7ededef127e
prerequisite-patch-id: e7dba9a68bc0d4481b2cebf029595bdb9f47271f
prerequisite-patch-id: 4ac7ef554fdd4c2fcceb9f5bd83e9203adaddaf3
prerequisite-patch-id: ec0a3bc81af005d80235b38f44c227b0a1c248d2
prerequisite-patch-id: 7083aa4a6a21ae34a8d6457791068ba419c1187d
prerequisite-patch-id: 7b3ceb60e52271be1655ab07595e1000d8734ae8
prerequisite-patch-id: 069dd47701f5607db952e7410b66bfc4a77b907c
prerequisite-patch-id: 6de803a1b4d8dba8b403205327bff91f239a39a8
prerequisite-patch-id: 8dfcdb9d5cdf69c54766a59a8f194af09c0840b8
prerequisite-patch-id: f7834a2848f562a130f3d6f28a6b849723dbe18f
prerequisite-patch-id: 2f283e2b6ff758a2b1f0f4f491c962499be68f91
prerequisite-patch-id: 7ca906fcc364ab07d6ab9b48fe8162e8006499b9
prerequisite-patch-id: 0ef05db7ab79653ae096f50497946214bc5084b9
prerequisite-patch-id: 1d60704d316f4b0f66d5c7e4bf17b025cf99c617
prerequisite-patch-id: ed3314a4690d9c15bbcfee441599a58e37215877
prerequisite-patch-id: 34ec93f88bed41db1608e214800f87fdc5a7f9f9
prerequisite-patch-id: aca1f8cc97d88784936517c7e8050c457c77c9af
prerequisite-patch-id: b499a1bfa95368ee03daa8c7d45b3ae9c1206871
prerequisite-patch-id: 5f1cb1245044b3ad4169500916c8b9459711416e
prerequisite-patch-id: 88e3e2e5947fbfa907213daa9ceef1651976d72f
prerequisite-patch-id: b4d4f67cd84b9ccb4c4eb48d8e7e20fc70b702ec
prerequisite-patch-id: b807936c32d4a4539a29ba56b637a3f4733713e3
prerequisite-patch-id: 72b95ab107eb6ae60f6517410ecce24a3308fa6e
prerequisite-patch-id: 007b9853bbb41eb2d2b85fd67c1b39d58c2dcc4d
prerequisite-patch-id: e6e05315ec9827b069836b4f394099272c4b3998
prerequisite-patch-id: cd63bd21f25dfb458c751306f1ba8fba6db43a35
prerequisite-patch-id: 790fe51546bed957d4094668086a87009ea6bc3e
prerequisite-patch-id: c55ca764e1bde1857cab3d1c7a569172e3a60dd0
prerequisite-patch-id: 4574efb15f6e60ba84b21718381c19faa2d06e6a
prerequisite-patch-id: 4026283a30594ccf4c5c297a45b817d7c95dcc81
prerequisite-patch-id: 2f6425ce98f57c1833fcfc1cb963a4b00550daaa
prerequisite-patch-id: 671d4f6b289715eecf11df3b8e94e566b4e3f358
prerequisite-patch-id: 59d20ef094471e06900a58216a35fb466e6350a6
prerequisite-patch-id: 8f6ac7d59fcdd44f015dce5b41ca7e20ed551b17
prerequisite-patch-id: b3f0435a6a54a62ae2b895ede265f657b2826929
prerequisite-patch-id: 06784b4d67904e2a8eab05f652d985750aeae26a
prerequisite-patch-id: 48e9916f08c8502323eadf9595d11a3ad7cf1b0c
prerequisite-patch-id: 9c5b9353f575b545d6ba706aa33a4200dc163e1e
prerequisite-patch-id: efadc065d2991129a9fa4380ed782b9dfac9807f
prerequisite-patch-id: 5a3e46fd6d5f1324a307bd01656993131644e59d
prerequisite-patch-id: 40be26b80ff47971946da8ccca6574333b4ac511
prerequisite-patch-id: 249d8bc2c8226ea94c27e2d2db8dfda056b8221d
prerequisite-patch-id: 64c7dc66a01b47fdc1d178e4264dbfb17f65cb48
prerequisite-patch-id: 7651dda34bd7be0a7c0c58b813abbfe4e75057a5
prerequisite-patch-id: 5b677afd301ba2d8385e73d6f55ef259e69cdd06
prerequisite-patch-id: f41124cb1f7db66cf578ee87b768438dcf66227d
prerequisite-patch-id: 6a173ab5f27750a6f4a2f8adebff537f95225d38
prerequisite-patch-id: c42d87f4f18b34c20121d7a7ee22564b8f2a9c3b
prerequisite-patch-id: e4c4b6c5c635e67f641c1bb4902bb5ec1a0eb1be
prerequisite-patch-id: 197202a25498a915f35f4417efb38e8844cac309
prerequisite-patch-id: 1e23186a890510f123ecd202f8a50d2094201277
prerequisite-patch-id: ba3e7e54dfbd8370ff50d1a5e85ac06d803fe68d
prerequisite-patch-id: edcca1af6061de5006b58ff7cd52a039aec88192
prerequisite-patch-id: 50ee0f2c714091aeab155cd40a94214fd1844463
prerequisite-patch-id: 31adcc5191ebc8b2ea26ee1e4b7de78a3d8e0f48
prerequisite-patch-id: dafdb698d23a185ee4adfbf9cbaf43ea31661bc1
prerequisite-patch-id: 683d340258d86d0774c772cc5d4bc4dfc6c214ac
prerequisite-patch-id: 0052a313ada5ebbd0e24905f2b75974736dae59e
prerequisite-patch-id: 1cbdbf0cf8727d07cfb7251551bbb8f47ca4f9d8
prerequisite-patch-id: c059fdfb33923cc5d728f53136021e01cab5f316
prerequisite-patch-id: d8cd3ac99c209600a4686d85627fae2956864272
prerequisite-patch-id: 7bfa53abc0cd50a22a81782353e30f0503bf87b3
prerequisite-patch-id: a2837d8005f85e1764d2baf4c5269ac4c26d0e03
prerequisite-patch-id: c7c2ba071a328f24d36a7bc73d096f701ff049c4
prerequisite-patch-id: 49edd721efd5860bce7a6da39a3983c1729dfb09
prerequisite-patch-id: b41ba2264cf8d51fad69c0d60b23282fdcaa02ed
prerequisite-patch-id: ce1094369b939e5df1c9ff586ba6e77eadd6755b
prerequisite-patch-id: cc76aa21e68006e190b6c095a7eab1f71a350035
prerequisite-patch-id: 016dbed32a9d26e0daa7fe068846dc5bf0bab4b2
prerequisite-patch-id: ea3270295ff22f15ae5a5213ae7ef0fb24f3d90e
prerequisite-patch-id: 0d7ec035c0ac8ea612791940c47c720fd0fc0983
prerequisite-patch-id: 073689ebff4dc3ed400b7a6a09b2aa3222eb5eaf
prerequisite-patch-id: 3de9c5dcd90a94356e41cd6c3a6b3a3ebd6da40f
prerequisite-patch-id: 02173a8508f62560dfc0c873ed4f8ffd3b2da127
prerequisite-patch-id: 325c71a3064a69ed233417bb0dd06ac5afe22ecd
prerequisite-patch-id: fb5f0634575b9cd445be39af1b442f641f33669e
prerequisite-patch-id: 375ec357c82582464519ccd102ba9c9969b27ccd
prerequisite-patch-id: 96724bd515fee1e70896e427ca5443cf6c3bd1c6
prerequisite-patch-id: d11653d1691c233ceac344313e1facf239c075e6
prerequisite-patch-id: a0c4b6d4fa27a1f1738ccd7d2c1c5203f4acc10c
prerequisite-patch-id: bcf62e2802a1d35bbeb601750792f3043e18e02e
prerequisite-patch-id: b6027c3dd6b0d7a576397c3f7cead1cb2e32ab3d
prerequisite-patch-id: 2993826cfc8ecb4743d1104ce9062ce064dee436
prerequisite-patch-id: 2de773c80c1d53b349768f3a9c1dedd9473141e2
prerequisite-patch-id: dcd065f3bede4933cf1071ca0ff8f631af30537e
prerequisite-patch-id: e8f9cef7f9a80d21786bdbc63de84dad5bb0f11b
prerequisite-patch-id: adefc62a9de4bcbb15ddba73edcdb96740b8527f
prerequisite-patch-id: b8028f15bc6bcfc0053852516acd70129434ef64
prerequisite-patch-id: a9378612984ceace5d8fc99c192de3d07fad4b4c
prerequisite-patch-id: 3e64fd39d97c528b5901f648d7ab92c9b3dfebd1
prerequisite-patch-id: 6900b6fcf58f765fa3266432dc9e2eebcacfbb4f
prerequisite-patch-id: 0d796b1a9c84ad77fecacee5450ae4fe067e7748
prerequisite-patch-id: c8cd1e1f3efda1056dd2f393a43b97a675f8fc00
prerequisite-patch-id: a1e5e6ee3a85aa293485f42163c5e6fb8ed7ac6c
prerequisite-patch-id: 29865d865b97531dd5be3019e22adb1066bcd0a3
prerequisite-patch-id: f5e05f1932b2fd24d00c3a7e64a2589f9c62a4e7
prerequisite-patch-id: 9f875036c21954004d3533697f89c7b8f3f35673
prerequisite-patch-id: f0f917f79ebed24ee4cd3427393d6cc24b9f2617
prerequisite-patch-id: 949be1cb8e66006949d4654aa60cf11b990bea13
prerequisite-patch-id: a035355f8731aa2619cd876157cfd2a9321c4814
prerequisite-patch-id: d23b3af12de5f250b5aded06076390d855065d34
prerequisite-patch-id: b649f233ca196c43de136937fbcaf0a5b792a7c7
prerequisite-patch-id: 0b474fc99e8b05aee2f470e8166d715261b9eb11
prerequisite-patch-id: a8f595e6c8b9714bfc4d89a7e39d5be3a9665d87
prerequisite-patch-id: 362ec11aff3d8ddc90f8b1aeb31d0fde8785384b
prerequisite-patch-id: 3695552670237d21bbd21fef03105083754ed6d1
prerequisite-patch-id: 89f2689e530147ac5530197ff972bc44135a1fe5
prerequisite-patch-id: e4a07cbaee52cbe451bfb9938b6b2a8636cac2f0
prerequisite-patch-id: f8f8edb0e66d2612359021654361be7fd0a55b70
prerequisite-patch-id: 743f4e4444f9cac24e67abce2bda52d6a421d870
prerequisite-patch-id: 8f0d19793716d0c18759e4261ef18c6db21c7f66
prerequisite-patch-id: 016a97f4bb36008d268ed1142d4fe67263d18c5f
prerequisite-patch-id: c9b1ea941f12ec7c34d17a7a81b999cdc90a46bb
prerequisite-patch-id: 2e4f5844a1680c659f4fe9af3723f8c9e6171c98
prerequisite-patch-id: 9b218d7632794493bcc98298de79e9d881bc4de2
prerequisite-patch-id: bd18dcb6c060ae56cadb55ad248138918b4542fa
prerequisite-patch-id: 5f4f31b906f1a415721c42bb4f06e9a97e6d9826
prerequisite-patch-id: fd625a00389f10724c4df0c309f46588ff4db63e
prerequisite-patch-id: 6aa7f6e164a2fc200361fd96399ad1c10f0825e2
prerequisite-patch-id: de267e462ebf8b5fda3d3df92d84914f3d49b093
prerequisite-patch-id: 10e0c0ed7bb11a5e9d50b4210a67d56d0baa7ae7
prerequisite-patch-id: 881a354db3dcf42e71ff51e86a712fe24a82378f
prerequisite-patch-id: 471c157425528ec5fa2fe0371dfc9babeff74c57
prerequisite-patch-id: a7d752c724506c047c0c69fb568f9e3e421773b5
prerequisite-patch-id: e207260eff0bee9b47719902663721ac36371856
prerequisite-patch-id: c978ecf00ccf17014919ba6d22a634f1fa5378b8
prerequisite-patch-id: c30ea3d0e9179a8f91523e4775aa1d7697777031
prerequisite-patch-id: 9caf8f6dc88c899b90242124e9efccecf61e6580
prerequisite-patch-id: 8104c6e0f28b79353bb1fe3d6d5bd49b8a1d4656
prerequisite-patch-id: ad97388f77ab9d4cc88a369418deec6f796d9ac3
prerequisite-patch-id: 1f6acfacff835f1d7f922614262505c4acbcb067
prerequisite-patch-id: 95d5625e0f04636a4c3ec335c77f34a5fecaa952
prerequisite-patch-id: 82e613feb908a11046bdafc6e874bcd8c4f52200
prerequisite-patch-id: 5f7a850dcf2102e4ac82791ba95ed0c0bc695613
prerequisite-patch-id: 50d03e282b31737919a2b979d59c5c4c17107627
prerequisite-patch-id: 8b51bae8e714a0e5277f67ff9d1455fd2f4e36b7
prerequisite-patch-id: eee196eb6f44f53040e52305d9c48909eb3bf2c5
prerequisite-patch-id: 35494985bedf6015cb3a8c2c70f58099e9c44316
prerequisite-patch-id: c3c5c822735b385dd0e55260f514623bf3f9ff1a
prerequisite-patch-id: b21222f6f96276b46ff605bdd1d2a75c9af839ca
prerequisite-patch-id: b63e092548d498d642b6363eae9c98247f5300f9
prerequisite-patch-id: 99cf93d15a50ad94c049c736b375bbdb77cf0ef6
prerequisite-patch-id: e2d86b651e3ff2f70848f827b29cc804cead48b2
prerequisite-patch-id: 1ec76b0303530aaa120186fb249252cd3a1bd7ec
prerequisite-patch-id: 9a35b1041fb252654255045df37478c8eb15a501
prerequisite-patch-id: e7227e60ea90415b54c6fcd553ddece24dd402fc
prerequisite-patch-id: 2f45861307fafa6a5696098406e164e166f4d207
prerequisite-patch-id: ab037b78ccf8a9db312333f5e01e6fd2e54832ca
prerequisite-patch-id: 9c886d5ccd279d6f283fcd60a794e66c94fe782d
prerequisite-patch-id: fa5a4fc2f2d77e9ad000d7477f56b822efce457f
prerequisite-patch-id: a0699fc9eb0ee36f53bc937770887d6086d2a7b8
prerequisite-patch-id: b383634edd50afef4180be293861d1014491d86d
prerequisite-patch-id: 2f404a754f2e1048165df254e963e26f6789de7f
prerequisite-patch-id: 07d59a1d0796816d8421b5a236175b1568d1f63f
prerequisite-patch-id: 9f904d43a86cb4e55a2a00440dd042ec717c8eb8
prerequisite-patch-id: b30b252bdf0646403dbd132c7dc629188e4f6a4b
prerequisite-patch-id: 73e2691afad05a42cb6cb5a28894eb958516f39c
prerequisite-patch-id: ef0f8b6061c55ada19107f026164c8598ebc66bd
prerequisite-patch-id: da21009a2dbc3384309cfdc4c49e10b86de6e747
prerequisite-patch-id: 2ef5022df54288b85ef1c8fe4e7a02a03d4577ff
prerequisite-patch-id: 5193b8507248975783d1eb6bc911265e6b55988e
prerequisite-patch-id: 1aef895eb9c159d33d617d7b2475928f75a73303
prerequisite-patch-id: bf87652bd502aeaf671da92e243553fb9a94f5d5
prerequisite-patch-id: cf9856dfd70d154fab043ffd2ee89288d9d41827
prerequisite-patch-id: f9daf7a441685aa6d25225b6616e51be5fcfe772
prerequisite-patch-id: 0101aa9af501543384863fa8c090febd6939f80f
prerequisite-patch-id: ccf1ac224734562e2f4207847b8128cd3c8b9d31
prerequisite-patch-id: 589ae86ee30b01355ce220ab9fc89c5403d95076
prerequisite-patch-id: 6e809a44a0ef69883eb812f8a4b57eb52ad32f41
prerequisite-patch-id: 116d110f795045527d54f2897e1ac12bb2f59238
prerequisite-patch-id: f4e0f48a8ce61bc6c229a18bf41f4b3cdec3a9d0
prerequisite-patch-id: e78df0253e48cdf5f9e44c17a169fc9cccb82c7e
prerequisite-patch-id: 1e6951da0eba531f4b445996167fea1e7320e3ae
prerequisite-patch-id: b1903fb1a742dd33ebb635299c725e9fc2a4e9ae
prerequisite-patch-id: eb07c15789948b34c0b219ff05f61c530882845d
prerequisite-patch-id: 92c0ba647ef4b4b7e83297554f6fa7e31f3a8fb5
prerequisite-patch-id: f968b1250e573119cb65aab0b98c225d8a7c4d8a
prerequisite-patch-id: 5e6dee90fe5f7a891794b5ea6bed41b1157c2930
prerequisite-patch-id: 3b10245cae08595a6bcbdc82ff836becaf6d04d2
prerequisite-patch-id: d7f15f333560e8ccfe2ad073e99ca4ef502e15d1
prerequisite-patch-id: 4c95c2badbd5911a7405a64e0d84e3091526444d
prerequisite-patch-id: f839c9824865564c12cbb7064ff455f34dc039f7
prerequisite-patch-id: 071e2570569f005c75ed7d8bf112db80cca310e5
prerequisite-patch-id: 7ee42594ecf51591428ae7f13bfb8403affed8cb
prerequisite-patch-id: 4b2105c900cf8ed047a9c0d1866fb2bdb4f9a59e
prerequisite-patch-id: dd4697ba0013408e637223fadd027c9b34945060
prerequisite-patch-id: e0881345b919ec25525c626303ba5d5e160f97f2
prerequisite-patch-id: fc6865c7e1fb19530ac8e77090eaa0b179f70496
prerequisite-patch-id: e3b8081ed28b7f0d370548044237287f52179967
prerequisite-patch-id: b672da115531fc52a591c9e50ac4da9e8b09e144
prerequisite-patch-id: f2764b91aa819feb1879d007993bda7aeb7f5df6
prerequisite-patch-id: dfb13890022578746ce611a965c62c34905b1f18
prerequisite-patch-id: bef3730ba816c84cb056d12e30b91a8c1f4b6aac
prerequisite-patch-id: 265211a01667357c86ce905ee33e4adbb81887d9
prerequisite-patch-id: c02d2492949e079494b9552c397e689774fad639
prerequisite-patch-id: 0f4180d693806ae210396ec1512be8e1d45c9530
prerequisite-patch-id: 22b486e7286a8b1a8ef90d3f1f4a4d48e43fb25c
prerequisite-patch-id: 0020828bf1b65907c906fb9ebf24104a5e72c790
prerequisite-patch-id: 4afad41c227028a4c6c35d1c43b0ee7883852a1e
prerequisite-patch-id: 890e19d588eca2dacfb83475c19ac461c0d83058
prerequisite-patch-id: f35d03d5ed63be69d2dfec77d07b28d21c40dc9a
prerequisite-patch-id: 2bebc000037d37260152802423445d39bc463f8e
prerequisite-patch-id: ccbec53de5ad88beb7657680ae6aa167f3505fd6
prerequisite-patch-id: 3c588bad04050087679a1d4f5479efb0da2537bb
prerequisite-patch-id: 87d915c6c5495d2accc7864dc592f2f651012fca
prerequisite-patch-id: a327cf20636f57b5feb31928c49d6517f102a709
prerequisite-patch-id: 8106cf8afd07cf37f3ecd63b831f1a22fa99998a
prerequisite-patch-id: a4ff39b72413dc2d894d269629919ce5199eb0fd
prerequisite-patch-id: c0db74dd58a097e7130420bd294b0f3d200730be
prerequisite-patch-id: df5bd199584a63d1ca2af8ca5e9bc659baffb8ab
prerequisite-patch-id: 9f8d32c0a8df05688a4e6779d45538056d891a72
prerequisite-patch-id: 167566e1096e56d7189393aed3528b8047421a2b
prerequisite-patch-id: 5ade75da262706c05c72bc2e1095cdc137334928
prerequisite-patch-id: 725cd8d55b55117b8732240a36ef6dd57560b7aa
prerequisite-patch-id: 2283e8ab28c671cd97fdba344bad9fad3b740955
prerequisite-patch-id: d86fed5ed934d2622a0e640677483dbd5e493b50
prerequisite-patch-id: 5a523603c0cc2344952de69d65a1dd6c9c28b1b0
prerequisite-patch-id: 8276956515aab9f3e81a9b4d51f5d270fea82c8b
prerequisite-patch-id: 1c0b8c20b01944262081a7fac4905a24a1f51afd
prerequisite-patch-id: 90b6ed9e4633014209d3291157104fe2db6cc268
prerequisite-patch-id: b78d480e28a5684e5a04f9e2d1dc6c8d6b6115d8
prerequisite-patch-id: 85129a45f66a9afd1d6aeb78a266f2b33131effc
prerequisite-patch-id: 46c2c0f251c385f740ec0f021ddf71b214dcf188
prerequisite-patch-id: de94541c97cd5dfb8f02b4210557a29264c60f28
prerequisite-patch-id: cb4a135f378247e43ecb9c5c1ca421e778356cd3
prerequisite-patch-id: 6941030e002fe4dac24a7e431297837bcebd6637
prerequisite-patch-id: 16ed31acf9114e5bcdeab9ac6f8b3c1d460d40ab
prerequisite-patch-id: 5a24fb875f0c703d031c3dcfd40faf2072a691b1
prerequisite-patch-id: 278384975e9224209b9df58781cb0d57d33cce91
prerequisite-patch-id: 8b4be8616dd4f2e1b6189657017e81999e3379bf
prerequisite-patch-id: 99853a3b8283b9aae581ec9c7a4b30dd27a9075f
prerequisite-patch-id: a48c177e8a82248dfd6642c35da34019d765a4a8
prerequisite-patch-id: 6b4419d64c7d1e887578e30a73fc476aad5408a6
prerequisite-patch-id: 93b79b926b74052e9bbba631e0f30da89c1dd0ec
prerequisite-patch-id: 9fe442b02446f58ea358d748da5f5f82805bc7ef
prerequisite-patch-id: 26828312870404b6611ccd685b162aa082dfce57
prerequisite-patch-id: 6ce31c6bb1a2b79ca465dca7a1157d1bb379d51b
prerequisite-patch-id: e6b4e8bd8a45796125d4fdcc169f97f5a3fb8bf8
prerequisite-patch-id: 94637d65272a73ec3e2b19dc3595d864fdea4836
prerequisite-patch-id: dd5dfa3e4d58a7db1f158bcc0daec057c028ce00
prerequisite-patch-id: 2295114d438c62a2128620775fc0300b0b418ff9
prerequisite-patch-id: 080adcee4042fd9511680fb10beebcae24a4dc06
prerequisite-patch-id: 022f540464bfd6c2202cdeb5530502903d207417
prerequisite-patch-id: 5ffcb1ea5dafbfe47753ce4165afa1f99d46cc82
prerequisite-patch-id: c4dcb2f3f063115727c204d3e0b0ef7c7a66cda9
prerequisite-patch-id: 984a29d2480696456528847eb7365e5785613ab6
prerequisite-patch-id: fa4b35b9b0874bdf8057f88303e204ff3b6e0538
prerequisite-patch-id: 12dac397d93e001201a2b8fcbadbca24a91a1f5a
prerequisite-patch-id: 51112edb6d85135a1930262e7a63f8f2fad3b22d
prerequisite-patch-id: b2fe22f7b89cd65edd2f67db746926a3deb69180
prerequisite-patch-id: 17757de676f6d55f18375ee9630ff33a1d101c1f
prerequisite-patch-id: ed5fdaf31479dc0d05afa7159e74a6ff5d390717
prerequisite-patch-id: 15f23a365586786d1b1cf45b4d5f1449c4507131
prerequisite-patch-id: 4c04f094a9f3dd5b2e83e45e5953e19140599477
prerequisite-patch-id: 036d1b98663bc2898502f50ded880e8759a29779
prerequisite-patch-id: 6c2d1e2e56d3917824f83caeb0ef72d13e2b0943
prerequisite-patch-id: fefa7cc8020e445d5696cce9805ac8a070f8ce62
prerequisite-patch-id: 2f3a5e1af6a18c3c900e907cdbd5b8f70e16f2cf
prerequisite-patch-id: 5323f57010be74dcec124a4b1039d71e4b43827d
prerequisite-patch-id: 084ccc81aa8dfb551f726b255bbc468b7927a4f6
prerequisite-patch-id: ef34cf54e320016fe563e6719e20ea5a9c3d8b0b
prerequisite-patch-id: cd5de61f31dc3939dfb3a650f766b652bc004f66
prerequisite-patch-id: a4f3078b22023208c08aa43904abaf7b9b96685c
prerequisite-patch-id: ebe1b18964e42c75f42ba7a86afc5dc05599c365
prerequisite-patch-id: daa0dec8fce546fedd54ea5c5cfbefd22cda6166
prerequisite-patch-id: ca6fb2e53c36765eb3a4d03996a33a75669856d1
prerequisite-patch-id: 5c737efd3e6ed83f02e7871bba03384349062e14
prerequisite-patch-id: 9a271a42b76d46e6dd0ab589b69e6153245d1d74
prerequisite-patch-id: 38075ae35bb852c54840ef45e252304d97abaf37
prerequisite-patch-id: fb9efadc22957488fb64dda477c247a34e31f818
prerequisite-patch-id: af07380f477d924bbbe7c88afd482f4f6e93e65c
prerequisite-patch-id: c56d58afe69b0c1a409785a8ab96dde9069effaa
prerequisite-patch-id: 634935a9c68aa1b459e21f9726b4c4072ba4c45e
prerequisite-patch-id: e799daf13b28e3b425d216669ebd0b5a854a3eab
prerequisite-patch-id: b29d99c4a75d8e9aa43235f33735f2218cc822d3
prerequisite-patch-id: 4d9a6373a1269f995d406bf8a642342e5caba6c8
prerequisite-patch-id: ff9217b0100aa988f5c15a76d64491db1c73780c
prerequisite-patch-id: 87a45370a00f9606abc8f6e5759aeac07b966cf2
prerequisite-patch-id: 17d341478c369638f4449607c5bf0467de6d44c7
prerequisite-patch-id: 7bc9559aae8de1321298683956f89db1a6581dc1
prerequisite-patch-id: 42780b061b459d6927346db582a5b4bda554ca0c
prerequisite-patch-id: c340b164838ecfefe67999b0d8ba024974552c18
prerequisite-patch-id: cc9ff80615bf7e4f14d546ebf27258a545c81232
prerequisite-patch-id: efc6be186b7f423904fcac6a8f26779b3cd5df2f
prerequisite-patch-id: d5773ccbf76c8d9ff26c63760dd0055d4365c476
prerequisite-patch-id: 71ce6e39f1a672d9924c63d3365a5e517bd6326b
prerequisite-patch-id: 45628cd61c02682f64642a7dad5edd72390a8bcc
prerequisite-patch-id: f6e95bd1f543f9c48f590c7dc1e4fa4e5f0bc458
prerequisite-patch-id: de7fae8b9afe828ee0d9b413378163719bf23bf5
prerequisite-patch-id: 1f228a1f43eaca0d8cb3cb4d0e51f90e815c9998
prerequisite-patch-id: eaa093b0cceb0a80995b0ae89392cec23c9d5b6f
prerequisite-patch-id: cd3d75fe297fd5e5541634007420f3aa7c03b405
prerequisite-patch-id: 138934b5fff6f62599848c496e0df4742ee218ef
prerequisite-patch-id: 974d30ca06e5f559f33d1a1657fb6df0db9c69d9
prerequisite-patch-id: 422baca4c98edc4b35bce264624ef7479b9be8b6
prerequisite-patch-id: 8d9c9e733f6d961e9c8030ac267c571c7962eaa0
prerequisite-patch-id: c14eea648e497a2e49222585f0890718ec41767e
prerequisite-patch-id: 1954449cdffc55d3f9dd27a4e3a25543963e770e
prerequisite-patch-id: f5c5a744afea35e7887f54904e099eae4ffb1aca
prerequisite-patch-id: ea51a4c1f0963bfe3e2d3b3f67f2fda1bed7e5ef
prerequisite-patch-id: 1415e67af722465af5288f5c55dc6ebed8abdf6d
prerequisite-patch-id: f74be9f37c99c3551b4a3aa1e90129b35531265e
prerequisite-patch-id: 40177684fcf06f9f7668a096332bcfacaa8b0ba5
prerequisite-patch-id: 4da39ed05abad8cb8e5fe4753f47176f9e72f0cf
prerequisite-patch-id: 2193c48aad99a7b7b97ed86ef97c07be900020a7
prerequisite-patch-id: 0aeff59426bed00d3f95bc72a6eaf7bf0b1dcda7
prerequisite-patch-id: 89d22914a9e5fb5039752b7c3bc9daf6bd46efcb
prerequisite-patch-id: ca978798bfa61476e54db18474c7155437ec2402
prerequisite-patch-id: 31b26538e173e882c0ccebe22bd0b38635284f12
prerequisite-patch-id: 1ab11d427effefc6d94167167c5519d474be897b
prerequisite-patch-id: 983ba2dceb7c26002eaa993a89f11f79e08fdd5d
prerequisite-patch-id: c9de3535115eb84960d4909c67c595b15f447b25
prerequisite-patch-id: 57b6bcbaf147da44a5cc47f8253db27bff5828cd
prerequisite-patch-id: bc7f23d98d7fbbb9e0413d297cddd31cf9e0dbd6
prerequisite-patch-id: c032bb4c8589a2ed0be0c8ad03ac9ff3e2f4d324
prerequisite-patch-id: 13e2df68f96c39ca79271507f48f5e212aec0115
prerequisite-patch-id: fe762eb689c310bf632bc19407995ad17bbfc2c4
prerequisite-patch-id: 2deffeb7b7935c74260ee8d64709ba7ce3ad0217
prerequisite-patch-id: a2582a6010bd1c460667a3a080813b33929bd2ac
prerequisite-patch-id: f450d1ca8a70d0b0c4889fa7bc60810732cd7947
prerequisite-patch-id: fdb116ec88160338de9b545ad02dca3f905aedea
prerequisite-patch-id: 1bb763f65bb738633bec985a413be4a0b39693c6
prerequisite-patch-id: cf0fe70af9ecd89401225a0d739d1e88583852ae
prerequisite-patch-id: 233d20ecb86560768ba2254695e2f794ae0fd33a
prerequisite-patch-id: 2c65bf75cbc7de019fb59a2da1f6f5f44b1ccbda
prerequisite-patch-id: f6c27f96bfa2dfe37a71d6a48bf500edc7ae3418
prerequisite-patch-id: 2ed93539ee2e5743a8b68d34576353741ad7da94
prerequisite-patch-id: 15785d74df9b983a08ee214513d117cd636aee8f
prerequisite-patch-id: 16deb75b0307db8f9f95dcbcd0b058722d386ad9
prerequisite-patch-id: de89214094f78ba21945e9b4243f21cb5717d5bd
prerequisite-patch-id: 041397724974afedefe7fb3f08ce6ad3f08d97b0
prerequisite-patch-id: 3c9b26862f31ccdfd5b3a7cdaa39be5120142a83
prerequisite-patch-id: b793e62096271e741444e8eb4184299ef8b2ba94
prerequisite-patch-id: 91df82d0f30fb73e8b9b878006bf0b4e4ea0d796
prerequisite-patch-id: 6ef2e3177b76f42906bdb2f876a94d949e16aa2d
prerequisite-patch-id: 96dc01a93b50f50e6d0528793095217379d66026
prerequisite-patch-id: ed35a1e1cb35e2dbad7689e94e09c387838fb411
prerequisite-patch-id: 0609fa34615f8047be739154ac89e9b2d6a8480e
prerequisite-patch-id: c9862b1ddd7cc6eaad90daef389c702df913a08f
prerequisite-patch-id: 90cb8842412a2ac7b5ccebbdb3630e0b5cc46c3a
prerequisite-patch-id: 8428e53fa41eb3e0b5188b3b6ca3288ce50be8b1
prerequisite-patch-id: ce8e418410c021788d50017dce6e13e1ced60bb7
prerequisite-patch-id: d7866cfaeb03ad945c8796a0308886c139047c74
prerequisite-patch-id: b350801c3eeeb3c80130687e8985f74188fc994f
prerequisite-patch-id: 14eea70294fd0f5002342760d112fc082271945e
prerequisite-patch-id: e4894f9f2debd0a2600298fcad44a1629223866a
prerequisite-patch-id: 62dace911ab970ccff9f382624d1c5f3aaec8aa2
prerequisite-patch-id: 5493504cd94c4ea7cffc218a980e6eb2a14031c5
prerequisite-patch-id: 58e4aa4e5777ee8af8f909a227aec305af457fea
prerequisite-patch-id: 4c4afb6f56b7882ce471cd5fb6cd813217cb2fb9
prerequisite-patch-id: 927acfb611453e2696dc65e8d83272ccd4b0e403
prerequisite-patch-id: 682c0fcd16293da15dd6b4e0f4fdd56ea9e6e569
prerequisite-patch-id: d58a92251520d5f46d780998fbbb0591bea4b7b5
prerequisite-patch-id: 9ed53909e9e1edfb76ab046e5d4e1b35fbab0da0
prerequisite-patch-id: 04ab1af392e362122437d19de2c9367c052ac83e
prerequisite-patch-id: 086b2c2e1753a612863b0971e075e20ea95c4a7d
prerequisite-patch-id: 29e939bbe7d45f377a164a09749d33f532175071
prerequisite-patch-id: ed5b4dfd1b1553d5e2b865c4191a992c30c21132
prerequisite-patch-id: d969c90cffc42d6b8c99170e0d10fc48331f2e58
prerequisite-patch-id: c9284b481f8ad787cb6f490bbeaf6fb808577911
prerequisite-patch-id: 517af516966899a43a303ccdd4fcef2a6e5ee577
prerequisite-patch-id: e0001b9b6263e02e3a731c386ca5ea3d65a51670
prerequisite-patch-id: 23e0e4b58145ca0d78c699b62e7a55ae1f52d70d
prerequisite-patch-id: 85f2326fe9ce690e3b42b077eb785e60e5379824
prerequisite-patch-id: e69f298f8c8562222f37d7966b4ef2c503b60e08
prerequisite-patch-id: 1e0e0263ab7e1bf157d9dd774a96ad9503734740
prerequisite-patch-id: f7496c45397d8f95adcf9830d1f5856927858405
prerequisite-patch-id: 73b3ffc5a8d655aa23423c8302809808d92732db
prerequisite-patch-id: ee62256a5751d04559d1504d46d4c1b7b0c6e6e8
prerequisite-patch-id: c6bd9f74134efea9daac4d73a1ec2c53fe3b585e
prerequisite-patch-id: 1d3a2310932060e996402c4a267c734e50c496ce
prerequisite-patch-id: 9aee8111ab4e57898d5e2f1b623c04f87695046e
prerequisite-patch-id: 86e3bd19355a5744bea9c42f3f8957d09a07a287
prerequisite-patch-id: 83b37fa6a526fc44ff01bf14fbfde8e83d6a7a4f
prerequisite-patch-id: 63cba8a93f43cd5045d451399f4a85fc33456e83
prerequisite-patch-id: 5a2c951b087317bcfe4b0958cdf171eab2421b06
prerequisite-patch-id: 1460d297d4f8e20c6d01c5f0f88188950fbfce57
prerequisite-patch-id: bf08a82d048aa92d7c3862ff32548a0b62c7f071
prerequisite-patch-id: 60ce32819ff090aad6e6ce01fd08e4071bda3549
prerequisite-patch-id: be5c127cd960ce5a25f67e640cf30078cbf79cb8
prerequisite-patch-id: e8b0e2e9e03f0afb57110066a7e6329b5b5a3493
prerequisite-patch-id: fbb79fe85a3568b84e05bf69c9e3ef5dcfc3257e
prerequisite-patch-id: db3f0b67b61d0fc2a5b5101ac6dd6419f5bd3137
prerequisite-patch-id: b87a3bb0452780840085c810052cbbc8faf4d013
prerequisite-patch-id: 8cedafb1b50ae33fa8f76e8fd133f6c2c414528f
prerequisite-patch-id: d04c87a8cf77d8094ff836f0be8d9e042a5d2768
prerequisite-patch-id: c96a7659555049e2cf961b4e21e800d674c91805
prerequisite-patch-id: 68a045c32711359289e1df394e3840881418bc45
prerequisite-patch-id: d2fa002984cacb5fa766ee7c0560e869257f5302
prerequisite-patch-id: 8fe48544ff726ed77247fb5c466c377e0c9dba44
prerequisite-patch-id: 43f8f3c636d8ba075c2e9bed14f234d41eabbe4f
prerequisite-patch-id: 457f419634d142b62065f976664bae627a80a51a
prerequisite-patch-id: 89472d9d3481d1da0bcc227abf1c9e66c790f1fc
prerequisite-patch-id: be9426375ba8f646fc912bd00db34e0ac41bb09f
prerequisite-patch-id: 7d7fcdb7252edd0f0fd8b13de24d1761a103cb23
prerequisite-patch-id: cff3b4ffc6a95a91579b10f461e507ce520bb9cf
prerequisite-patch-id: 1cd684d1263739811ad5bb310b5eb166914f02d8
prerequisite-patch-id: 4a5599a994849532a3ba984976c65effcf3ba0d6
prerequisite-patch-id: 2776f4fbf23e937f7df2bf5387ebef26688275d1
prerequisite-patch-id: 7d3346fffd5232416d40af4724bda9abdfdd0356
prerequisite-patch-id: 28f9cc22406f0f305f720ec3ad943e7f817c2939
prerequisite-patch-id: ea6f447beb65e2d5db1660827674287381b9b9e5
prerequisite-patch-id: 69b66800eb7c001b95df304442a31c3ee2f7e161
prerequisite-patch-id: ce27fdbca7c4d8166ab282e2b25d4ccaec40f393
prerequisite-patch-id: 441d22d2bf1d6c1e4a0eda0d9d31bab5cf9a2e55
prerequisite-patch-id: 53924cdd6f3692dd65ae1f77dddb73bdc3294a2c
prerequisite-patch-id: bb214b1e934caf834883eca585c353e115a08b9a
prerequisite-patch-id: c07154f982dd9782e25deb55b6a000e8b04c11c4
prerequisite-patch-id: 5280433b57d4692ae3f9e97e46bbaf7922370d3d
prerequisite-patch-id: 1c6f12b4e9309129788b424c9284daf6b60ee9b5
prerequisite-patch-id: c4eedfc09679d990e23c6d421aace9ed3d32f154
prerequisite-patch-id: acc4746fe3af90a2ec385ce57e853509295c06e0
prerequisite-patch-id: e244a220a68170d242ab5f961795783c6f04902f
prerequisite-patch-id: 6e65d510de4eabf09a54cc2ffcdb2bed3649f761
prerequisite-patch-id: 8d3e7fe354b3c3265f0adb8cdfaa24aa15391bf3
prerequisite-patch-id: c024806a31922d497318ad5fbcbebfab29a39492
prerequisite-patch-id: 44cc5b3145bc8e99d7fd0d041a6b68b6e1fe6af3
prerequisite-patch-id: b3d585e9af678cfb50903f4e1d9e66ebd5cff44c
prerequisite-patch-id: f931c78aaa05fd13f97c9bf12503294244701b9e
prerequisite-patch-id: 1296062e3df72f7f2cecb668308961fb91be7ce9
prerequisite-patch-id: d75b242588be7739718e1a070295fb63cb7e0756
prerequisite-patch-id: a075a5befd7dd6eeab88fc3c4796537f3da83473
prerequisite-patch-id: 2888d4c35b48823523526391bd4b9ac83a4f8a27
prerequisite-patch-id: 7444dbafcd85b722ff5f41ecb9671fd51b5519d8
prerequisite-patch-id: a8d23c66ec57895c58f75e3518635cd29ac21ded
prerequisite-patch-id: d18b4181c229b683f388f8f9c7ff136e460975ce
prerequisite-patch-id: 6b90a832959fd5cb5ece8899f552ca357353ba58
prerequisite-patch-id: e5cc026d99d74c6bb98b7342eb23d1b590107a05
prerequisite-patch-id: 52fa32f509bad09f82578a7cc4864e0605c88681
prerequisite-patch-id: fb6c31f20c42664f54cbee98abcb2d582ee3833e
prerequisite-patch-id: 2299f6a41d417afb467795864c5b61c3a5f9f0ca
prerequisite-patch-id: cae81655b0bfa395f898148fc1d0d36edf7a8193
prerequisite-patch-id: 536ec4c2b03517f7dba70a41aede81bf6ae5ff7a
prerequisite-patch-id: aaab2c2cc7a4a6f49698e53b44cdfc8607c8a376
prerequisite-patch-id: 670d9d7ff5df66b84ff27bcce9dd01a7532a2ba8
prerequisite-patch-id: 19b180164e39c5608ff6902ab5ee553b748f5859
prerequisite-patch-id: dfbd93a818d3f5eed596c4687835dac991d166f3
prerequisite-patch-id: 8b22664e85536beb02d22879fab98fdf28315618
prerequisite-patch-id: bffb029a8cd6501e407602cd148d5c21e25eb965
prerequisite-patch-id: a32b4d2f8d7184031c0a306976e4cef229347f3b
prerequisite-patch-id: 9017fe93144820e71d2cefb72fcb03ce7313ca99
prerequisite-patch-id: 34312d59de349a80a376206b3404437677b7f120
prerequisite-patch-id: ebe4bb17027660572ae9658cd8905bdba0c16e9a
prerequisite-patch-id: d692bb75ef1969172adeb099a6386c1235013153
prerequisite-patch-id: 9a3f301ecc93d23af91a8fe8fa6e714343ead32a
prerequisite-patch-id: 5e6cb0983183e036b55f4dbc6094117166ecb7cc
prerequisite-patch-id: 95c6751a65b543906730039b811bcee257a3f3ab
prerequisite-patch-id: 54bff55d537cc871a230bb15bdc225e7a61c2b26
prerequisite-patch-id: 79fb07650546965c020b4eebff80eec5efa57bf7
prerequisite-patch-id: cf16d2b93d7faf1cdddca0080daf80545b82d661
prerequisite-patch-id: e5c5aeb4fa79e524855202494d7b3b2cf1651a36
prerequisite-patch-id: f5396c4fc6e4040f291daf3f84035070dfe38271
prerequisite-patch-id: f6ddc0842121b48f63b5fb7734ba813db8674ca4
prerequisite-patch-id: 432b69e0a862428f8fc11ae6a0fc5e41853f015c
prerequisite-patch-id: 1af2cd1ad1c428e398f0414f9cc273848352bd90
prerequisite-patch-id: 3e5613ed437bdc0657edfe87c943176f74ff0b3f
prerequisite-patch-id: 89b164ae83d3673a8f1216eff71ad9788005f3ed
prerequisite-patch-id: 26944c7c5b305eba9ff4e35712c43284e26e211c
prerequisite-patch-id: 3038246646d7e5d23907dfb79b7f82ad5deb8805
prerequisite-patch-id: 1ce089814d735fd92bdbdbf48ddf761b6413f655
prerequisite-patch-id: 83125519e4583cf56e4b6dda892833ea7ced750c
prerequisite-patch-id: 290cee975ff773fa261fb21c0545f13c1ab235dd
prerequisite-patch-id: 19c282c8895c4b32baa31d9198d4b82c344060da
prerequisite-patch-id: 63801c6984e518bd7b57631020492c2aca4f425e
prerequisite-patch-id: ab1a0ed3805aa3944aa6c70a3b94a208ab7c45f1
prerequisite-patch-id: f4d1b4c03fa7bd5291d5f35ebdaf28eab69aeef6
prerequisite-patch-id: 3897c590116da23981b9b7f3b1fd6916ed41d432
prerequisite-patch-id: 722f38a8ebd79f6ee8a19535f5a95ee46a87ccf2
prerequisite-patch-id: 8f773daf68d7d46894e54f701866f38184a0f7c2
prerequisite-patch-id: dac81a32f5cfb6328b31f352470bf8a9567c4d3b
prerequisite-patch-id: f1a0f7dfc35e59e81c69c294a7feb51d58592989
prerequisite-patch-id: 089055482caf7a20f1661dbb33aeef6636f9252c
prerequisite-patch-id: 389ee5b8e985636736446b23f5f601e4fb15475c
prerequisite-patch-id: 384a3037d947723c09c54aa5502911614e273765
prerequisite-patch-id: 9941250aabcd893faa88e89d4140241827159d46
prerequisite-patch-id: 0975a519fb8192ebaf82a6e308c3ccac3f32b450
prerequisite-patch-id: a029a87a1d19c67dfb33d10749c1336ecfc6ba1f
prerequisite-patch-id: af738eb988982b72cf32553b30bb18ee27360dac
prerequisite-patch-id: 69f4cb485d3b5d01be21a3c78c494aef1e1c0fac
prerequisite-patch-id: bacc53a7aa217954866d08dcf10a52348be86760
prerequisite-patch-id: 746f6ab8bbebfa83d44b710b18f25e0c693cc227
prerequisite-patch-id: d1ee1c0a8dcb68c8e4adddc0eaf20484adb765bd
prerequisite-patch-id: 0915d1ff12b43ee9982a8d420acf1ac9c3f28e34
prerequisite-patch-id: 86538de475f1ce84853771cb0cb3348b66c559ee
prerequisite-patch-id: 9409dfa4ab865c51c697f573dc1574c38d032385
prerequisite-patch-id: 9db4775859dce41e343a7a231a1a55928b0a6e0d
prerequisite-patch-id: 57b2b865515799e3f903ebf860c75ffb1a3821c6
prerequisite-patch-id: e9f12cda0765307acaac3aa00e93fd0080329ad4
prerequisite-patch-id: 28c6a5c9c0794adf089c24e5f59586631c5d6b4c
prerequisite-patch-id: 9c603e2a4d0559a6884f896b09d1c8c0589da1ad
prerequisite-patch-id: 3a01250499d35e1757d36f7fdbf1190632b6cdac
prerequisite-patch-id: 92ca7f1db806b24e9695770e923643b850fadb52
prerequisite-patch-id: 5ec5fef9fafbc91fb5785cd215d8da0bcef4d574
prerequisite-patch-id: 6e3441b16c01cfb8efd3f938adcf55a784b5e1d4
prerequisite-patch-id: 33c3e95ef39d41155b602a214fe9f8d5ca4917b7
prerequisite-patch-id: a5e40abb91a8a9c90d130fc5af7ea42559c5d7f7
prerequisite-patch-id: d27b7c7462ff417e351bcb0d7c41949af2ac7afc
prerequisite-patch-id: 12ac470a51ff8c96801e6fd047ab7441077268b9
prerequisite-patch-id: 6e3536e64c991c1d710b855d65a2e25a4fb9fdc0
prerequisite-patch-id: fc051e6207dd4376fd7b7706c54d098b0f818f74
prerequisite-patch-id: f5e2519a7be4d136a6515be6cd9ea4571cf6abd3
prerequisite-patch-id: 8f3ada3b8e14e06422dea35453f08a0d51d15cff
prerequisite-patch-id: 2f968d1f224a034addcd9df6c3b030e4e28af5fa
prerequisite-patch-id: 1794f68df5baa90b3a527f4f4fe53e59b018d401
prerequisite-patch-id: 2ec31d5e0d80527e0c23b08de5821263d4a0075c
prerequisite-patch-id: d151afc82ec8745b93c1ea0105f3b0bba3a1ddd4
prerequisite-patch-id: bba9a199ccc2440600386e0457bce4f80ebe99bf
prerequisite-patch-id: e78a4c5a6af7fc4b22f9bfcf64277037ea49b384
prerequisite-patch-id: 3edb87cbfbdce464089b9c1060cf840a69c7ea1b
prerequisite-patch-id: 5934e18518001a89e3cfe5cbe756b3d9a6eb1166
prerequisite-patch-id: 7c019a15cadd978cb479633000c0f2dacd10bb52
prerequisite-patch-id: 841dadb5f8a89fbcfe3f1bb424c4a60f78a77083
prerequisite-patch-id: e58d6acc2c142ed6ad1a0bf7c06b9dad18dc20c1
prerequisite-patch-id: 679adeae1a72afbce141e4d0218476d31aae2815
prerequisite-patch-id: 68d67a0a3cf0d58f6f58d74517e63f53e93505fd
prerequisite-patch-id: 066f669c9af54b5c645deef1b0c4570a9e6bbf65
prerequisite-patch-id: d5daf8d8f195b54ef670e65f4d219aa7c660fffe
prerequisite-patch-id: bcac5b73c5cbae987864f550021c2f82d3d9ee8b
prerequisite-patch-id: 0b665a0ba6a980db2dca7645febb7219691664c6
prerequisite-patch-id: b460f0f90227717309d566c3a72ad09ff9593cb7
prerequisite-patch-id: 1862f1d2586c0fa27bee90b63f4b54f4d920d032
prerequisite-patch-id: e974c1119d570de40c3f3361afbd6e3a456c8338
prerequisite-patch-id: 303a591a800893f730b616de8e4c4e64497ead57
prerequisite-patch-id: 1fcad282fe5a71275f9ee54eaa4cb8519dcd142a
prerequisite-patch-id: b879726293513fcbc4b7df92bcc976404416b695
prerequisite-patch-id: cb9e1e08eef99b55a9d4a642593e2124b1d59bf3
prerequisite-patch-id: cabb5c5f62947e5b8aa76ad81dbbea20d989304e
prerequisite-patch-id: 992aa11e3fa7d5825d3323e5402387d0b363540d
prerequisite-patch-id: fc8faa8f143a7288e2091443118568a052b6e6d2
prerequisite-patch-id: 4f644256e92f677bba88b723c9247e4bb5594ad6
prerequisite-patch-id: 6312ff8ca67c4fed6c7f2fe706393ed60dc0242e
prerequisite-patch-id: f0bc9598cbaafd91f50a8d92b97c8fc4bb7e559e
prerequisite-patch-id: 25ec3e05b340c787a34b4e255578cb125a1834f2
prerequisite-patch-id: 22bf77ebd8e2347fe690234b649367cc34739fec
prerequisite-patch-id: 0ef3de8f8c951a075dc085a6595a57586f989cb6
prerequisite-patch-id: c606a1320ab84cef1659abe68fbd4eab3f7bdeff
prerequisite-patch-id: c82d465fbca8610df881657b72f7d8dae3b0e79c
prerequisite-patch-id: cdb1275fd6bfe29f07353bd90f54951503886c4b
prerequisite-patch-id: 5b95e0663182a21e01f88e4501b4ac243ce177d1
prerequisite-patch-id: 20e8a12e4aa42674af00439dd442ffc38440e751
prerequisite-patch-id: 0d1e9e307840fb071022df8c4e9cb4d9e88f2b56
prerequisite-patch-id: efdd1ebfca9594bfa429c9bd93f59dbe224b4aa8
prerequisite-patch-id: bc8b9e35515808437851054d99c804028ecdf6bf
prerequisite-patch-id: 9755ff232b993329cdd266b7ef0e1b401ed5b4b9
prerequisite-patch-id: aeb939939e9383d00f242a9cd1839fc41f1a4256
prerequisite-patch-id: a2651fce169be1c8c31e1d9e0e9ba9373dd5a0b5
prerequisite-patch-id: 7a2866a45590b5465a62329b2e7831005a5632f1
prerequisite-patch-id: 1749abaa42e89597316db4a2998f6ae4de6947f0
prerequisite-patch-id: 6fa71c7c79ed25c70a17490f0e3ab86101d9d024
prerequisite-patch-id: 9b7d6d38423a56cf42b0ccc45ac41b2c0522d2ff
prerequisite-patch-id: 2498825797ee2bda24bcb244144737ba069b7930
prerequisite-patch-id: 25293df4400faea32b554dc32475992582dd06b4
prerequisite-patch-id: 3ca576b60af50d8cf4ba78a6a8a8aa6cb90139bc
prerequisite-patch-id: 6e5bc789ad2ac22931789cd28d5449c953c2ca8c
prerequisite-patch-id: 7dad009046e8104b69e6d253e54f6f8db59313e4
prerequisite-patch-id: 9eeb9bd1ac6d76aaa4e4591256fe073526f38a04
prerequisite-patch-id: ed0fd0b37fe8c2e66338774106febc8cddc29931
prerequisite-patch-id: 66083e5f3f4ec4642f94252b242e49b790b8129a
prerequisite-patch-id: 698bd67ad1caaa862d66239a0be98c2e409db6e2
prerequisite-patch-id: 45e37b374a981429338bc38158fce475a0db7924
prerequisite-patch-id: 5a11d6a33add844132489eeb175817f388695e2d
prerequisite-patch-id: 9edf1e582dcac29f4033833b400a4c52f3857161
prerequisite-patch-id: 6e9772f7e705dd3580e5868fa4e248c61be96e30
prerequisite-patch-id: 3f4b587ba344283c7841db9d3d97f449629493d7
prerequisite-patch-id: aa862b30a9fea7a89f6131b294c2932f0bcc78f4
prerequisite-patch-id: 8d852707a4a2eb203205c5465987d1e1d8939450
prerequisite-patch-id: 532af578825a58ac9c295fc8db429cea3b277098
prerequisite-patch-id: c8a27cad31f849aef57325ce65d5ebe285dcf4c7
prerequisite-patch-id: d8b7650cfa3814c5a0cc5c8e0ab39d6336c2b33e
prerequisite-patch-id: 87c4a2643ae883dbb8501900425ae977ad150306
prerequisite-patch-id: 4fbd11c27b6b7daebb9a5dea3c719fcc2262798f
prerequisite-patch-id: ee3f6fe89e83f486e6b8ef6efdc6b2db45a72864
prerequisite-patch-id: ea6519809e16b0782415f7bec2cd5a935d9c73a5
prerequisite-patch-id: 7dd6748c710479f19aaf218b9f5686af15855c2c
prerequisite-patch-id: 77dbec0c65ba3797ed41790dfbaa78203329bf39
prerequisite-patch-id: cc15520a1cd5b1bc5769b51a3e9eb85c2d393188
prerequisite-patch-id: 0732b9cb53a202093b3d9b7750a7f5f1b4f1f3b5
prerequisite-patch-id: 79894442b1be8ca9e078ea88fa13ccbb3df28550
prerequisite-patch-id: d4a137a8f49975f2c6c20fa267a2d9cac61d26fb
prerequisite-patch-id: 06ca55f1a01829ec7afc5b47985686f908afe8d4
prerequisite-patch-id: b9528a32154ccee95e1b0c2b68c96f42c3b1f9f7
prerequisite-patch-id: 48e29f71eb0fe4df5c6a42cd1e8567399d264ffc
prerequisite-patch-id: 1a6a233a806dfd05b93b9a622ea6171ae36417ae
prerequisite-patch-id: ee8f15ff1d084d334c8acaaa451de7d421ae37a6
prerequisite-patch-id: fab180f96e075818a3bf36bb50c35d9a0ff6fe4c
prerequisite-patch-id: f020c4f16e6cb53e014dd3371932b06674d424e0
prerequisite-patch-id: 04dba0554f700b6dae0732976d233bad95182e59
prerequisite-patch-id: dfe758dad73e9c94b243927b0a0e5e3aa19c4842
prerequisite-patch-id: 3e8c0d29569f8e29d5bfa3870a96bc341b8ed084
prerequisite-patch-id: 8ff38cd9ec3cc8d1bd46ea9f09f6abb0f9feea64
prerequisite-patch-id: 284048587c1b428540c43c712ce4e3ba0e53ac22
prerequisite-patch-id: cdf9cc5669dc2f9ed9b86dbb5cb8378ee8e2dffd
prerequisite-patch-id: d002d2307e6117d0b9529616b612c7f49efa9c1f
prerequisite-patch-id: 62483f5db9805228e548613b2e3699b31cfb059b
prerequisite-patch-id: 50995631250545c1952e7885776230edb0de8203
prerequisite-patch-id: 420ac7064075cb87ebac3955096a96c57b88c8c4
prerequisite-patch-id: 44f502402b740e6cb75becf6b4c8a65660cc379f
prerequisite-patch-id: 0c898ffb8b42d2f9f9adce3bf8f5c7c9f9b1d46a
prerequisite-patch-id: b27b8c4f0be54edfa12f2e2d751ee9446d74c6c5
prerequisite-patch-id: c6a01dd5341e303968c6703c098a9d28e30b1894
prerequisite-patch-id: e4e268a418266086339eb9bb4b7eb89a26e5297c
prerequisite-patch-id: a801338ef99c377b3a39bed175649d001463c0d1
prerequisite-patch-id: 35aecf539a386edb1d08f2845cf0af4eef3a1b48
prerequisite-patch-id: bfa07db433e94539f3e376de5d64e54bba2eb3b0
prerequisite-patch-id: e15b50a62e24983d78627dcdb37da674978f2626
prerequisite-patch-id: 75cb7cfee66c5202941eb878d75485393e802545
prerequisite-patch-id: 5e1fc713a9a14275ceec5a3ba41fc951789f3967
prerequisite-patch-id: d59fa648686b5ac19ffd72832cca3ecfe9766d02
prerequisite-patch-id: cea0196f4c053094c5b316cf0a2f1f3c74b63cec
prerequisite-patch-id: 423c19d2e540f684e6815c0f72635c5c39745c1a
prerequisite-patch-id: af78cc216f04520eb441883a5bedfb19dddb9933
prerequisite-patch-id: 38e3c498d39bff4f67130f13c6f27021c39bb54d
prerequisite-patch-id: 57ab685b78ab971efdef882d4c35d6c472be6151
prerequisite-patch-id: 4ba4c4b49dc72df9a1b137fe7a267072c220984a
prerequisite-patch-id: b4e9bb4915ecea620b32d86c21659299efabb56c
prerequisite-patch-id: 69722f3b1418464d0d6a780be1c6e4b74346320a
prerequisite-patch-id: 35822013e41cf00f69fd1ce7e81c2a585beb6e8d
prerequisite-patch-id: 9411fd133b93e2259f5628b2c275cb27c6ad094b
prerequisite-patch-id: 204ac5f376f25945e0c1eb7b52c473a85e058c24
prerequisite-patch-id: 5e305314ab8c43dcc298d8b39b3ea280d045d77c
prerequisite-patch-id: b9ea61092da07e7a0da4aa6fb79e16ae77afa2ae
prerequisite-patch-id: ed80f84b02532fe41d93af19603aebcfd65e949b
prerequisite-patch-id: 2e90de4ef45e00a74fb1aea3f6a1ec727329ae52
prerequisite-patch-id: 5a1ea5e2712fdec1f43728133c456f502c4028af
prerequisite-patch-id: e908105a9e435cd7971675758d2d67d442121ffb
prerequisite-patch-id: 7f30da70196e31f543db1a9ffbe533f7756378e5
prerequisite-patch-id: 5a75b6ea4c4dffd65c4f9f0e7bf171be4109aa3b
prerequisite-patch-id: f7ac979062c0e1379f24fb14a3578e98fcfa9a13
prerequisite-patch-id: 770d132a909d713467f62791d58f74e4effa4a23
prerequisite-patch-id: faee6556ff141b783fc0fca0b0c157f895ae6589
prerequisite-patch-id: 01c0b55cfae6d841cf7bade83264509470325de7
prerequisite-patch-id: ecae17791d171a5cf3eb157297fc9661ece9849e
prerequisite-patch-id: 7402bf8989dddb67dd1559acca2e01aa83140123
prerequisite-patch-id: 043b6dc70a1a301eb9511defc7750860ebc38668
prerequisite-patch-id: 10b57e8866610c0978c4260d916afd5b9e32e224
prerequisite-patch-id: 064b7e196812cf4717d12f88a7a93e66cc1617ec
prerequisite-patch-id: 463d0143cfef3c628a74ade9bcf56acab9fd4efe
prerequisite-patch-id: 0cb3298cf43138b45117f0e87bec3d9ed9f01760
prerequisite-patch-id: eaad7f4cdc7d5390417dabba6771d6c151a485df
prerequisite-patch-id: 812df4210b4b43ae324b90cab8b158be0d09b987
prerequisite-patch-id: bda5e6da3341aae3c94d81fdf8937656793b9659
prerequisite-patch-id: 5a879e86be9fa4b863804ded656c63473d115724
prerequisite-patch-id: d3fa701ee4724557a60d142988d909766d9af499
prerequisite-patch-id: 0015fc2de3fee67993686950687a6fb4c8f7cb49
prerequisite-patch-id: 9f9528ecf9562d9d7ddd8956a4516a57ece6af67
prerequisite-patch-id: 559437e82d7d5f23cfb297f28d4c17ff4ec4900b
prerequisite-patch-id: 73bd56454ee4f5f889f9935763274fdd487f002a
prerequisite-patch-id: cef5431cff055e4afd69f344019cbae2bfe8a7f3
prerequisite-patch-id: d12c6031c57e09ebbd9fcfe62110e4ee9c4cb8bf
prerequisite-patch-id: 637cc1434130d5decc696cf531f9c178d73364ac
prerequisite-patch-id: 8aa89e07b8c417913b1c8f7ee7dd4fc1a16b2014
prerequisite-patch-id: 5eda1bad1a6cc0c1d3110881393ed61ebc7bf130
prerequisite-patch-id: f69230a62e0698f3b01adfb08dfc83e6a987c67d
prerequisite-patch-id: e6b1301238a8a536adba8d2523b0e8ca04119a79
prerequisite-patch-id: 29b8ae49eab547a8c4269dfd4b4a95e9e25f0edc
prerequisite-patch-id: 4487b604781dcd0eeda7b650fb0b6f094f64fc90
prerequisite-patch-id: 0c84b2c06ff3f041a0e70454c6616d9020fdb8dd
prerequisite-patch-id: 827903f984b3fc64441d2b456c35b752d2a901c0
prerequisite-patch-id: 27cea095be6f2b29179c8e17eaa9605c2bad0a7c
prerequisite-patch-id: 9d4bc46a26cfbdc0c44b3c562fda3c0410a2edcd
prerequisite-patch-id: 1188748be98a08984b9a92f77ea22c2f56b6c337
prerequisite-patch-id: a8fe90de44bb1c6d3e1b11ef6d4ef6b86094730e
prerequisite-patch-id: 929c07df466d1ae09ce6a5a62b608d01dedfb17c
prerequisite-patch-id: 8cba3e5d39aa47cda6d3447e775530598ea688c2
prerequisite-patch-id: 3ecfbaf5a4e0ea34cd09211604eaf7407d022bb4
prerequisite-patch-id: f4e6a64dcc187752faa22121b3fa1102d1d64cb9
prerequisite-patch-id: c36a33fbedc157f2c7a9668bddcf36f74ca10032
prerequisite-patch-id: 5aceb6a0b11d6c227597e835adee1848f240021b
prerequisite-patch-id: 273dad87c9a1e1fd0db881dc2d9c4c4d98ff1eb5
prerequisite-patch-id: cd516605e1a2161fa346010b92c909134ac03768
prerequisite-patch-id: 458e821bb39bdae89de21464d6a7bc6c543bb80e
prerequisite-patch-id: c81057935daebd4bc9b53c3bc290cfa9cdedaaff
prerequisite-patch-id: f4be4148aa65423a07cded146922e48b00709140
prerequisite-patch-id: 66571b3afb78e5d74fd0536a138df22c2bdbdfed
prerequisite-patch-id: 721dbecea86184a8538971f6fc3672dd354e9739
prerequisite-patch-id: 4e196ade903b1743d6a8d7bdc0c8cfeca62ecacf
prerequisite-patch-id: 0044313c793b63dd002469f13ede022a16b15196
prerequisite-patch-id: e2d7963a8b58ca242338c0867a8f40ec1c9682ff
prerequisite-patch-id: e4a2a37bba772ad118014208a84db41c22897b4b
prerequisite-patch-id: 775264cc01b43db7e672aac416c806245b00ebbe
prerequisite-patch-id: 675a9b3d9f94d184582df5e740cf211d3957a8a7
prerequisite-patch-id: 7ae711430addd14f3b28fe0a862ef92f643ada7b
prerequisite-patch-id: 84f417e95f2e83cf3d223919fbad3174dea31bf6
prerequisite-patch-id: 08fb8c1651a1af3fc9bff59bc7e2eaa964b6b493
prerequisite-patch-id: ef4f7ea666f0a0b5adb19a364f1d48dfcc83361e
prerequisite-patch-id: a1d44a3efdd35f14db2168891897560f9721f9ed
prerequisite-patch-id: ec1e1b2355b7b33d949b842698ea91acce1a1dc2
prerequisite-patch-id: 7723c4642968049a3f04c2902699067fbaac0f50
prerequisite-patch-id: 5c169a5312e9bf76aa1a7a6b21b986ff90569296
prerequisite-patch-id: 84118148cd324aa548c37fe8591406cec6be7e45
prerequisite-patch-id: eb6b0ffa74114db95b945e6e674f5de62cce654c
prerequisite-patch-id: 85d99764ba65f88aaaed956c140ca9d78ecb42df
prerequisite-patch-id: 8f7bcbf08c92bde3f88f204365c99b964684e881
prerequisite-patch-id: b4bac73cd17eb4646d3ef4ea6b98012eaab59115
prerequisite-patch-id: bbc44946d192b9a42ced16a60c5ed006dfb49500
prerequisite-patch-id: d6a6de83750fa5671312b686a92d3bfa6cf99e60
prerequisite-patch-id: 6f9d54bda524f819c1110c2fce7cd3ac69836815
prerequisite-patch-id: 5923021d7d6119d2846b1479d4ab486013d3ac84
prerequisite-patch-id: a7c1bcd386c91cde581f4802d00b715821a3ba8e
prerequisite-patch-id: e07a228fc5deee1aa04fb4c2b5129fd1dc74ad4d
prerequisite-patch-id: a38023788f3b62b52d8351c450cc44557895a091
prerequisite-patch-id: b390badc1f867b23c5b7d005512c14b545fa9328
prerequisite-patch-id: d7c543308f6de2af847fc4515d9b517bf4e79fd0
prerequisite-patch-id: 736973d8f4393af59e8b01c5618a4175d16777ae
prerequisite-patch-id: 345bd7fed23f85891d17963600888f5267cb4f14
prerequisite-patch-id: d0a8ff04b6df0310a2a8f06bba522cc0115787a5
prerequisite-patch-id: ca308c5f4f9b123b941d09c394681d57152a4ef3
prerequisite-patch-id: e715a03c2180127d509d032f1e3aec7cc96797a9
prerequisite-patch-id: b1dddf090f67bd6234db9caee3c1976b00a966cc
prerequisite-patch-id: 32170e4f396b1bac984c7f14dd5f8d9bf731278e
prerequisite-patch-id: 62d79aff969f2180c506ddb1eddcc8b449300466
prerequisite-patch-id: c3a41abc55ee6837c3447e252d9bbae2a701da25
prerequisite-patch-id: 4b7c2b796f27a75518ad80b67f7bedff59568d47
prerequisite-patch-id: 0ccfae411cd31fb7472b749d2b18b011378780e4
prerequisite-patch-id: f05c48b3a1eb17cf525ac2a7e7464a2ee7eae4eb
prerequisite-patch-id: f4178398794e25ace228166552bba0a42e6c96d5
prerequisite-patch-id: 3336fe52ec48b76a5f502fac43c14573c87a19d3
prerequisite-patch-id: dac8b0987cb0281feddbfb697a1005bdc9b5a6cc
prerequisite-patch-id: 909e6a82e7d87b0cf7c63027cc258688550f939a
prerequisite-patch-id: 6b83a5bbf40f858d8a4e7de23df8624664c3d2ae
prerequisite-patch-id: 5c5b98e274ba9d7c6458084f02d305f7ad6190c7
prerequisite-patch-id: b3e53553fc24a74860f235c66c6ac1b188a94bf9
prerequisite-patch-id: f82ba3d3672a91b693918541e0773b750034a2f3
prerequisite-patch-id: 5bfe61eb10a4487f288be402e64f323dbaf425fa
prerequisite-patch-id: ad0628d1ffa66b02a021bd854153da1185b00d50
prerequisite-patch-id: 16293c19a434bab1ffc5be012555bfb739ac3391
prerequisite-patch-id: 23a38e6b1ac8ee96d4cea92a74902e22bf32ac30
prerequisite-patch-id: ac38629d757701ac70d1b2b7fb66f9f08433390c
prerequisite-patch-id: 0cddb92816cb457d7124bca2c24aafba416acd1c
prerequisite-patch-id: 4a97ed85ac3f78d2121edb09637a11ed5e7b8873
prerequisite-patch-id: 1611c315eda9405844c3651e15543578f7b224a8
prerequisite-patch-id: e296a07614e247b600d652c5f47648c56badf16b
prerequisite-patch-id: 920da6b4be03a7de3bb3bbcecb986a7109d2e88f
prerequisite-patch-id: 58d9efa3f306004890c6a68d32c97300ba5180ae
prerequisite-patch-id: 4abe7b5687fd3dea136cabde00865c45d04ee391
prerequisite-patch-id: 39518cb25ed1a552c55250e36288ad75ed7048f7
prerequisite-patch-id: 54db3a330c4454446a0c0523aba8af5f30996f49
prerequisite-patch-id: 919ad5993d9120bb3c4cd0d7f43cdc8ba6218d58
prerequisite-patch-id: 343176e16afa0bb301f5c93b909e3668694e9d92
prerequisite-patch-id: 1fb12a9e29bd641088d0466a47596efea2d07f48
prerequisite-patch-id: 808d4a397508766ed8ac2d7728a48cf713495f98
prerequisite-patch-id: acfc18bb4adf4240557880c14aae49f43b976cf5
prerequisite-patch-id: bd57f75c5e5b8e2af553c73b63be19e10152c262
prerequisite-patch-id: 1ad9b41bbb319e58757f90b9e563eb43e151358a
prerequisite-patch-id: 3fdabca66aa3ac5584b162cd0183eff4b17aa741
prerequisite-patch-id: 2a81917cf088150d4d6f5b20cfd3ba145476724f
prerequisite-patch-id: 34c1427ba334ab96ac055460e55efc5bb76c7151
prerequisite-patch-id: 0d36d0f0da4e00a2368bb94e1c249e7fd5e6ef18
prerequisite-patch-id: 5e75644f27c9f4067e9f89f882a1c57ebc938498
prerequisite-patch-id: 06fe903704bdf8747b1e84776a3a92a039991659
prerequisite-patch-id: d0486d7b596c3f49de3d082fe4422f1e39138e72
prerequisite-patch-id: e37599d7ad7ef6997f910c94c2ebd9585f969e70
prerequisite-patch-id: 208beb78b05c57d9423069dced05a27033859f6d
prerequisite-patch-id: 7cf208632c7ebd159f6d4d1374217b873c757f8e
prerequisite-patch-id: 964089b505c690a9487a1273cfc65ce0d52dfac4
prerequisite-patch-id: f19036152be4bb6d15d216625a2c4f1b15734f2c
prerequisite-patch-id: 5cf81fa47f82869fd1bbf655a6d8ba36881d808a
prerequisite-patch-id: f67f22060b349ebd9baa0358b710f468bf8c6c1c
prerequisite-patch-id: c36c5ab719431af026901e9d9d3f799ba6924b60
prerequisite-patch-id: b9eed72efe1a4f6452e796e9647e28d7d5a808d4
prerequisite-patch-id: 14c5eb3c626b3d15b4217eea85ebfd8dcd1d87f5
prerequisite-patch-id: a6776c5f48f0febf24959106a2d014eae9f8b4b4
prerequisite-patch-id: 18d63501962b4eaed57704c632f054da0efe6949
prerequisite-patch-id: b6830a9e790f22794beee604d42220354645e91f
prerequisite-patch-id: cf505be91555743cc09c340d36d48eeec02d338c
prerequisite-patch-id: c61a507e8ab1180b0b1a214b36f5a05e4fa178ca
prerequisite-patch-id: 6c22308847a70b35aeedd50f509f60f46f252852
prerequisite-patch-id: 93dbf91fcd77f1cc18a465b7d5bb99118c28f7a3
prerequisite-patch-id: 9c750ce8bb0b85c51b0ac9fb5e22222c05d89ce2
prerequisite-patch-id: 4f1d97a625200f9f0ba8eef3086d7aae8fe8ab42
prerequisite-patch-id: 636c79a16d12680b279ff6f30d89c63161cabbb9
prerequisite-patch-id: 9abb0279f60d77a375d6c71f98be174789b3a122
prerequisite-patch-id: b6e3e0d6ff0d46c457f2ebf5d1fd67aa07cf6ff5
prerequisite-patch-id: 04c619729c4854f2a2961f499a2b4d6c4cec20da
prerequisite-patch-id: 3e727c4294e5a0636a30f963bbfd6617a71c199a
prerequisite-patch-id: b41ce3788f60be3a5ddf32a4d14aa2eaa472bee6
prerequisite-patch-id: 54601fb89b1fe018c42cbb0ea6ed0914c192511d
prerequisite-patch-id: 33c6e88051526501f86d2578e5fce7d1397426e1
prerequisite-patch-id: b482501b487f34702061445220fb4af1978c0dc8
prerequisite-patch-id: 189a84cbdc72923ac43619343ecac4ed1b3d2475
prerequisite-patch-id: fa4d175bd937ee97a4f27ad0e9b7cbead8f10e43
prerequisite-patch-id: 10e07b0b32881dc346dd786d411bdf7e75647999
prerequisite-patch-id: e5d0560693233bfd7af769951e44c7c1abee5732
prerequisite-patch-id: b145b357d4dbc4093c246d71b65e5a1453678eb3
prerequisite-patch-id: ddcba15da6d020cbac920e13fc7f1b712cb099d6
prerequisite-patch-id: 45f85cd2fdcecb6d33445da1d255b4f6805ed9a2
prerequisite-patch-id: 750582bb3966ed52aadbe79d8e46086751d076a9
prerequisite-patch-id: 0edad4a58b5c2b81c59d321557f2b7c8b39de7e0
prerequisite-patch-id: 793578aae1101c723532bc6a89a933ef3491c1d5
prerequisite-patch-id: 50a57121b0aaaefed61f7a47eee6f1f293bbe0ac
prerequisite-patch-id: c0bf569a88695247336214bc177755eab9dcd37a
prerequisite-patch-id: a4711cb4bbbd5809c0d0eb9954e691c41ff402d7
prerequisite-patch-id: 172eb89b296c37dbd893ddbe9fd74399eb3930c5
prerequisite-patch-id: 65a5a5e1bcb7272a48420ef071131f9854848c1b
prerequisite-patch-id: 897bfad1fc960213d45bae461f91304f0e5e0f8d
prerequisite-patch-id: 16663f9fbb7b2ea0d97442de934e8e2befb6c5bc
prerequisite-patch-id: d23ebaa2c035b285b7dcded40e4e724f740bd9c6
prerequisite-patch-id: db9e6168806fb39fbee8e89171933d387ee40c3c
prerequisite-patch-id: 859928c8fb5a8361e86f83d0bd8a1d24b2093a9b
prerequisite-patch-id: 1121e8b41831ed76d2a84f205dcd2ee39f32b8f2
prerequisite-patch-id: c9c5f889ce6abbd0c7f50694acdb043dbe4fdbbc
prerequisite-patch-id: f1f28e18996ce7ddae50e47ea31b52d85aef6c51
prerequisite-patch-id: 8d5d086cb0a4d654e58e5e15e540401d6d1a3208
prerequisite-patch-id: 61559b627ce865c148ca1629f34ef8fbf0651ff6
prerequisite-patch-id: 0e42fcf9c151abcbd78cf7344bc776d977c0120f
prerequisite-patch-id: 3aaabe701d2536c8516539885ccf35a203920fc6
prerequisite-patch-id: b8f9037e98fabe53d3af1a8dc4a645bf426d4c30
prerequisite-patch-id: 3146d134618e7ab0ba40ccf34a8c091c5d34e261
prerequisite-patch-id: e0a045470e49c1d2a47dd43a7219d3244fce6a49
prerequisite-patch-id: 876766b9d75e2a383ba96696194cd29022fd21b1
prerequisite-patch-id: 0e5f52d34a92fd6f2d5c7f7937cbac406cdba5ca
prerequisite-patch-id: cbe73e71941327c7d5e9ede18b034da2e57bccd2
prerequisite-patch-id: 2084c6728c978bc6a7c941fc5c81ae0aef020630
prerequisite-patch-id: d37301b6ee1e426a956adbb524ffa3a21c6ab3da
prerequisite-patch-id: fa93754fff6fcdae87bfed33ce8dd938e4d0cd37
prerequisite-patch-id: e06eadfb7d62823832c851e715dec54834f0e6ef
prerequisite-patch-id: 6ce71cfbc4711e8e6156e49ff222bc973d61d90e
prerequisite-patch-id: 765bfb42f8eaee869ccdc6abb8524f746f92a25f
prerequisite-patch-id: 8fbf5cfe6cc532d5257b2a7317947cd330ab6b1e
prerequisite-patch-id: fffbaeb0a21813057e38bf522bb494142ddd8b31
prerequisite-patch-id: 29d8a4d847b3f51e9ac11f60fd9abf65729966f8
prerequisite-patch-id: effa379aef07c069f790261357912fe897f13666
prerequisite-patch-id: 353a6b86d029c5cb3595957d6da954ff8e52b6fd
prerequisite-patch-id: b79d6327a1785179639dfb6581cc39bca514d7f1
prerequisite-patch-id: d11a218ebe3ca3307df98d3b70ea9c45018f292a
prerequisite-patch-id: 5ac3c829b0aed3e8aed61027065cfd09bba9a51f
prerequisite-patch-id: 2cdff38a1410f827400327622f4f3293afe02d39
prerequisite-patch-id: b537b3e0e655c3e65ce282d5fce8e284a66ef58d
prerequisite-patch-id: d43f9a516f0cd9a87852dee50307da48ef368348
prerequisite-patch-id: c5461f69fe4b088eee864c4acd7a42217d39ce5d
prerequisite-patch-id: 483e4dcde2fd73e4fe20658ae91ef85cd06bad2f
prerequisite-patch-id: c7f2f908744d941f2013c98f03a03c0246017577
prerequisite-patch-id: 0594b138076ebca0f8b48851f2ac4ee4049b8818
prerequisite-patch-id: e4ff1abee02721a2e5bbca2ace2c3fd8f9a629e9
prerequisite-patch-id: 2c6e2519cdfebb76a3d0bf0a0cd2a2ea5fe870ca
prerequisite-patch-id: 8b9c5cb45d0198cf9256957e280b7126d34c1f45
prerequisite-patch-id: cd6d19ba950e546bb4d8b9cf0a68f716f521b64b
prerequisite-patch-id: 8e2b664ac007941389d32ee88765656a4bb617eb
prerequisite-patch-id: 284f66b9ff740f87e3ad6a6827eb91b36f22ee6d
prerequisite-patch-id: be7d0ee535032b5f3668cfe69c3d77678c606149
prerequisite-patch-id: a1825339f4c4c061d36eba9fc4be23740b51b7c5
prerequisite-patch-id: 06cc4118d31968433e1f85b044c4a7e26cd69d3d
prerequisite-patch-id: efcdc3a29ca101accaa04a07c63dbd20d2fadbff
prerequisite-patch-id: 84cf32aa322156c703ad3857fefa1594bbcfd81d
prerequisite-patch-id: 2079f118308171a0f867ea86da790e8c915a6d02
prerequisite-patch-id: eda3b01a0262a1a53d84725a75f7c8fdbf018072
prerequisite-patch-id: eebcd1c3a373e5abd86aef70175e832b8ea48500
prerequisite-patch-id: cfa0b6d218cb742b5cd1dd95ac61187ad430c229
prerequisite-patch-id: 8b6bba2a3450495f6a09d4f6446599a03893f3a2
prerequisite-patch-id: fe2b50fff6bb39600d0456df23474b1c50e360e5
prerequisite-patch-id: e3af097c3c725a940f2a27c2ac027010ac65a9b7
prerequisite-patch-id: f1c4fdd3a84993c3a7b8bf796068b59daff53818
prerequisite-patch-id: f8bb119d26d88f0757d10173563b14a23e66d0b9
prerequisite-patch-id: 32796f891cb8e2012cf734b6d7cd94a88f2293f3
prerequisite-patch-id: a0df0a9b04a5d0f252ea54a39969926af2e7ed9a
prerequisite-patch-id: a7d56fb9c4b0ce829c13f826520b87a55f9be295
prerequisite-patch-id: 12836b2a35c4cd551dd3af6578fde4e7119ea443
prerequisite-patch-id: 6f29316cb5b085a4d04063df64743ea8e333374b
prerequisite-patch-id: 636b27aad27b36fa64257e9496ab0104ad59b6eb
prerequisite-patch-id: a38e4989bc1042688c4b63184dffe33ce322eae4
prerequisite-patch-id: 64735ae9913c3a4c13fbb20a7ffe2defc2a2a83b
prerequisite-patch-id: 95a760abab906df016bed3f902b7e132a5622a18
prerequisite-patch-id: d122b3e22dd2e0684db4b727d851d04206c8394e
prerequisite-patch-id: 192a6382bccaa3d91f07a79da43b3ea6ff80e402
prerequisite-patch-id: 8c4f3a6e487548720fc1c36e3b67d869043970c1
prerequisite-patch-id: 7c4380cc52f8541a6e787a53da8d1bd51aff9961
prerequisite-patch-id: 3637a1078531745ca31b78ff19d9036365d97e44
prerequisite-patch-id: 6f7d037dade4d0f21014984d798f6341dcd2358b
prerequisite-patch-id: 01f1b46c8a709308e7d53e70ad220712b7dcb5f2
prerequisite-patch-id: 883b473fa39a043f7222c1fd6ad5132fa4b80e6c
prerequisite-patch-id: 3268e4d57017e38ddff42d16a2e1be7c112c8ceb
prerequisite-patch-id: 7ac4059bf34412de9016fd9bd94b2fc08118f22e
prerequisite-patch-id: c230ee1c98b8842a3a6d31cb5a76e15bea915c15
prerequisite-patch-id: 30f170206d7446f77b7d75522f364cb3c3a45bbe
prerequisite-patch-id: 572238245ae722fc2e324d6d391439f1cd7d4afa
prerequisite-patch-id: 2707bf58107c8bfee589f46bafb1b868bacb90fb
prerequisite-patch-id: c9beeca324e8bd984cd61d3a3c606854d6168d69
prerequisite-patch-id: 983dc1b200d748bb3416d7b7a81a59086ccc3984
prerequisite-patch-id: 8b7408ca5c667854e37342a2e2680eb43735887f
prerequisite-patch-id: b7b521cd42011d1631f6612dbf35e0f160bd0f02
prerequisite-patch-id: 4740b95e57df759c7a23fbac770ecb8410fb912d
prerequisite-patch-id: 63fa6c30408a0aafe0a43d5d8e487d78b9dda89b
prerequisite-patch-id: ea83ca31d98748db013eb292bd71aaa5cfc736c2
prerequisite-patch-id: 80281570d9be74471565e79bc2b0b93fdf29b672
prerequisite-patch-id: 6c790f45688043e020e438436c7c14e276fe1443
prerequisite-patch-id: 18041719de9481b6dcde0e670a8a38fb47934146
prerequisite-patch-id: 53a48c64d56aa28f143e1304b2242877ae16d7be
prerequisite-patch-id: 62a1d1d5b13d8da7c94ad4b23a58162a5e2d92aa
prerequisite-patch-id: 2c2b6d2373669a575852f2a99e7c97e4a660a88b
prerequisite-patch-id: e9ae2aeb6fc391d840d902d0ab58ecdbcb820aad
prerequisite-patch-id: bea87ad5c9ddd7bf3f3bd1b505249e491f3273c9
prerequisite-patch-id: 0d312791e970833b2d488bd3f0159339bd58d5bb
prerequisite-patch-id: 648d4f9daacdbb405404b9a52f75e17c99959a2c
prerequisite-patch-id: 4d1d1a62f504ce842a7daf4e4458425276a5b093
prerequisite-patch-id: 85bea0e329abfc46faa33aabaf3806b425eba7f3
prerequisite-patch-id: 63f6b9c80cc911f19c9b0584f27538a3ca9d4001
prerequisite-patch-id: 7f04c14f63aa50e011361fba1c2c0b179ae89926
prerequisite-patch-id: 619d191d7e7718d0fc5a6d354689e3f310d64383
prerequisite-patch-id: 325562f375e21d8988c73f5096dd719c2ecda2c7
prerequisite-patch-id: 22f3ed17298f6e6f0c14a9faa363ab8df9401e60
prerequisite-patch-id: d67f92a7e3b612fd78c1c83f35b527add683beb8
prerequisite-patch-id: 0c040b72c513e969a6f61edc2057e1abb47a3f43
prerequisite-patch-id: 2602a564a4b8fb30a0145ad876395515db731db5
prerequisite-patch-id: 2b5703d9ac3ceea4d636853c813ff923c98c6202
prerequisite-patch-id: 86a2055b71f842342859c47a9a209415c9b09089
prerequisite-patch-id: bb6ed87141f4644c1033d7335fc0e9ba7efa788d
prerequisite-patch-id: 986694be3716eec824eb3c90ff92952d47d4315e
prerequisite-patch-id: 47b08a71c6d77bb2fb3952a1af627337da46c54c
prerequisite-patch-id: bf8891e49e7bbf498b8798adf158df96cf2ebf77
prerequisite-patch-id: 6e442be0319ad6c4ac79de559d8f9148d68af382
prerequisite-patch-id: e8ab6c424bc2d040ca07ccd501091350307f88d2
prerequisite-patch-id: d818403fbd427b4623b9723341d1978c487b6937
prerequisite-patch-id: 628c5a386b73c4efe71dd8113d4e83c4ee99552b
prerequisite-patch-id: 1ac395bb2e3903fade69caf3cd2ad66e9a685d15
prerequisite-patch-id: e3885688316e1d6071239d3823b01ddcad1844d9
prerequisite-patch-id: ce49633294b4c8ca6fa1b1da0598bb4552ea033c
prerequisite-patch-id: e0b34570bad66275336678803a1a590a2bd32696
prerequisite-patch-id: c402c9fc9d70e6790f3284a04986c171e7ebd969
prerequisite-patch-id: ace8a9c9db11025bc588fcc5a59b2d21963aa9da
prerequisite-patch-id: 6577196b66dd29305f316c6dd02b86bf33810b03
prerequisite-patch-id: f8a6cd179b73cd21533daa98d45957ca937a507a
prerequisite-patch-id: 9e07e1e5d9bc9a2195f0dc58696777939e6ed69f
prerequisite-patch-id: a3628a8b2edc024958f241a29a92c0588933702a
prerequisite-patch-id: d48c9dede9b6f9784b20605f62d9531c3d971f93
prerequisite-patch-id: de5f2c4a44ab2d3f898349db687614286bfffa7f
prerequisite-patch-id: d3cbbd51fcb4f4f8aaac9bed3c458cf5d8b022c5
prerequisite-patch-id: 74f7e6fb0707e3e5731f5d973ce06ae17c7b21f3
prerequisite-patch-id: a9c7853850971165e1310cd92bfdb2eec3205117
prerequisite-patch-id: 8aa179f7b2e5c013172ee0f8da95241adc50d351
prerequisite-patch-id: 902aa81e545f70a4d3eab8b3aa280273f4654065
prerequisite-patch-id: 29557a772d2c30af1673716dc2c13ae188a784ee
prerequisite-patch-id: acd909a2ee2624597d40b8cb422c3f9c001f6b60
prerequisite-patch-id: 01ec98820e7db115bead39fb3a1c3837645d36b9
prerequisite-patch-id: 5fc388311016e26ebecefd4142b9ca89436e5512
prerequisite-patch-id: e4357bc1d7d0240fabf9513cd5fea57999b69479
prerequisite-patch-id: f7e65a1bff1f561e26752f4c0f17c55702baa310
prerequisite-patch-id: ed30ae46d50e8f906a84ca0c5b7488c904814f5b
prerequisite-patch-id: 291b66a40bc69ef88224a484ff49bd46c75d7dd2
prerequisite-patch-id: be6c4f862c4eeac3e92b150598c1b114e81da43d
prerequisite-patch-id: 55b3e43eaf882f4e466096a31182433d4b3cd94b
prerequisite-patch-id: 3566e8a1f298f5feb878ac68b26b9822b41a1a89
prerequisite-patch-id: f92c80a987c8ed66df0edf9f5aa566af4b2962e3
prerequisite-patch-id: 3e245507aacd5c79bfb309c1c551df3d5d6617a5
prerequisite-patch-id: 21cba613fdce456f845033af9745e871b6a48938
prerequisite-patch-id: a00de59f7c735d4593a791b969c5f08a47634be5
prerequisite-patch-id: 101b5bc377a0dce612b7f8656afd16ab6c5b3cef
prerequisite-patch-id: 3e1b32a1a2dc6df1892e63b8fe502fdf7e28e439
prerequisite-patch-id: 509c58c079dca695fa54bf9257f95102b3ebeac8
prerequisite-patch-id: c107c1fd0e7d2e78d7ea1d58361f1b4de1a032ca
prerequisite-patch-id: d77f90914d8748ab2ec36082b8412d4ebc1dcf53
prerequisite-patch-id: a32802598208de685d76f2df127dfbfa55945de1
prerequisite-patch-id: 20bfed2d4f255213c1f42c0ed32e4efc0da2b328
prerequisite-patch-id: a4377d84a909785cd93c00e138adbfd3fa94fc82
prerequisite-patch-id: fbc0e4f7dfe136d85b2c4ff3675a6d3dac303c22
prerequisite-patch-id: 1bdec01df9d06ef60968ecaaf83490b2ca1f9aec
prerequisite-patch-id: c1ecd39d746a60d923f6783cb0ee0be5653c7584
prerequisite-patch-id: 51f5bfe1e3512971864a684f8c27ffe24af63576
prerequisite-patch-id: 22544cb1088d02f7ddf389f3e9c9f5fc53ee765d
prerequisite-patch-id: 257c83615a2ea293ce814dd81637b698b2978eeb
prerequisite-patch-id: dd98a0e2d23e65f9fddbfd41cc58f62071366482
prerequisite-patch-id: 732628a32a667bdc4c43aadaf79f882e11a203cb
prerequisite-patch-id: 4f94da71920f3ef6f3df3d16d526bf179c8da467
prerequisite-patch-id: 3feab955d207448d61962cac418577ee16c9ef9d
prerequisite-patch-id: d03a0478a0cfb5c0459985566118a32225e6d856
prerequisite-patch-id: f8899d5c36554a3f551aad8e452c2d331f031cd8
prerequisite-patch-id: b2e5c24e8563b91d1c9b52c21e782e543f4e553b
prerequisite-patch-id: 4c2665d2c01a0b982cc3e6baa2c1733afd20a870
prerequisite-patch-id: 97db0c5ecacd41faa4beaf2b17b9f7a43d6a1c1d
prerequisite-patch-id: 74102b9ae89faab80b42229aa6cf080b73341c20
prerequisite-patch-id: 9be5e927848387f50d81f5604a57090e6077c158
prerequisite-patch-id: 3cbd3874faca8c9ab7e6c5c2a1545883efd1afa6
prerequisite-patch-id: a35b5ac12cf6eb7737716f4b035cc5f47f7e531d
prerequisite-patch-id: 1bf1b4abcc3f950d6d42bd93a4f970123cc8020b
prerequisite-patch-id: d6af42c821a57b642f62dff617bcc1127f321b78
prerequisite-patch-id: cef02a09ced689c3f1ca4531372c2a3c6c8e620d
prerequisite-patch-id: 484f431a72a0c205ba02e715b630ac856517c914
prerequisite-patch-id: 4f12f3232a3d566c0626eb857d2abc2e40f6ad3b
prerequisite-patch-id: a3586a90f44843b4dbefa8f8372c6fe83010b157
prerequisite-patch-id: d76da7eefa99d562ae7655a63e3ae1a62ce7b0a4
prerequisite-patch-id: 1a89c07341f663812ea6b4e3fb7fda568cb4266f
prerequisite-patch-id: 0533a2005658b3573463e12b38b83a10cb2a8f7d
prerequisite-patch-id: d045f9c9c7b760c7d39971d090e43cc34c630d82
prerequisite-patch-id: f908a2d645a5cfe42901a9d3b5af0d86f098de31
prerequisite-patch-id: a3142600f59ad0bd821390ad3bb618138e85fd5f
prerequisite-patch-id: 54047af7a588f4b8cc9099c53d99d1cddb48eda1
prerequisite-patch-id: 6e14dca5e345d1ce3301a285a8c21eb7b30a52ea
prerequisite-patch-id: 90eeb7a4167b3cfbc84788e0045fc6dfa6002e6e
prerequisite-patch-id: 20538041ea440598c44bc93ac4031123a8fa1eaf
prerequisite-patch-id: 8f5e0268cee6bb09d451ec5e79829811b519ba55
prerequisite-patch-id: af24e2aa712e0da72c83d23bcb29cfa14279f499
prerequisite-patch-id: f18e257b03a192ddb87c2db1538d7ff2fffcd019
prerequisite-patch-id: fcb3bf8e9d064d9f8d60384a42667b98f2b5352b
prerequisite-patch-id: 12e48c72fa8f79a428426db6650a1ee74428a8ac
prerequisite-patch-id: 0ce0d142e76a74b556f08c9784614960d7ca2c7a
prerequisite-patch-id: eb094216b11316fedcfdb9c4e2d913fe9bafcf96
prerequisite-patch-id: 1d8dd0210ad21905dd1211928d411a2e85536b07
prerequisite-patch-id: a662561009f7623305c9829060437fd8426797f2
prerequisite-patch-id: c470194823f82c5ab21e726bb8576100db14a307
prerequisite-patch-id: 91dccb672a8128d61499828eccdb493300d7c4ea
prerequisite-patch-id: e9f323aa01b38a30030dfc5309e3ba82598045e0
prerequisite-patch-id: 74770e15f409988c8ac61ebcd4cdeabb36d20230
prerequisite-patch-id: cfdd4c1224cc2034c74bd274ad5eab68f2f3494a
prerequisite-patch-id: b7fb6694825cfdbe06c35c88dfc846bff3e89447
prerequisite-patch-id: c40cf1f798f019a995e68f9948152f0a7d742114
prerequisite-patch-id: 5953c505fc6146637149f765ae1c9bfa25d92f72
prerequisite-patch-id: 02b147160fd099c3ff6c5a9ed06b2b9cad6ecc20
prerequisite-patch-id: b9dc616db5bec917356afec776db5427488d54ee
prerequisite-patch-id: 94cf53ec71503faf1c3757c30f744f0f79e64394
prerequisite-patch-id: 299215ed5af78a515bd887a1cb1ed3f75e92a455
prerequisite-patch-id: 879f9f976f85843bfee73f512fd1faec1293598c
prerequisite-patch-id: c55603fa8127aa78ec3b566e1a8cf4a007aaf354
prerequisite-patch-id: bc805518b8f8c62e9314406645f20691e3f0608e
prerequisite-patch-id: 04411d10601bda0195324738b5d615be84bb4663
prerequisite-patch-id: f625709036dccf0748525b2ef3c39d8abc72b923
prerequisite-patch-id: 9688ad13e09132aac36723b44dcb3b3e02397c52
prerequisite-patch-id: 6094dba1c2c27e872879dd007c1b64b4a34f607e
prerequisite-patch-id: a5cda78b0761b1df9c7d7f49c2cb25c932cf2e9e
prerequisite-patch-id: 0a56ff479947dcc75a0f97bbbfaeaf5f4f1fd289
prerequisite-patch-id: 46e3902621b83af797b5699b35c4419963de98d9
prerequisite-patch-id: 04316dce352d637b8c246dd313c6f08ac1fe11f4
prerequisite-patch-id: fac85c182391d105014207e15a678c1aa724cee2
prerequisite-patch-id: c87f8502c4bb487f970c6598f31071837958d272
prerequisite-patch-id: 7b4cfa99e3ef34d282a31d67f127dba19ef557f6
prerequisite-patch-id: 7159354471f1e17ee6e920cb3dac8e6649ef8846
prerequisite-patch-id: ec13cc10be14ad928e3618e572f1c3cc6b118ee7
prerequisite-patch-id: d19bcc10e81adf8af9660aec6552955355fd3939
prerequisite-patch-id: 93e862a1b3a8f0bd45f726edc7e3286d314f0b1e
prerequisite-patch-id: 15e8f40beebdd32a09b20d05873281b32bdacf0c
prerequisite-patch-id: 8af6738c2531587244a099c1f9ac3f47388e1af5
prerequisite-patch-id: de7371c3f91ba2225cb89abb2a8c53fd1f341fe3
prerequisite-patch-id: d1c08c269db3a3179cd7b92db37f4b1617677a0f
prerequisite-patch-id: ded763abaa96c9c5c56a7e6c4275e9777eb4bb0f
prerequisite-patch-id: 7a5de3b8edbb4cc915768080bd25705225454a9b
prerequisite-patch-id: 3e2170029e314759541cb18b9911cb1f35d36fce
prerequisite-patch-id: 2b4bfb92a2b38df9dd09ce6bf4ca955f45c32188
prerequisite-patch-id: 2e904136d3f1ebaa5b7d48513d570ba2808a0932
prerequisite-patch-id: ffe5b23260f8ab2fa5e05e3e09cf7964328e85a9
prerequisite-patch-id: 19378bab4205f1d860a7844303b0f15e07400b5d
prerequisite-patch-id: c2b3e3f1ac6497f0b6cc74ff0d651c9a2bad9b34
prerequisite-patch-id: c90027987d943b6c59ce2750bd3f184c7d5c8185
prerequisite-patch-id: b770c7ec1f7bedef2c1d73d2c678c49c64a7aeee
prerequisite-patch-id: 8daf565c297852369b758116d4dba029e5ac3a52
prerequisite-patch-id: 8c339b0add5d57790d4dccbc8fd77dfc21f57d1e
prerequisite-patch-id: 1ff73f7bae91c98ac7b7d0f9f98a1f370d1680ec
prerequisite-patch-id: dadf3841aad46b07421bc9777e68e66029c4876d
prerequisite-patch-id: 84d3024e36e5ae65ad760dc63162b69b4c32a401
prerequisite-patch-id: ccc414960ca4a8f70213ae221096ba84523d5fb9
prerequisite-patch-id: 8756f492878fb23f3b386499261c699febd0f2d8
prerequisite-patch-id: f161383494740947fdfe7f017397b3f97a3207f4
prerequisite-patch-id: a7056951429c16eed376f1c1eb7054032115ef9e
prerequisite-patch-id: 37c994fd42ff102640c65b8244c042a5155c5761
prerequisite-patch-id: 5ab420dc6ec07bd4be62b98d963aedf2cf0fbb2d
prerequisite-patch-id: e9bc6195f5d05d19881194dce9d34cae8aa95bb3
prerequisite-patch-id: 9ea2ebec5d021b5fa082a70ad23a86890a66abf9
prerequisite-patch-id: 5b4c3a89194c414736cc40272e2e6a0f9f435411
prerequisite-patch-id: 8dc9b3bb62014d3d743c728604f387d5032d26be
prerequisite-patch-id: 0ca5aedfe43a8033e3b580d3c87bd1a709c51ab8
prerequisite-patch-id: 3ed6bd5d285246540719f943190a91d88dea43ad
prerequisite-patch-id: 589f678214f7d3829b9c7c8c17de16d19fe3e618
prerequisite-patch-id: 145526d8b67ccc9e6850867ec79410e59e902694
prerequisite-patch-id: ae1a18e8bf6e2d1208b91d722debe71c7e3480d8
prerequisite-patch-id: f7684c465eef3391344b27397000ff1b9d9b7f27
prerequisite-patch-id: 3f15198ea83724195d891e8c8975499eff6a1db5
prerequisite-patch-id: 4f5d98a816ea35ad87bf30f890a3807d285e1a8b
prerequisite-patch-id: 2cd9dc0811e5613e14684c09f0e682ce5dec1d85
prerequisite-patch-id: 092028c8734d6ce55e3d8643f3d2166f58228864
prerequisite-patch-id: 2fe993b480df54e681c9752b021230aef35c583f
prerequisite-patch-id: a25d3aa7dbf953cee7a3651e6a8f291bca74f359
prerequisite-patch-id: 64458792b1b192e799b9d9f519b89b65ddb8e5c5
prerequisite-patch-id: d3595d91ed82610d9188a1be15c17e9dff3b998a
prerequisite-patch-id: 0cea5038c8b57ee9471dd25145dcddf4f7888962
prerequisite-patch-id: 0a4e76f6fb643d418d43c7795a11154b15c1fa23
prerequisite-patch-id: 7b4eb3fb690bb9757de4ca22f9509e246d621cd5
prerequisite-patch-id: 7386a9281a73f0e0687726341d3954c98033bf7a
prerequisite-patch-id: c8444fb06db687a7501f9ce9345e665b00fd133f
prerequisite-patch-id: 3e611415873ccc841e24004f68e5c6e282b9412e
prerequisite-patch-id: 4a00f70b775d979167570eb161c21fe0461c9166
prerequisite-patch-id: 061bd08f9b5702009dc8a692a123675bde15793a
prerequisite-patch-id: dccfc82218ccaa4fad357cf5cebd1c89372dff34
prerequisite-patch-id: a38f1f10635f3b2c683e7d3589a7a3a4e76068e2
prerequisite-patch-id: 2aefd777b3120b263e82ad9f078d34646e69c420
prerequisite-patch-id: 7af7b7dcfea2305837e20e1447fd6913474f11b8
prerequisite-patch-id: 5b3fcb913ab82da2f34753cf435a01f029235cec
prerequisite-patch-id: fe23792dce94f73e58672b48e7d648a561ae696b
prerequisite-patch-id: b36ebaca40e89e7311283295eacdab168a33f9fc
prerequisite-patch-id: 5949cc30210a2cd533e2fe3d5271167f87552de5
prerequisite-patch-id: ffc7155d5c142c37aaa3e8ab7ea7169a3e495099
prerequisite-patch-id: 256dd6bc11b1a54433459b6685b45af067a98f43
prerequisite-patch-id: 6620c2bf909451dbca060a0bbd1b0b00874ef7c3
prerequisite-patch-id: 6180283915904b42ac281af10fc885c0c9c76adc
prerequisite-patch-id: daf105aa715ea99b4cec9adb41c7504d70b88d8a
prerequisite-patch-id: eee74983072be9f833678af7d130966537664443
prerequisite-patch-id: a7160ae8e97c5ee7aa3d97cd07ae1cb2b4e20cd4
prerequisite-patch-id: 7a1faeb151663039718b566184ce3ddc30665162
prerequisite-patch-id: e61ec58bd9d204a7672a54b5f59246ab471db929
prerequisite-patch-id: 9bf158d7dbab321b5f66fc337db6c16b43ca8965
prerequisite-patch-id: 23269123477dabc909023a908eaebc27e33f70a0
prerequisite-patch-id: f995967e0a6bcd64d0031c348a7ffe426f37c04b
prerequisite-patch-id: 8e9f20e196a2794ae337e22294c7a83556b7ba60
prerequisite-patch-id: 5d475629446b445f8ebfdf0bdee77d20e58ba5d6
prerequisite-patch-id: 7c823f926df87299ae41fca2feb0cab7303dc459
prerequisite-patch-id: d5d085ba4b0dccd71426283e2963b83aa8ddd889
prerequisite-patch-id: 4ec9e858f3a0d64c7049670a01927fbe6cf10fb3
prerequisite-patch-id: 2285acb7895ea1bd60e1b53d734fc07da35c184f
prerequisite-patch-id: 3d4e74e45801099943fe9e688214f3b8a60980f8
prerequisite-patch-id: 6b49ea2296bb191a8cc940c93daf31b5d472fb2d
prerequisite-patch-id: c5233d71f445624d104f700f12c4e721797e1d9d
prerequisite-patch-id: 43ac887f08ac4df7b127bd0d3acdb55ec08bf9ae
prerequisite-patch-id: 3abd225254fa426dff3abf5baf8c62d392d9ed81
prerequisite-patch-id: 27f443352dadf303b2443c5f2632610728de6165
prerequisite-patch-id: f38fed9ef190059f86979f41da6a131608e9c303
prerequisite-patch-id: d8a7d2850d5cf5678fdce707555c22358974f643
prerequisite-patch-id: cf2df0e07b95e2cbec2d18ba6c1a0ac473c76d91
prerequisite-patch-id: 0fcc9abb4d245634538f7385703d4af996fa951c
prerequisite-patch-id: 7e42b1ae500ed53779d2129eced553ce28c2fbc6
prerequisite-patch-id: 6e1c101a2a08cf900a453231b8259216efc625aa
prerequisite-patch-id: 365eb7b9a9c8f2da80f2e8ce8baace8690ba4ad7
prerequisite-patch-id: 528142feb865d728566ab1697acab67f0cd46ac7
prerequisite-patch-id: 071097e169c72c3892504e010c126a837c9d6294
prerequisite-patch-id: 49ed34c1c281aef200bdb4e950195015ee459d26
prerequisite-patch-id: 6b54fdf5816509b431a557e7a394e6ee4495a5cc
prerequisite-patch-id: 1420469904f265f8bdddb422517dd5e713cee0e4
prerequisite-patch-id: 027f5b7d551d1ca4698f2b0063f29651c919feee
prerequisite-patch-id: a4a53279264f84cc00aa21e5c74625ac52741bb7
prerequisite-patch-id: 36f018e76d0c7923a8259c8a8fb244ad92bd0947
prerequisite-patch-id: d37edf776f79670c0053d9ad71ff4f7029293cff
prerequisite-patch-id: 8de06b65fd34ae59f194d15eec39a73cd9be1fee
prerequisite-patch-id: 2bca096d5cf1564f13f981efa0c9878bd0666f3c
prerequisite-patch-id: f6ae1e3545eba5c4ae3d57068763a68c3fa0a09e
prerequisite-patch-id: 5ac84de269639d408016ee8a4fbb5b04b87d10dc
prerequisite-patch-id: 4f9e954d51bf098324169b45c4377723ed8aff29
prerequisite-patch-id: 9e5e58bd47d1f35aa49ce7ceda78757320f6ba31
prerequisite-patch-id: 8cab8eccd5c1de7cec9a55bf06429e03639da9c1
prerequisite-patch-id: c784f2158188cc1f994dbf29bb0bc8cba2cb76bb
prerequisite-patch-id: 8c864522e29d602f96253f97ec113ea4bc9f82e3
prerequisite-patch-id: 777bbae287549bb3e9e6b3ad807f32b6c09f9fbb
prerequisite-patch-id: 9dec602593087b787f841d986826c14401eaf494
prerequisite-patch-id: bc940c03f2f415636659acf25720ddda4d73b1ff
prerequisite-patch-id: f71a0da68709f095ab264267d6a5751efbca323b
prerequisite-patch-id: 456ea2965f749c582481f400ccea0f76b0aa3b6f
prerequisite-patch-id: 8a7f8e3d272e0b07fea018ff026142601937c269
prerequisite-patch-id: 342c770b197398ff5fd8a601e8a4b3ca7b413959
prerequisite-patch-id: 23b6d25833a041982757a1d64ffab7714b073682
prerequisite-patch-id: 08cec7d85fb4138f26445f87d60e0a7cae937a91
prerequisite-patch-id: 4c88dbe0746d1581e44885e1a036ac7ce8cfecb6
prerequisite-patch-id: 229ee96b1574c243cbf117a14786586146128fbf
prerequisite-patch-id: aaecab0d557468295a3021eadc5b950f0098ac31
prerequisite-patch-id: 3c70dd9b8587b1434bd6d48c7364be8a94438b04
prerequisite-patch-id: 2adf8bc5bffabc6811432d791fad5a29f34509ff
prerequisite-patch-id: f8d94fb2f075b843f854a165128184f2efd6adb5
prerequisite-patch-id: c1948e6e0310c267da0da8b1878711d160b2e435
prerequisite-patch-id: f43e2895cc83204cc528f121710f95ca2a186ce6
prerequisite-patch-id: 60793bb53de9bf494142cc7599c5729fbef47e45
prerequisite-patch-id: 7edc23530c3235f4c1f8c124329817051bb753c4
prerequisite-patch-id: 84f9ff82134b39c942e5065220940f52180fd66b
prerequisite-patch-id: ad358e4c31a36ad6e4901a53680ff68fc2657f03
prerequisite-patch-id: 2b41debac0e4c60bc3234a232e94591f8b5c909b
prerequisite-patch-id: d0f0e32f456d2e98ed23b85c7c0cbfd78e018890
prerequisite-patch-id: 8f014f277d998f7a058b871d1def3d0ae99d74bc
prerequisite-patch-id: fe0a5898429255a5fc81dc236025ba90dced7c1d
prerequisite-patch-id: 91b21615cee8f3048e3960a4c4d352bc97437a4c
prerequisite-patch-id: 8fbaa402ded833464d2d317b63223abb5311f824
prerequisite-patch-id: acd58232f973a42903bdc43784e987f3aa8a7571
prerequisite-patch-id: 74024d9c97053cd113c9f2e493afba7c1f4fea2e
prerequisite-patch-id: 75e2bc5a17116679261a9017f146d9bb50873b14
prerequisite-patch-id: f1e16568c726d2cd8b686e73c122555d41f46b29
prerequisite-patch-id: d768dfb5184f17c74186a852d22702e911e9b390
prerequisite-patch-id: 705ab214e727227c72dabb59a68daa541550209d
prerequisite-patch-id: 7ebfe7a5ba012826771b589312b3ef056a0c3054
prerequisite-patch-id: a1f0d3a2b51efb06873d7c022b3c13dc71ee8027
prerequisite-patch-id: be95390271b76fa32e7af24d925798b981156dc4
prerequisite-patch-id: 4ce1693fa4302a55f2d72f6d94142422cb416f42
prerequisite-patch-id: 2362435e32decea4b1c18e8a3db5d266882d136c
prerequisite-patch-id: 6422a287e8a781dc469ab1642928f71a2d9c64d0
prerequisite-patch-id: 7795c7f718d99be9cfcc50aa3439e93e3a8897a6
prerequisite-patch-id: 281a26655e3292be28912adcce54d6c835f33771
prerequisite-patch-id: 76350633625ea8ebf6642d0e961fc95bcd395252
prerequisite-patch-id: e1d24b44b42065a4ce6627478ad37e465851e104
prerequisite-patch-id: 0bc53145a1073b4d78ff020e00f8b9af59dc6b16
prerequisite-patch-id: 027d3f74eaa16dfdfed9bd0d59a7812cf8c18af8
prerequisite-patch-id: c97dcbe9dda3dbd7cff20495e9e42e4c7b154be1
prerequisite-patch-id: 63d7b6fac5158a7d2bfe2bab267ae2662abd3976
prerequisite-patch-id: 6f506235689cb5b52719cca4709b5c630463019f
prerequisite-patch-id: 209fffe7f8d5bc12c06ef079b92d5a51d87a4760
prerequisite-patch-id: d88b14e89333f66c1c95d4b4796e2516da0dbc1d
prerequisite-patch-id: 8fa3fddf5c3d61dbbf48479f927ff5805d076db5
prerequisite-patch-id: 0d29d6790b6bafcdfc7e6562e3103d18633ff20c
prerequisite-patch-id: 7607499c7743b4f51becaed9346af7bfb565840f
prerequisite-patch-id: a465be9fded8db8a75c65fe836309bfe21713329
prerequisite-patch-id: 3d93d01c89c7af2d831e1314f17a677a027908d0
prerequisite-patch-id: 4c17c39017ede021e6bb12be517cc7d58a5de188
prerequisite-patch-id: 06097d3ef33f31854bfa082fb6eb702be2fbfd3a
prerequisite-patch-id: 5263bb04d2c542aefa400923c95389fe0d4bf915
prerequisite-patch-id: 2ae098b6da3d1f63b13b21b6572cdf3e81ef924f
prerequisite-patch-id: df5577a13db780e938d0aaa1b5e9897bbf3cc6dc
prerequisite-patch-id: 2f031bfd9f6db91a237be996cf563b1a79540bda
prerequisite-patch-id: e2900107249d0f1602a89abebafde22fd4129afe
prerequisite-patch-id: 427b66fa5ace402a2304b90b4e2fbe4b32b738cc
prerequisite-patch-id: 19eb53c51c834cd2190d6050fb29c95e1695c7d0
prerequisite-patch-id: e3c489a5b3badc2df780933cebffa4a19c2684ea
prerequisite-patch-id: 3c33f641c2cb131fcfecc0958a8fb7f5505c5a99
prerequisite-patch-id: 3d009a7765b1853fbefffa07efe9f2b1459d096f
prerequisite-patch-id: d2b970d8e7c931526432d43f422d7ea119b7f0e4
prerequisite-patch-id: 520fdbdce08db94d3ccd5dde1a6197f25c55b798
prerequisite-patch-id: 1432717911dac32b702e78ef342054e2c1eadd55
prerequisite-patch-id: b4bbaff724447deb6f346447fd47eb6d505de2dd
prerequisite-patch-id: c9abcb49eee93fe01e4b27cb0341f61966fef292
prerequisite-patch-id: f72614047ed0b922ac8dde569544785a4624e3d4
prerequisite-patch-id: 3f839e93b5b8934edce6af77b29494fdca8955a4
prerequisite-patch-id: 596c2a947dd1bd947a406da7dff12a6ec13aeeed
prerequisite-patch-id: d58d988d6ad5c520513ae89e5d249b9566c89234
prerequisite-patch-id: d43daa271aad64d2bf9ae85df5279431b0963a22
prerequisite-patch-id: 32c59f28517b44b6ea0fc83b2d9f4af1a66bb669
prerequisite-patch-id: 205ff6200cfe0fbf5447710dd80940ba47eb4445
prerequisite-patch-id: eca6d0ab73c9078ec82a3a9821ae7f8e29a2635a
prerequisite-patch-id: 7600dcc6bf999fab9607d4c2cba27189ee0564a5
prerequisite-patch-id: 4a6cb0cce2cc24af241f779ad881851088605dc1
prerequisite-patch-id: 04a71ea7635d63c49b42a8e0a944b91660af3db0
prerequisite-patch-id: 4fddd83d752bf7a43e6a11625c09b4bd827cdbd5
prerequisite-patch-id: b78967f514ed500e0817c01000e255cbdb71273e
prerequisite-patch-id: 3d84b50143749a9c4d3c8a38193ddf0a78e7701d
prerequisite-patch-id: e8f40430a2e068c47537bfa54e8933653609d822
prerequisite-patch-id: c708e73d09e916fc8a145ec939653921bc4417a2
prerequisite-patch-id: ec440d05b20f6bf89a85020f3484318438746d31
prerequisite-patch-id: e285aa1cbf2a4e243d14e4cdff950f30a5789c71
prerequisite-patch-id: 2778af856a867977ce3311c150115e7e5a2969af
prerequisite-patch-id: 2ceeeb1d2826c8d9ddc1df5842f3d3755931e906
prerequisite-patch-id: b6c1ce4ac2f6ffbc5d2c7dedde005f2a3e909646
prerequisite-patch-id: cb50e6ab01a3864ce5bcc65580f436cae2cdd76c
prerequisite-patch-id: cfea7aa3c6017fdbfc11f1a08806db122fc5295c
prerequisite-patch-id: c0bc5648259f0b745e0904853bc62f380fab8c05
prerequisite-patch-id: e57d2bf04e59d595bc9f5da243079e0e68bf598a
prerequisite-patch-id: 8774b8a75713d87218fb556cf955f8e5fbc6a3c7
prerequisite-patch-id: 83c8eda5576ddaba715d879155bba2646e0e1920
prerequisite-patch-id: 7983ab7a22793db463263cc1577ff995f9f38f03
prerequisite-patch-id: 71a4c33fd4f7df455483caed45966b3b40c1c71c
prerequisite-patch-id: f228c836107b884053c995e20370273584dd3216
prerequisite-patch-id: 7a3d86bfa6f5d573cb20a6bb287a497a2c30343e
prerequisite-patch-id: f7c9821614f04628c2ed347391b0522c1b195e09
prerequisite-patch-id: 0e2f9afa421887cd55959cffea9b0b0307750782
prerequisite-patch-id: 9f8d035a609f8d6c32c98c655f4a487316c069ad
prerequisite-patch-id: 5b2348bc499c5cd2d527cffb4b9c072d2cd00936
prerequisite-patch-id: c0bec91eb90ef0d33da54af3a448691fae70b841
prerequisite-patch-id: b5d91f1149ba1cc214f6a962e1ed4f95d4786e25
prerequisite-patch-id: 77820380f86729009bc9c2adb2543c60d280b6df
prerequisite-patch-id: 450914fb250c999acb285ff59abf511d68bb85bd
prerequisite-patch-id: 847a8ca23e451cc1f1469c9b55903b0d0bf3a6a9
prerequisite-patch-id: 8d1afd20261e46cbbdac851baafc455e5526d91b
prerequisite-patch-id: 5abafd3e73de29f93605c9a63e90c6c1b8369253
prerequisite-patch-id: 3b2e202fdcba2eb6fc4336474cee154981af1f33
prerequisite-patch-id: a230ad456ad018aaf8e26a3f5a62c9efcab25f95
prerequisite-patch-id: 52f052d37e14c94b58398779c5adca404dfa69ca
prerequisite-patch-id: 2008b7871a57cacc9b2f2a6dd5e0e9d141adc1e3
prerequisite-patch-id: 6d42133839570199760d10ee4f53cb486bf9da1f
prerequisite-patch-id: 329bebec9244fd3db26a3f42e330446aea54330e
prerequisite-patch-id: ceefb9b420823f10df231998ff0cec81ff404539
prerequisite-patch-id: 60acfd91f36236c0494ec4f6360f258c0b7c5684
prerequisite-patch-id: 792e4153c1c6d268f5b1e67a0711ed415ff7e44b
prerequisite-patch-id: cdd032b589e3a97d0136d9b35fa823be3f6321e9
prerequisite-patch-id: bb9bcb09f9621ef0ed6cd07de9e53d8b33aa5781
prerequisite-patch-id: b17842bb654628562abd02e707c2176e05aca06f
prerequisite-patch-id: adba72eed4b88fca5ab095f4da48c04b17cb22fd
prerequisite-patch-id: 7f22145ec135fe4f7d1fe54b9f0c2f451035fbeb
prerequisite-patch-id: bbe7de23a364dd79fdf2bdd47e1b6dedbc043e8a
prerequisite-patch-id: 4cf02d886326663d253423c18835b23fdb6cc2c2
prerequisite-patch-id: 1beb4e85f616e76e27501f1fb196cbdc5b256a3f
prerequisite-patch-id: ce229b728cd7ffda125fa81567a0741bee3c1ec4
prerequisite-patch-id: d62768cf0d8e1aab34b2c658d1bbad274270a099
prerequisite-patch-id: 6ae6a81140360b18efc09b1a4c5546d3549f5d4c
prerequisite-patch-id: 3b66fdde063bd4dda9cb4e9fcebbc82217eaa854
prerequisite-patch-id: f0ecf07be04265cf171d028fda7cb780442b0e36
prerequisite-patch-id: e7867003d05b18e233ebbb977073f25329d784fc
prerequisite-patch-id: c6e1050494ab95bcb5b33ebfa34f7af69da0c1b0
prerequisite-patch-id: 67b1848a27231a88122a2441723f27eebd76cb97
prerequisite-patch-id: 38b6f10b4fb196c4717809ba7f1b3a2fc4c8b07a
prerequisite-patch-id: 597c4dc1569749a930f26061d53cb32f52defd76
prerequisite-patch-id: b2f8111f78edeb6d7b96e0f94f61fd5e655bb9ae
prerequisite-patch-id: 367b3e3946ec215a8be41b719830f3b85710101b
prerequisite-patch-id: 03b0f85d471861565bf20aa212650852dea00ffa
prerequisite-patch-id: dc0911fc241a72fd322495d240e0b828cfbb3ede
prerequisite-patch-id: f8864129c6c9546b19c768ad357edf9055e8034b
prerequisite-patch-id: 4f09ef1bdefbdfa8d5d89639de28b35c31666efb
prerequisite-patch-id: 7df2ba8110f2e56217ad61fc5082ca1291bdc844
prerequisite-patch-id: 9e2538496d48ee88c8bc71a455a8f7cbea90fd27
prerequisite-patch-id: 96a4240916b4b391de25dd169179499214b94157
prerequisite-patch-id: f169df2bc0fe7673df3c05760680a5777a3a7fda
prerequisite-patch-id: 59b16431e1e9786c7301b4fd23d89bd680d4fdcd
prerequisite-patch-id: dc9c3f292e1da0a9fc668aacf4f860613c1ea2e4
prerequisite-patch-id: aff07ad3a153b522f5edb5e36e1d1e2321bf4166
prerequisite-patch-id: c7895392b8e55b91765c9013f7fbb1f3f3bc6c8b
prerequisite-patch-id: c20a7fa90f95d3208bd4f0234cf78b46a78681aa
prerequisite-patch-id: d4b9d9780a66a808a9a74c801ab88b9353447bc0
prerequisite-patch-id: 7dbd76172bc5c4cf7dbd0c472d423050e6181202
prerequisite-patch-id: 3a1061d7edd49bf57dc634a5f1b8b56b1c603576
prerequisite-patch-id: 66f1e5d96cca04839376d42f18e69cd01ba48529
prerequisite-patch-id: 0cc1fb87b280d5db3215b56b7b7a92f2620b0766
prerequisite-patch-id: c5fbd24d91ff1835ad0151bd92e342048e47c6bf
-- 
2.45.2


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 318+ messages in thread

* [PATCH v16b 0/4] c: Add __countof__ operator
  2024-10-16 12:09 [PATCH v16b 0/4] c: Add __countof__ operator Alejandro Colomar
  2024-07-28 14:15 ` [RFC v1 0/2] c: Add _Lengthof operator Alejandro Colomar
@ 2024-10-16 12:10 ` Alejandro Colomar
  2024-10-16 12:10 ` [PATCH v16b 1/4] contrib/: Add support for Cc: and Link: tags Alejandro Colomar
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 318+ messages in thread
From: Alejandro Colomar @ 2024-10-16 12:10 UTC (permalink / raw)
  To: gcc-patches, Joseph Myers
  Cc: Alejandro Colomar, Gabriel Ravier, Jakub Jelinek, Kees Cook,
	Qing Zhao, David Brown, Florian Weimer, Andreas Schwab,
	Timm Baeder, Daniel Plakosh, A. Jiang, Eugene Zelenko,
	Aaron Ballman, Paul Koning, Daniel Lundin, Nikolaos Strimpas,
	JeanHeyd Meneide, Fernando Borretti, Jonathan Protzenko,
	Chris Bazley, Ville Voutilainen, Alex Celeste,
	Jakub Łukasiewicz, Douglas McIlroy, Jason Merrill,
	Siddhesh Poyarekar, DJ Delorie, Carlos O'Donell,
	Martin Uecker, Gustavo A. R. Silva, Patrizia Kaye, Ori Bernstein,
	Robert Seacord, James K. Lowden, Marek Polacek, Sam James,
	corentinjabot, Richard Biener

[-- Attachment #1: Type: text/plain, Size: 96585 bytes --]

Hi!

v16 changes:

-  Remove () from commit messages in function names.  [Joseph]
-  Use __countof__ (name of the actual operator) in diagnostic messages.
   [Joseph]
-  Add CC (sorry for not CCing the patches to most people in v15; I
   accidentally suppressed most of them while sending).

v16b is a resend, since I accidentally didn't send them to the mailing
list.

Have a lovely day!
Alex

Alejandro Colomar (4):
  contrib/: Add support for Cc: and Link: tags
  gcc/: Rename array_type_nelts => array_type_nelts_minus_one
  gcc/: Merge definitions of array_type_nelts_top
  c: Add __countof__ operator

 contrib/gcc-changelog/git_commit.py    |   5 +-
 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                        |  32 ++++--
 gcc/c/c-fold.cc                        |   7 +-
 gcc/c/c-parser.cc                      |  62 +++++++---
 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/tree.cc                         |  13 ---
 gcc/doc/extend.texi                    |  30 +++++
 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/testsuite/gcc.dg/countof-compile.c | 115 +++++++++++++++++++
 gcc/testsuite/gcc.dg/countof-vla.c     |  46 ++++++++
 gcc/testsuite/gcc.dg/countof.c         | 150 +++++++++++++++++++++++++
 gcc/tree.cc                            |  17 ++-
 gcc/tree.h                             |   3 +-
 27 files changed, 600 insertions(+), 80 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/countof-compile.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-vla.c
 create mode 100644 gcc/testsuite/gcc.dg/countof.c

Range-diff:
1:  b6da2185675 = 1:  eac2d18d8a0 contrib/: Add support for Cc: and Link: tags
2:  a0fa3f139f9 ! 2:  7418a11fcd6 gcc/: Rename array_type_nelts() => array_type_nelts_minus_one()
    @@ Metadata
     Author: Alejandro Colomar <alx@kernel.org>
     
      ## Commit message ##
    -    gcc/: Rename array_type_nelts() => array_type_nelts_minus_one()
    +    gcc/: Rename array_type_nelts => array_type_nelts_minus_one
     
         The old name was misleading.
     
    @@ Commit message
                 * config/aarch64/aarch64.cc
                 (pure_scalable_type_info::analyze_array)
                 * config/i386/i386.cc (ix86_canonical_va_list_type):
    -            Rename array_type_nelts() => array_type_nelts_minus_one()
    +            Rename array_type_nelts => array_type_nelts_minus_one
                 The old name was misleading.
     
         gcc/c/ChangeLog:
     
                 * c-decl.cc (one_element_array_type_p, get_parm_array_spec)
                 * c-fold.cc (c_fold_array_ref):
    -            Rename array_type_nelts() => array_type_nelts_minus_one()
    +            Rename array_type_nelts => array_type_nelts_minus_one
     
         gcc/cp/ChangeLog:
     
    @@ Commit message
                 (build_delete)
                 * lambda.cc (add_capture)
                 * tree.cc (array_type_nelts_top):
    -            Rename array_type_nelts() => array_type_nelts_minus_one()
    +            Rename array_type_nelts => array_type_nelts_minus_one
     
         gcc/fortran/ChangeLog:
     
    @@ Commit message
                 * trans-openmp.cc
                 (gfc_walk_alloc_comps)
                 (gfc_omp_clause_linear_ctor):
    -            Rename array_type_nelts() => array_type_nelts_minus_one()
    +            Rename array_type_nelts => array_type_nelts_minus_one
     
         gcc/rust/ChangeLog:
     
                 * backend/rust-tree.cc (array_type_nelts_top):
    -            Rename array_type_nelts() => array_type_nelts_minus_one()
    +            Rename array_type_nelts => array_type_nelts_minus_one
     
         Cc: Gabriel Ravier <gabravier@gmail.com>
         Cc: Martin Uecker <uecker@tugraz.at>
3:  43a2e18c6a2 ! 3:  0cfae0598b3 Merge definitions of array_type_nelts_top()
    @@ Metadata
     Author: Alejandro Colomar <alx@kernel.org>
     
      ## Commit message ##
    -    Merge definitions of array_type_nelts_top()
    +    gcc/: Merge definitions of array_type_nelts_top
     
         There were two identical definitions, and none of them are available
         where they are needed for implementing __nelementsof__.  Merge them, and
4:  8a6959d2d38 ! 4:  12a30a2a6fd c: Add __countof__ operator
    @@ Commit message
                 (pop_maybe_used)
                 (is_top_array_vla)
                 (c_expr_countof_expr, c_expr_countof_type):
    -            Add __countof__operator.
    +            Add __countof__ operator.
     
         gcc/testsuite/ChangeLog:
     
    @@ Commit message
         Cc: Robert Seacord <rcseacord@gmail.com>
         Cc: Marek Polacek <mpolacek@gcc.gnu.org>
         Cc: Sam James <sam@gentoo.org>
    +    Cc: Richard Biener <richard.guenther@gmail.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)
     +  type_code = TREE_CODE (type);
     +  if (type_code != ARRAY_TYPE)
     +    {
    -+      error_at (loc, "invalid application of %<countof%> to type %qT", type);
    ++      error_at (loc, "invalid application of %<__countof__%> to type %qT", type);
     +      return error_mark_node;
     +    }
     +  if (!COMPLETE_TYPE_P (type))
     +    {
     +      error_at (loc,
    -+		"invalid application of %<countof%> to incomplete type %qT",
    ++		"invalid application of %<__countof__%> to incomplete type %qT",
     +		type);
     +      return error_mark_node;
     +    }
    @@ gcc/c/c-decl.cc: start_struct (location_t loc, enum tree_code code, tree name,
     +		    ? "typeof"
     +		    : (in_alignof
     +		       ? "alignof"
    -+		       : "countof"))));
    ++		       : "__countof__"))));
      
        if (in_underspecified_init)
          error_at (loc, "%qT defined in underspecified object initializer", ref);
    @@ gcc/c/c-decl.cc: start_enum (location_t loc, struct c_enum_contents *the_enum, t
     +		    ? "typeof"
     +		    : (in_alignof
     +		       ? "alignof"
    -+		       : "countof"))));
    ++		       : "__countof__"))));
      
        if (in_underspecified_init)
          error_at (loc, "%qT defined in underspecified object initializer",
    @@ gcc/c/c-parser.cc: c_parser_unary_expression (c_parser *parser)
     -c_parser_sizeof_expression (c_parser *parser)
     +c_parser_sizeof_or_countof_expression (c_parser *parser, enum rid rid)
      {
    -+  const char *op_name = (rid == RID_COUNTOF) ? "countof" : "sizeof";
    ++  const char *op_name = (rid == RID_COUNTOF) ? "__countof__" : "sizeof";
        struct c_expr expr;
        struct c_expr result;
        location_t expr_loc;
    @@ gcc/doc/extend.texi: If the operand of the @code{__alignof__} expression is a fu
      the expression evaluates to the alignment of the function which may
      be specified by attribute @code{aligned} (@pxref{Common Function Attributes}).
      
    -+@node countof
    ++@node __countof__
     +@section Determining the Number of Elements of Arrays
    -+@cindex countof
    ++@cindex __countof__
     +@cindex number of elements
     +
     +The keyword @code{__countof__} determines

base-commit: 9cbcf8d1de159e6113fafb5dc2feb4a7e467a302
prerequisite-patch-id: 3bb58e302e54b35e987452de2e3cb6da7f6917ce
prerequisite-patch-id: 090612df745c5ed878a75175606ce1deabf61cb0
prerequisite-patch-id: c3a80d94c326f7402bdf46049c434e809a9f376e
prerequisite-patch-id: 883007acf6a47f51128798dc952895854b40e1ff
prerequisite-patch-id: 93e211483ce2b939ce5e549de78e9ac4606bb114
prerequisite-patch-id: 008f55a1dc4b0a2551e4682b3319a3b0df86c72e
prerequisite-patch-id: be6ecc95f5fcf2fe9ac44263e6eae8a69068ee53
prerequisite-patch-id: e64a9e239738ff1af9753893372bb0fff907d8e6
prerequisite-patch-id: 22cc97d05ab08735db2341f5062c737f9cff9209
prerequisite-patch-id: 9e9756ca0458d4f6f162229e5ffe5923ffceb9d7
prerequisite-patch-id: 9d64d075010c059eaceb2fb2326d48f6a8798950
prerequisite-patch-id: be2e5a5deb6836b4715e4715cddd03018d2f3346
prerequisite-patch-id: a627d18e62fc98b7ccf11b31b0dc885a52994795
prerequisite-patch-id: 39aea8b15f043ab5e2804a6e127d2fe5108d814b
prerequisite-patch-id: 8cb26809cc4de24fe408e71a468fbc278241faab
prerequisite-patch-id: 1b0dd932c7637d953a7b7086aa5625287df6c79a
prerequisite-patch-id: 0bb1888a37e3537ba48e69ac378b7b3e41453949
prerequisite-patch-id: 79657c31c616c9bf477ec015a4ccb94f298193c0
prerequisite-patch-id: 2506a44e9d695cffa4c710176092c30392037103
prerequisite-patch-id: da4a114bc9bef4aafb816328f1674b5f85818753
prerequisite-patch-id: f4a32714d46e022356759a3fb305a8827ef565e9
prerequisite-patch-id: 08a6388b590804ab3f8da8c03d953e88428228e9
prerequisite-patch-id: 37fb8203174274fa9e3054ba0d83ff41dd9ba206
prerequisite-patch-id: 5a6559b661dd999abf5d5b0a40309636faa3504e
prerequisite-patch-id: a66c0ace262f24e19546e0669fecd0bbb6c4b4bf
prerequisite-patch-id: de6b8f05d41b61f29fc517883fafdf89aada7de9
prerequisite-patch-id: 4412c0ef6909608fc761b86cfb22722d862d61d0
prerequisite-patch-id: ad452759de17adaaf82c9f30e556fb477e3b1941
prerequisite-patch-id: 7b8615c4ad8e6c825ee192c8225e7b8f673aaeb4
prerequisite-patch-id: 7f806ab2c8bac5b2a79fad8eef55c4190ec33d44
prerequisite-patch-id: 84d3e86a4b573228dab7d37c3d89845ec1989723
prerequisite-patch-id: 293a69cf606ea42badcc678f43b53f2e47aded19
prerequisite-patch-id: 1a871a86b6c1b147ed731970f999b5d102444d1d
prerequisite-patch-id: 7798a8ca79c1f13268e3762d47861ff94d8eba02
prerequisite-patch-id: ea12050f12ad6e1278b695f5fe345ca9bc842b1f
prerequisite-patch-id: 775ec83e6019784675e3412125ae6215b4bf045d
prerequisite-patch-id: 8cc5a6f94523c8120086dcb2217ba8168b045a3e
prerequisite-patch-id: ee9fa7eb9352555ff989551e0af040359671f3d7
prerequisite-patch-id: 02737f65218d4b0c2766cfcf8c0fcde24ca93ac2
prerequisite-patch-id: 4649eac88f8eb70f79e7777b7cebff4460d8cfc7
prerequisite-patch-id: 6cba96eb4bee2e8b3b47e0bf6b21ec9fa8639480
prerequisite-patch-id: 67691213e43b5776c999e8c0927df69be8689e14
prerequisite-patch-id: c92d8f4dab324c8f42605d626035999cd990a18e
prerequisite-patch-id: f0a10e37287f97e915eb245d6394ad8e1115905a
prerequisite-patch-id: f67343a2b854a5f51d75200d56715b2cd10ddc9c
prerequisite-patch-id: 0d42c83260a2a02de43ad5066f76b4483703f155
prerequisite-patch-id: 71fc9c326b88271512ee65320dcb3b3454326472
prerequisite-patch-id: 5770267c01d4e5b5d0187445d31ee87b662fa61d
prerequisite-patch-id: 999d706f78ac4f85adbfad63adc3df03615ce716
prerequisite-patch-id: a3a7f88920dcaec397cdce89680dd341da6b7d50
prerequisite-patch-id: 74495be2707634e339b90ed5ad3a4c375f6b9ec2
prerequisite-patch-id: 7be19bb7867585445b6119f6357b69f5f8baa5b8
prerequisite-patch-id: 03efabd23ba77ba8141aa0a8f19b04f0fa6c97f1
prerequisite-patch-id: 04a4ddcad10e249f4e8cd96ade03c16997e8f83f
prerequisite-patch-id: b0b8243418ae865a61a5f92d1da80fdbed6d23d4
prerequisite-patch-id: 349842ef44ddca54066bdbb26d634ac24e076710
prerequisite-patch-id: d15d4d8c4c0b6843118774fee0c8231e948779cf
prerequisite-patch-id: eff8d7df797afdd2ba6b14c1d8ec9dbdc58b5c3d
prerequisite-patch-id: 18ae20d67e1f01478d4b01981488e0a3d6864ad2
prerequisite-patch-id: b6c162640de66eeaf8f2b470801dc3cec9d1141e
prerequisite-patch-id: fccd6815aa703114b7ea3e61b3971621316a8706
prerequisite-patch-id: ec894a0480c8c523b9f895eea7b809b68998bbfe
prerequisite-patch-id: a408ede8ac2c69f821dd06cdad368652784e975f
prerequisite-patch-id: 31f81b5fce5e577e66c09784d24727fadce0b71b
prerequisite-patch-id: 0fa06efe4a2349a00a6e1d7ed3fcb7ededef127e
prerequisite-patch-id: e7dba9a68bc0d4481b2cebf029595bdb9f47271f
prerequisite-patch-id: 4ac7ef554fdd4c2fcceb9f5bd83e9203adaddaf3
prerequisite-patch-id: ec0a3bc81af005d80235b38f44c227b0a1c248d2
prerequisite-patch-id: 7083aa4a6a21ae34a8d6457791068ba419c1187d
prerequisite-patch-id: 7b3ceb60e52271be1655ab07595e1000d8734ae8
prerequisite-patch-id: 069dd47701f5607db952e7410b66bfc4a77b907c
prerequisite-patch-id: 6de803a1b4d8dba8b403205327bff91f239a39a8
prerequisite-patch-id: 8dfcdb9d5cdf69c54766a59a8f194af09c0840b8
prerequisite-patch-id: f7834a2848f562a130f3d6f28a6b849723dbe18f
prerequisite-patch-id: 2f283e2b6ff758a2b1f0f4f491c962499be68f91
prerequisite-patch-id: 7ca906fcc364ab07d6ab9b48fe8162e8006499b9
prerequisite-patch-id: 0ef05db7ab79653ae096f50497946214bc5084b9
prerequisite-patch-id: 1d60704d316f4b0f66d5c7e4bf17b025cf99c617
prerequisite-patch-id: ed3314a4690d9c15bbcfee441599a58e37215877
prerequisite-patch-id: 34ec93f88bed41db1608e214800f87fdc5a7f9f9
prerequisite-patch-id: aca1f8cc97d88784936517c7e8050c457c77c9af
prerequisite-patch-id: b499a1bfa95368ee03daa8c7d45b3ae9c1206871
prerequisite-patch-id: 5f1cb1245044b3ad4169500916c8b9459711416e
prerequisite-patch-id: 88e3e2e5947fbfa907213daa9ceef1651976d72f
prerequisite-patch-id: b4d4f67cd84b9ccb4c4eb48d8e7e20fc70b702ec
prerequisite-patch-id: b807936c32d4a4539a29ba56b637a3f4733713e3
prerequisite-patch-id: 72b95ab107eb6ae60f6517410ecce24a3308fa6e
prerequisite-patch-id: 007b9853bbb41eb2d2b85fd67c1b39d58c2dcc4d
prerequisite-patch-id: e6e05315ec9827b069836b4f394099272c4b3998
prerequisite-patch-id: cd63bd21f25dfb458c751306f1ba8fba6db43a35
prerequisite-patch-id: 790fe51546bed957d4094668086a87009ea6bc3e
prerequisite-patch-id: c55ca764e1bde1857cab3d1c7a569172e3a60dd0
prerequisite-patch-id: 4574efb15f6e60ba84b21718381c19faa2d06e6a
prerequisite-patch-id: 4026283a30594ccf4c5c297a45b817d7c95dcc81
prerequisite-patch-id: 2f6425ce98f57c1833fcfc1cb963a4b00550daaa
prerequisite-patch-id: 671d4f6b289715eecf11df3b8e94e566b4e3f358
prerequisite-patch-id: 59d20ef094471e06900a58216a35fb466e6350a6
prerequisite-patch-id: 8f6ac7d59fcdd44f015dce5b41ca7e20ed551b17
prerequisite-patch-id: b3f0435a6a54a62ae2b895ede265f657b2826929
prerequisite-patch-id: 06784b4d67904e2a8eab05f652d985750aeae26a
prerequisite-patch-id: 48e9916f08c8502323eadf9595d11a3ad7cf1b0c
prerequisite-patch-id: 9c5b9353f575b545d6ba706aa33a4200dc163e1e
prerequisite-patch-id: efadc065d2991129a9fa4380ed782b9dfac9807f
prerequisite-patch-id: 5a3e46fd6d5f1324a307bd01656993131644e59d
prerequisite-patch-id: 40be26b80ff47971946da8ccca6574333b4ac511
prerequisite-patch-id: 249d8bc2c8226ea94c27e2d2db8dfda056b8221d
prerequisite-patch-id: 64c7dc66a01b47fdc1d178e4264dbfb17f65cb48
prerequisite-patch-id: 7651dda34bd7be0a7c0c58b813abbfe4e75057a5
prerequisite-patch-id: 5b677afd301ba2d8385e73d6f55ef259e69cdd06
prerequisite-patch-id: f41124cb1f7db66cf578ee87b768438dcf66227d
prerequisite-patch-id: 6a173ab5f27750a6f4a2f8adebff537f95225d38
prerequisite-patch-id: c42d87f4f18b34c20121d7a7ee22564b8f2a9c3b
prerequisite-patch-id: e4c4b6c5c635e67f641c1bb4902bb5ec1a0eb1be
prerequisite-patch-id: 197202a25498a915f35f4417efb38e8844cac309
prerequisite-patch-id: 1e23186a890510f123ecd202f8a50d2094201277
prerequisite-patch-id: ba3e7e54dfbd8370ff50d1a5e85ac06d803fe68d
prerequisite-patch-id: edcca1af6061de5006b58ff7cd52a039aec88192
prerequisite-patch-id: 50ee0f2c714091aeab155cd40a94214fd1844463
prerequisite-patch-id: 31adcc5191ebc8b2ea26ee1e4b7de78a3d8e0f48
prerequisite-patch-id: dafdb698d23a185ee4adfbf9cbaf43ea31661bc1
prerequisite-patch-id: 683d340258d86d0774c772cc5d4bc4dfc6c214ac
prerequisite-patch-id: 0052a313ada5ebbd0e24905f2b75974736dae59e
prerequisite-patch-id: 1cbdbf0cf8727d07cfb7251551bbb8f47ca4f9d8
prerequisite-patch-id: c059fdfb33923cc5d728f53136021e01cab5f316
prerequisite-patch-id: d8cd3ac99c209600a4686d85627fae2956864272
prerequisite-patch-id: 7bfa53abc0cd50a22a81782353e30f0503bf87b3
prerequisite-patch-id: a2837d8005f85e1764d2baf4c5269ac4c26d0e03
prerequisite-patch-id: c7c2ba071a328f24d36a7bc73d096f701ff049c4
prerequisite-patch-id: 49edd721efd5860bce7a6da39a3983c1729dfb09
prerequisite-patch-id: b41ba2264cf8d51fad69c0d60b23282fdcaa02ed
prerequisite-patch-id: ce1094369b939e5df1c9ff586ba6e77eadd6755b
prerequisite-patch-id: cc76aa21e68006e190b6c095a7eab1f71a350035
prerequisite-patch-id: 016dbed32a9d26e0daa7fe068846dc5bf0bab4b2
prerequisite-patch-id: ea3270295ff22f15ae5a5213ae7ef0fb24f3d90e
prerequisite-patch-id: 0d7ec035c0ac8ea612791940c47c720fd0fc0983
prerequisite-patch-id: 073689ebff4dc3ed400b7a6a09b2aa3222eb5eaf
prerequisite-patch-id: 3de9c5dcd90a94356e41cd6c3a6b3a3ebd6da40f
prerequisite-patch-id: 02173a8508f62560dfc0c873ed4f8ffd3b2da127
prerequisite-patch-id: 325c71a3064a69ed233417bb0dd06ac5afe22ecd
prerequisite-patch-id: fb5f0634575b9cd445be39af1b442f641f33669e
prerequisite-patch-id: 375ec357c82582464519ccd102ba9c9969b27ccd
prerequisite-patch-id: 96724bd515fee1e70896e427ca5443cf6c3bd1c6
prerequisite-patch-id: d11653d1691c233ceac344313e1facf239c075e6
prerequisite-patch-id: a0c4b6d4fa27a1f1738ccd7d2c1c5203f4acc10c
prerequisite-patch-id: bcf62e2802a1d35bbeb601750792f3043e18e02e
prerequisite-patch-id: b6027c3dd6b0d7a576397c3f7cead1cb2e32ab3d
prerequisite-patch-id: 2993826cfc8ecb4743d1104ce9062ce064dee436
prerequisite-patch-id: 2de773c80c1d53b349768f3a9c1dedd9473141e2
prerequisite-patch-id: dcd065f3bede4933cf1071ca0ff8f631af30537e
prerequisite-patch-id: e8f9cef7f9a80d21786bdbc63de84dad5bb0f11b
prerequisite-patch-id: adefc62a9de4bcbb15ddba73edcdb96740b8527f
prerequisite-patch-id: b8028f15bc6bcfc0053852516acd70129434ef64
prerequisite-patch-id: a9378612984ceace5d8fc99c192de3d07fad4b4c
prerequisite-patch-id: 3e64fd39d97c528b5901f648d7ab92c9b3dfebd1
prerequisite-patch-id: 6900b6fcf58f765fa3266432dc9e2eebcacfbb4f
prerequisite-patch-id: 0d796b1a9c84ad77fecacee5450ae4fe067e7748
prerequisite-patch-id: c8cd1e1f3efda1056dd2f393a43b97a675f8fc00
prerequisite-patch-id: a1e5e6ee3a85aa293485f42163c5e6fb8ed7ac6c
prerequisite-patch-id: 29865d865b97531dd5be3019e22adb1066bcd0a3
prerequisite-patch-id: f5e05f1932b2fd24d00c3a7e64a2589f9c62a4e7
prerequisite-patch-id: 9f875036c21954004d3533697f89c7b8f3f35673
prerequisite-patch-id: f0f917f79ebed24ee4cd3427393d6cc24b9f2617
prerequisite-patch-id: 949be1cb8e66006949d4654aa60cf11b990bea13
prerequisite-patch-id: a035355f8731aa2619cd876157cfd2a9321c4814
prerequisite-patch-id: d23b3af12de5f250b5aded06076390d855065d34
prerequisite-patch-id: b649f233ca196c43de136937fbcaf0a5b792a7c7
prerequisite-patch-id: 0b474fc99e8b05aee2f470e8166d715261b9eb11
prerequisite-patch-id: a8f595e6c8b9714bfc4d89a7e39d5be3a9665d87
prerequisite-patch-id: 362ec11aff3d8ddc90f8b1aeb31d0fde8785384b
prerequisite-patch-id: 3695552670237d21bbd21fef03105083754ed6d1
prerequisite-patch-id: 89f2689e530147ac5530197ff972bc44135a1fe5
prerequisite-patch-id: e4a07cbaee52cbe451bfb9938b6b2a8636cac2f0
prerequisite-patch-id: f8f8edb0e66d2612359021654361be7fd0a55b70
prerequisite-patch-id: 743f4e4444f9cac24e67abce2bda52d6a421d870
prerequisite-patch-id: 8f0d19793716d0c18759e4261ef18c6db21c7f66
prerequisite-patch-id: 016a97f4bb36008d268ed1142d4fe67263d18c5f
prerequisite-patch-id: c9b1ea941f12ec7c34d17a7a81b999cdc90a46bb
prerequisite-patch-id: 2e4f5844a1680c659f4fe9af3723f8c9e6171c98
prerequisite-patch-id: 9b218d7632794493bcc98298de79e9d881bc4de2
prerequisite-patch-id: bd18dcb6c060ae56cadb55ad248138918b4542fa
prerequisite-patch-id: 5f4f31b906f1a415721c42bb4f06e9a97e6d9826
prerequisite-patch-id: fd625a00389f10724c4df0c309f46588ff4db63e
prerequisite-patch-id: 6aa7f6e164a2fc200361fd96399ad1c10f0825e2
prerequisite-patch-id: de267e462ebf8b5fda3d3df92d84914f3d49b093
prerequisite-patch-id: 10e0c0ed7bb11a5e9d50b4210a67d56d0baa7ae7
prerequisite-patch-id: 881a354db3dcf42e71ff51e86a712fe24a82378f
prerequisite-patch-id: 471c157425528ec5fa2fe0371dfc9babeff74c57
prerequisite-patch-id: a7d752c724506c047c0c69fb568f9e3e421773b5
prerequisite-patch-id: e207260eff0bee9b47719902663721ac36371856
prerequisite-patch-id: c978ecf00ccf17014919ba6d22a634f1fa5378b8
prerequisite-patch-id: c30ea3d0e9179a8f91523e4775aa1d7697777031
prerequisite-patch-id: 9caf8f6dc88c899b90242124e9efccecf61e6580
prerequisite-patch-id: 8104c6e0f28b79353bb1fe3d6d5bd49b8a1d4656
prerequisite-patch-id: ad97388f77ab9d4cc88a369418deec6f796d9ac3
prerequisite-patch-id: 1f6acfacff835f1d7f922614262505c4acbcb067
prerequisite-patch-id: 95d5625e0f04636a4c3ec335c77f34a5fecaa952
prerequisite-patch-id: 82e613feb908a11046bdafc6e874bcd8c4f52200
prerequisite-patch-id: 5f7a850dcf2102e4ac82791ba95ed0c0bc695613
prerequisite-patch-id: 50d03e282b31737919a2b979d59c5c4c17107627
prerequisite-patch-id: 8b51bae8e714a0e5277f67ff9d1455fd2f4e36b7
prerequisite-patch-id: eee196eb6f44f53040e52305d9c48909eb3bf2c5
prerequisite-patch-id: 35494985bedf6015cb3a8c2c70f58099e9c44316
prerequisite-patch-id: c3c5c822735b385dd0e55260f514623bf3f9ff1a
prerequisite-patch-id: b21222f6f96276b46ff605bdd1d2a75c9af839ca
prerequisite-patch-id: b63e092548d498d642b6363eae9c98247f5300f9
prerequisite-patch-id: 99cf93d15a50ad94c049c736b375bbdb77cf0ef6
prerequisite-patch-id: e2d86b651e3ff2f70848f827b29cc804cead48b2
prerequisite-patch-id: 1ec76b0303530aaa120186fb249252cd3a1bd7ec
prerequisite-patch-id: 9a35b1041fb252654255045df37478c8eb15a501
prerequisite-patch-id: e7227e60ea90415b54c6fcd553ddece24dd402fc
prerequisite-patch-id: 2f45861307fafa6a5696098406e164e166f4d207
prerequisite-patch-id: ab037b78ccf8a9db312333f5e01e6fd2e54832ca
prerequisite-patch-id: 9c886d5ccd279d6f283fcd60a794e66c94fe782d
prerequisite-patch-id: fa5a4fc2f2d77e9ad000d7477f56b822efce457f
prerequisite-patch-id: a0699fc9eb0ee36f53bc937770887d6086d2a7b8
prerequisite-patch-id: b383634edd50afef4180be293861d1014491d86d
prerequisite-patch-id: 2f404a754f2e1048165df254e963e26f6789de7f
prerequisite-patch-id: 07d59a1d0796816d8421b5a236175b1568d1f63f
prerequisite-patch-id: 9f904d43a86cb4e55a2a00440dd042ec717c8eb8
prerequisite-patch-id: b30b252bdf0646403dbd132c7dc629188e4f6a4b
prerequisite-patch-id: 73e2691afad05a42cb6cb5a28894eb958516f39c
prerequisite-patch-id: ef0f8b6061c55ada19107f026164c8598ebc66bd
prerequisite-patch-id: da21009a2dbc3384309cfdc4c49e10b86de6e747
prerequisite-patch-id: 2ef5022df54288b85ef1c8fe4e7a02a03d4577ff
prerequisite-patch-id: 5193b8507248975783d1eb6bc911265e6b55988e
prerequisite-patch-id: 1aef895eb9c159d33d617d7b2475928f75a73303
prerequisite-patch-id: bf87652bd502aeaf671da92e243553fb9a94f5d5
prerequisite-patch-id: cf9856dfd70d154fab043ffd2ee89288d9d41827
prerequisite-patch-id: f9daf7a441685aa6d25225b6616e51be5fcfe772
prerequisite-patch-id: 0101aa9af501543384863fa8c090febd6939f80f
prerequisite-patch-id: ccf1ac224734562e2f4207847b8128cd3c8b9d31
prerequisite-patch-id: 589ae86ee30b01355ce220ab9fc89c5403d95076
prerequisite-patch-id: 6e809a44a0ef69883eb812f8a4b57eb52ad32f41
prerequisite-patch-id: 116d110f795045527d54f2897e1ac12bb2f59238
prerequisite-patch-id: f4e0f48a8ce61bc6c229a18bf41f4b3cdec3a9d0
prerequisite-patch-id: e78df0253e48cdf5f9e44c17a169fc9cccb82c7e
prerequisite-patch-id: 1e6951da0eba531f4b445996167fea1e7320e3ae
prerequisite-patch-id: b1903fb1a742dd33ebb635299c725e9fc2a4e9ae
prerequisite-patch-id: eb07c15789948b34c0b219ff05f61c530882845d
prerequisite-patch-id: 92c0ba647ef4b4b7e83297554f6fa7e31f3a8fb5
prerequisite-patch-id: f968b1250e573119cb65aab0b98c225d8a7c4d8a
prerequisite-patch-id: 5e6dee90fe5f7a891794b5ea6bed41b1157c2930
prerequisite-patch-id: 3b10245cae08595a6bcbdc82ff836becaf6d04d2
prerequisite-patch-id: d7f15f333560e8ccfe2ad073e99ca4ef502e15d1
prerequisite-patch-id: 4c95c2badbd5911a7405a64e0d84e3091526444d
prerequisite-patch-id: f839c9824865564c12cbb7064ff455f34dc039f7
prerequisite-patch-id: 071e2570569f005c75ed7d8bf112db80cca310e5
prerequisite-patch-id: 7ee42594ecf51591428ae7f13bfb8403affed8cb
prerequisite-patch-id: 4b2105c900cf8ed047a9c0d1866fb2bdb4f9a59e
prerequisite-patch-id: dd4697ba0013408e637223fadd027c9b34945060
prerequisite-patch-id: e0881345b919ec25525c626303ba5d5e160f97f2
prerequisite-patch-id: fc6865c7e1fb19530ac8e77090eaa0b179f70496
prerequisite-patch-id: e3b8081ed28b7f0d370548044237287f52179967
prerequisite-patch-id: b672da115531fc52a591c9e50ac4da9e8b09e144
prerequisite-patch-id: f2764b91aa819feb1879d007993bda7aeb7f5df6
prerequisite-patch-id: dfb13890022578746ce611a965c62c34905b1f18
prerequisite-patch-id: bef3730ba816c84cb056d12e30b91a8c1f4b6aac
prerequisite-patch-id: 265211a01667357c86ce905ee33e4adbb81887d9
prerequisite-patch-id: c02d2492949e079494b9552c397e689774fad639
prerequisite-patch-id: 0f4180d693806ae210396ec1512be8e1d45c9530
prerequisite-patch-id: 22b486e7286a8b1a8ef90d3f1f4a4d48e43fb25c
prerequisite-patch-id: 0020828bf1b65907c906fb9ebf24104a5e72c790
prerequisite-patch-id: 4afad41c227028a4c6c35d1c43b0ee7883852a1e
prerequisite-patch-id: 890e19d588eca2dacfb83475c19ac461c0d83058
prerequisite-patch-id: f35d03d5ed63be69d2dfec77d07b28d21c40dc9a
prerequisite-patch-id: 2bebc000037d37260152802423445d39bc463f8e
prerequisite-patch-id: ccbec53de5ad88beb7657680ae6aa167f3505fd6
prerequisite-patch-id: 3c588bad04050087679a1d4f5479efb0da2537bb
prerequisite-patch-id: 87d915c6c5495d2accc7864dc592f2f651012fca
prerequisite-patch-id: a327cf20636f57b5feb31928c49d6517f102a709
prerequisite-patch-id: 8106cf8afd07cf37f3ecd63b831f1a22fa99998a
prerequisite-patch-id: a4ff39b72413dc2d894d269629919ce5199eb0fd
prerequisite-patch-id: c0db74dd58a097e7130420bd294b0f3d200730be
prerequisite-patch-id: df5bd199584a63d1ca2af8ca5e9bc659baffb8ab
prerequisite-patch-id: 9f8d32c0a8df05688a4e6779d45538056d891a72
prerequisite-patch-id: 167566e1096e56d7189393aed3528b8047421a2b
prerequisite-patch-id: 5ade75da262706c05c72bc2e1095cdc137334928
prerequisite-patch-id: 725cd8d55b55117b8732240a36ef6dd57560b7aa
prerequisite-patch-id: 2283e8ab28c671cd97fdba344bad9fad3b740955
prerequisite-patch-id: d86fed5ed934d2622a0e640677483dbd5e493b50
prerequisite-patch-id: 5a523603c0cc2344952de69d65a1dd6c9c28b1b0
prerequisite-patch-id: 8276956515aab9f3e81a9b4d51f5d270fea82c8b
prerequisite-patch-id: 1c0b8c20b01944262081a7fac4905a24a1f51afd
prerequisite-patch-id: 90b6ed9e4633014209d3291157104fe2db6cc268
prerequisite-patch-id: b78d480e28a5684e5a04f9e2d1dc6c8d6b6115d8
prerequisite-patch-id: 85129a45f66a9afd1d6aeb78a266f2b33131effc
prerequisite-patch-id: 46c2c0f251c385f740ec0f021ddf71b214dcf188
prerequisite-patch-id: de94541c97cd5dfb8f02b4210557a29264c60f28
prerequisite-patch-id: cb4a135f378247e43ecb9c5c1ca421e778356cd3
prerequisite-patch-id: 6941030e002fe4dac24a7e431297837bcebd6637
prerequisite-patch-id: 16ed31acf9114e5bcdeab9ac6f8b3c1d460d40ab
prerequisite-patch-id: 5a24fb875f0c703d031c3dcfd40faf2072a691b1
prerequisite-patch-id: 278384975e9224209b9df58781cb0d57d33cce91
prerequisite-patch-id: 8b4be8616dd4f2e1b6189657017e81999e3379bf
prerequisite-patch-id: 99853a3b8283b9aae581ec9c7a4b30dd27a9075f
prerequisite-patch-id: a48c177e8a82248dfd6642c35da34019d765a4a8
prerequisite-patch-id: 6b4419d64c7d1e887578e30a73fc476aad5408a6
prerequisite-patch-id: 93b79b926b74052e9bbba631e0f30da89c1dd0ec
prerequisite-patch-id: 9fe442b02446f58ea358d748da5f5f82805bc7ef
prerequisite-patch-id: 26828312870404b6611ccd685b162aa082dfce57
prerequisite-patch-id: 6ce31c6bb1a2b79ca465dca7a1157d1bb379d51b
prerequisite-patch-id: e6b4e8bd8a45796125d4fdcc169f97f5a3fb8bf8
prerequisite-patch-id: 94637d65272a73ec3e2b19dc3595d864fdea4836
prerequisite-patch-id: dd5dfa3e4d58a7db1f158bcc0daec057c028ce00
prerequisite-patch-id: 2295114d438c62a2128620775fc0300b0b418ff9
prerequisite-patch-id: 080adcee4042fd9511680fb10beebcae24a4dc06
prerequisite-patch-id: 022f540464bfd6c2202cdeb5530502903d207417
prerequisite-patch-id: 5ffcb1ea5dafbfe47753ce4165afa1f99d46cc82
prerequisite-patch-id: c4dcb2f3f063115727c204d3e0b0ef7c7a66cda9
prerequisite-patch-id: 984a29d2480696456528847eb7365e5785613ab6
prerequisite-patch-id: fa4b35b9b0874bdf8057f88303e204ff3b6e0538
prerequisite-patch-id: 12dac397d93e001201a2b8fcbadbca24a91a1f5a
prerequisite-patch-id: 51112edb6d85135a1930262e7a63f8f2fad3b22d
prerequisite-patch-id: b2fe22f7b89cd65edd2f67db746926a3deb69180
prerequisite-patch-id: 17757de676f6d55f18375ee9630ff33a1d101c1f
prerequisite-patch-id: ed5fdaf31479dc0d05afa7159e74a6ff5d390717
prerequisite-patch-id: 15f23a365586786d1b1cf45b4d5f1449c4507131
prerequisite-patch-id: 4c04f094a9f3dd5b2e83e45e5953e19140599477
prerequisite-patch-id: 036d1b98663bc2898502f50ded880e8759a29779
prerequisite-patch-id: 6c2d1e2e56d3917824f83caeb0ef72d13e2b0943
prerequisite-patch-id: fefa7cc8020e445d5696cce9805ac8a070f8ce62
prerequisite-patch-id: 2f3a5e1af6a18c3c900e907cdbd5b8f70e16f2cf
prerequisite-patch-id: 5323f57010be74dcec124a4b1039d71e4b43827d
prerequisite-patch-id: 084ccc81aa8dfb551f726b255bbc468b7927a4f6
prerequisite-patch-id: ef34cf54e320016fe563e6719e20ea5a9c3d8b0b
prerequisite-patch-id: cd5de61f31dc3939dfb3a650f766b652bc004f66
prerequisite-patch-id: a4f3078b22023208c08aa43904abaf7b9b96685c
prerequisite-patch-id: ebe1b18964e42c75f42ba7a86afc5dc05599c365
prerequisite-patch-id: daa0dec8fce546fedd54ea5c5cfbefd22cda6166
prerequisite-patch-id: ca6fb2e53c36765eb3a4d03996a33a75669856d1
prerequisite-patch-id: 5c737efd3e6ed83f02e7871bba03384349062e14
prerequisite-patch-id: 9a271a42b76d46e6dd0ab589b69e6153245d1d74
prerequisite-patch-id: 38075ae35bb852c54840ef45e252304d97abaf37
prerequisite-patch-id: fb9efadc22957488fb64dda477c247a34e31f818
prerequisite-patch-id: af07380f477d924bbbe7c88afd482f4f6e93e65c
prerequisite-patch-id: c56d58afe69b0c1a409785a8ab96dde9069effaa
prerequisite-patch-id: 634935a9c68aa1b459e21f9726b4c4072ba4c45e
prerequisite-patch-id: e799daf13b28e3b425d216669ebd0b5a854a3eab
prerequisite-patch-id: b29d99c4a75d8e9aa43235f33735f2218cc822d3
prerequisite-patch-id: 4d9a6373a1269f995d406bf8a642342e5caba6c8
prerequisite-patch-id: ff9217b0100aa988f5c15a76d64491db1c73780c
prerequisite-patch-id: 87a45370a00f9606abc8f6e5759aeac07b966cf2
prerequisite-patch-id: 17d341478c369638f4449607c5bf0467de6d44c7
prerequisite-patch-id: 7bc9559aae8de1321298683956f89db1a6581dc1
prerequisite-patch-id: 42780b061b459d6927346db582a5b4bda554ca0c
prerequisite-patch-id: c340b164838ecfefe67999b0d8ba024974552c18
prerequisite-patch-id: cc9ff80615bf7e4f14d546ebf27258a545c81232
prerequisite-patch-id: efc6be186b7f423904fcac6a8f26779b3cd5df2f
prerequisite-patch-id: d5773ccbf76c8d9ff26c63760dd0055d4365c476
prerequisite-patch-id: 71ce6e39f1a672d9924c63d3365a5e517bd6326b
prerequisite-patch-id: 45628cd61c02682f64642a7dad5edd72390a8bcc
prerequisite-patch-id: f6e95bd1f543f9c48f590c7dc1e4fa4e5f0bc458
prerequisite-patch-id: de7fae8b9afe828ee0d9b413378163719bf23bf5
prerequisite-patch-id: 1f228a1f43eaca0d8cb3cb4d0e51f90e815c9998
prerequisite-patch-id: eaa093b0cceb0a80995b0ae89392cec23c9d5b6f
prerequisite-patch-id: cd3d75fe297fd5e5541634007420f3aa7c03b405
prerequisite-patch-id: 138934b5fff6f62599848c496e0df4742ee218ef
prerequisite-patch-id: 974d30ca06e5f559f33d1a1657fb6df0db9c69d9
prerequisite-patch-id: 422baca4c98edc4b35bce264624ef7479b9be8b6
prerequisite-patch-id: 8d9c9e733f6d961e9c8030ac267c571c7962eaa0
prerequisite-patch-id: c14eea648e497a2e49222585f0890718ec41767e
prerequisite-patch-id: 1954449cdffc55d3f9dd27a4e3a25543963e770e
prerequisite-patch-id: f5c5a744afea35e7887f54904e099eae4ffb1aca
prerequisite-patch-id: ea51a4c1f0963bfe3e2d3b3f67f2fda1bed7e5ef
prerequisite-patch-id: 1415e67af722465af5288f5c55dc6ebed8abdf6d
prerequisite-patch-id: f74be9f37c99c3551b4a3aa1e90129b35531265e
prerequisite-patch-id: 40177684fcf06f9f7668a096332bcfacaa8b0ba5
prerequisite-patch-id: 4da39ed05abad8cb8e5fe4753f47176f9e72f0cf
prerequisite-patch-id: 2193c48aad99a7b7b97ed86ef97c07be900020a7
prerequisite-patch-id: 0aeff59426bed00d3f95bc72a6eaf7bf0b1dcda7
prerequisite-patch-id: 89d22914a9e5fb5039752b7c3bc9daf6bd46efcb
prerequisite-patch-id: ca978798bfa61476e54db18474c7155437ec2402
prerequisite-patch-id: 31b26538e173e882c0ccebe22bd0b38635284f12
prerequisite-patch-id: 1ab11d427effefc6d94167167c5519d474be897b
prerequisite-patch-id: 983ba2dceb7c26002eaa993a89f11f79e08fdd5d
prerequisite-patch-id: c9de3535115eb84960d4909c67c595b15f447b25
prerequisite-patch-id: 57b6bcbaf147da44a5cc47f8253db27bff5828cd
prerequisite-patch-id: bc7f23d98d7fbbb9e0413d297cddd31cf9e0dbd6
prerequisite-patch-id: c032bb4c8589a2ed0be0c8ad03ac9ff3e2f4d324
prerequisite-patch-id: 13e2df68f96c39ca79271507f48f5e212aec0115
prerequisite-patch-id: fe762eb689c310bf632bc19407995ad17bbfc2c4
prerequisite-patch-id: 2deffeb7b7935c74260ee8d64709ba7ce3ad0217
prerequisite-patch-id: a2582a6010bd1c460667a3a080813b33929bd2ac
prerequisite-patch-id: f450d1ca8a70d0b0c4889fa7bc60810732cd7947
prerequisite-patch-id: fdb116ec88160338de9b545ad02dca3f905aedea
prerequisite-patch-id: 1bb763f65bb738633bec985a413be4a0b39693c6
prerequisite-patch-id: cf0fe70af9ecd89401225a0d739d1e88583852ae
prerequisite-patch-id: 233d20ecb86560768ba2254695e2f794ae0fd33a
prerequisite-patch-id: 2c65bf75cbc7de019fb59a2da1f6f5f44b1ccbda
prerequisite-patch-id: f6c27f96bfa2dfe37a71d6a48bf500edc7ae3418
prerequisite-patch-id: 2ed93539ee2e5743a8b68d34576353741ad7da94
prerequisite-patch-id: 15785d74df9b983a08ee214513d117cd636aee8f
prerequisite-patch-id: 16deb75b0307db8f9f95dcbcd0b058722d386ad9
prerequisite-patch-id: de89214094f78ba21945e9b4243f21cb5717d5bd
prerequisite-patch-id: 041397724974afedefe7fb3f08ce6ad3f08d97b0
prerequisite-patch-id: 3c9b26862f31ccdfd5b3a7cdaa39be5120142a83
prerequisite-patch-id: b793e62096271e741444e8eb4184299ef8b2ba94
prerequisite-patch-id: 91df82d0f30fb73e8b9b878006bf0b4e4ea0d796
prerequisite-patch-id: 6ef2e3177b76f42906bdb2f876a94d949e16aa2d
prerequisite-patch-id: 96dc01a93b50f50e6d0528793095217379d66026
prerequisite-patch-id: ed35a1e1cb35e2dbad7689e94e09c387838fb411
prerequisite-patch-id: 0609fa34615f8047be739154ac89e9b2d6a8480e
prerequisite-patch-id: c9862b1ddd7cc6eaad90daef389c702df913a08f
prerequisite-patch-id: 90cb8842412a2ac7b5ccebbdb3630e0b5cc46c3a
prerequisite-patch-id: 8428e53fa41eb3e0b5188b3b6ca3288ce50be8b1
prerequisite-patch-id: ce8e418410c021788d50017dce6e13e1ced60bb7
prerequisite-patch-id: d7866cfaeb03ad945c8796a0308886c139047c74
prerequisite-patch-id: b350801c3eeeb3c80130687e8985f74188fc994f
prerequisite-patch-id: 14eea70294fd0f5002342760d112fc082271945e
prerequisite-patch-id: e4894f9f2debd0a2600298fcad44a1629223866a
prerequisite-patch-id: 62dace911ab970ccff9f382624d1c5f3aaec8aa2
prerequisite-patch-id: 5493504cd94c4ea7cffc218a980e6eb2a14031c5
prerequisite-patch-id: 58e4aa4e5777ee8af8f909a227aec305af457fea
prerequisite-patch-id: 4c4afb6f56b7882ce471cd5fb6cd813217cb2fb9
prerequisite-patch-id: 927acfb611453e2696dc65e8d83272ccd4b0e403
prerequisite-patch-id: 682c0fcd16293da15dd6b4e0f4fdd56ea9e6e569
prerequisite-patch-id: d58a92251520d5f46d780998fbbb0591bea4b7b5
prerequisite-patch-id: 9ed53909e9e1edfb76ab046e5d4e1b35fbab0da0
prerequisite-patch-id: 04ab1af392e362122437d19de2c9367c052ac83e
prerequisite-patch-id: 086b2c2e1753a612863b0971e075e20ea95c4a7d
prerequisite-patch-id: 29e939bbe7d45f377a164a09749d33f532175071
prerequisite-patch-id: ed5b4dfd1b1553d5e2b865c4191a992c30c21132
prerequisite-patch-id: d969c90cffc42d6b8c99170e0d10fc48331f2e58
prerequisite-patch-id: c9284b481f8ad787cb6f490bbeaf6fb808577911
prerequisite-patch-id: 517af516966899a43a303ccdd4fcef2a6e5ee577
prerequisite-patch-id: e0001b9b6263e02e3a731c386ca5ea3d65a51670
prerequisite-patch-id: 23e0e4b58145ca0d78c699b62e7a55ae1f52d70d
prerequisite-patch-id: 85f2326fe9ce690e3b42b077eb785e60e5379824
prerequisite-patch-id: e69f298f8c8562222f37d7966b4ef2c503b60e08
prerequisite-patch-id: 1e0e0263ab7e1bf157d9dd774a96ad9503734740
prerequisite-patch-id: f7496c45397d8f95adcf9830d1f5856927858405
prerequisite-patch-id: 73b3ffc5a8d655aa23423c8302809808d92732db
prerequisite-patch-id: ee62256a5751d04559d1504d46d4c1b7b0c6e6e8
prerequisite-patch-id: c6bd9f74134efea9daac4d73a1ec2c53fe3b585e
prerequisite-patch-id: 1d3a2310932060e996402c4a267c734e50c496ce
prerequisite-patch-id: 9aee8111ab4e57898d5e2f1b623c04f87695046e
prerequisite-patch-id: 86e3bd19355a5744bea9c42f3f8957d09a07a287
prerequisite-patch-id: 83b37fa6a526fc44ff01bf14fbfde8e83d6a7a4f
prerequisite-patch-id: 63cba8a93f43cd5045d451399f4a85fc33456e83
prerequisite-patch-id: 5a2c951b087317bcfe4b0958cdf171eab2421b06
prerequisite-patch-id: 1460d297d4f8e20c6d01c5f0f88188950fbfce57
prerequisite-patch-id: bf08a82d048aa92d7c3862ff32548a0b62c7f071
prerequisite-patch-id: 60ce32819ff090aad6e6ce01fd08e4071bda3549
prerequisite-patch-id: be5c127cd960ce5a25f67e640cf30078cbf79cb8
prerequisite-patch-id: e8b0e2e9e03f0afb57110066a7e6329b5b5a3493
prerequisite-patch-id: fbb79fe85a3568b84e05bf69c9e3ef5dcfc3257e
prerequisite-patch-id: db3f0b67b61d0fc2a5b5101ac6dd6419f5bd3137
prerequisite-patch-id: b87a3bb0452780840085c810052cbbc8faf4d013
prerequisite-patch-id: 8cedafb1b50ae33fa8f76e8fd133f6c2c414528f
prerequisite-patch-id: d04c87a8cf77d8094ff836f0be8d9e042a5d2768
prerequisite-patch-id: c96a7659555049e2cf961b4e21e800d674c91805
prerequisite-patch-id: 68a045c32711359289e1df394e3840881418bc45
prerequisite-patch-id: d2fa002984cacb5fa766ee7c0560e869257f5302
prerequisite-patch-id: 8fe48544ff726ed77247fb5c466c377e0c9dba44
prerequisite-patch-id: 43f8f3c636d8ba075c2e9bed14f234d41eabbe4f
prerequisite-patch-id: 457f419634d142b62065f976664bae627a80a51a
prerequisite-patch-id: 89472d9d3481d1da0bcc227abf1c9e66c790f1fc
prerequisite-patch-id: be9426375ba8f646fc912bd00db34e0ac41bb09f
prerequisite-patch-id: 7d7fcdb7252edd0f0fd8b13de24d1761a103cb23
prerequisite-patch-id: cff3b4ffc6a95a91579b10f461e507ce520bb9cf
prerequisite-patch-id: 1cd684d1263739811ad5bb310b5eb166914f02d8
prerequisite-patch-id: 4a5599a994849532a3ba984976c65effcf3ba0d6
prerequisite-patch-id: 2776f4fbf23e937f7df2bf5387ebef26688275d1
prerequisite-patch-id: 7d3346fffd5232416d40af4724bda9abdfdd0356
prerequisite-patch-id: 28f9cc22406f0f305f720ec3ad943e7f817c2939
prerequisite-patch-id: ea6f447beb65e2d5db1660827674287381b9b9e5
prerequisite-patch-id: 69b66800eb7c001b95df304442a31c3ee2f7e161
prerequisite-patch-id: ce27fdbca7c4d8166ab282e2b25d4ccaec40f393
prerequisite-patch-id: 441d22d2bf1d6c1e4a0eda0d9d31bab5cf9a2e55
prerequisite-patch-id: 53924cdd6f3692dd65ae1f77dddb73bdc3294a2c
prerequisite-patch-id: bb214b1e934caf834883eca585c353e115a08b9a
prerequisite-patch-id: c07154f982dd9782e25deb55b6a000e8b04c11c4
prerequisite-patch-id: 5280433b57d4692ae3f9e97e46bbaf7922370d3d
prerequisite-patch-id: 1c6f12b4e9309129788b424c9284daf6b60ee9b5
prerequisite-patch-id: c4eedfc09679d990e23c6d421aace9ed3d32f154
prerequisite-patch-id: acc4746fe3af90a2ec385ce57e853509295c06e0
prerequisite-patch-id: e244a220a68170d242ab5f961795783c6f04902f
prerequisite-patch-id: 6e65d510de4eabf09a54cc2ffcdb2bed3649f761
prerequisite-patch-id: 8d3e7fe354b3c3265f0adb8cdfaa24aa15391bf3
prerequisite-patch-id: c024806a31922d497318ad5fbcbebfab29a39492
prerequisite-patch-id: 44cc5b3145bc8e99d7fd0d041a6b68b6e1fe6af3
prerequisite-patch-id: b3d585e9af678cfb50903f4e1d9e66ebd5cff44c
prerequisite-patch-id: f931c78aaa05fd13f97c9bf12503294244701b9e
prerequisite-patch-id: 1296062e3df72f7f2cecb668308961fb91be7ce9
prerequisite-patch-id: d75b242588be7739718e1a070295fb63cb7e0756
prerequisite-patch-id: a075a5befd7dd6eeab88fc3c4796537f3da83473
prerequisite-patch-id: 2888d4c35b48823523526391bd4b9ac83a4f8a27
prerequisite-patch-id: 7444dbafcd85b722ff5f41ecb9671fd51b5519d8
prerequisite-patch-id: a8d23c66ec57895c58f75e3518635cd29ac21ded
prerequisite-patch-id: d18b4181c229b683f388f8f9c7ff136e460975ce
prerequisite-patch-id: 6b90a832959fd5cb5ece8899f552ca357353ba58
prerequisite-patch-id: e5cc026d99d74c6bb98b7342eb23d1b590107a05
prerequisite-patch-id: 52fa32f509bad09f82578a7cc4864e0605c88681
prerequisite-patch-id: fb6c31f20c42664f54cbee98abcb2d582ee3833e
prerequisite-patch-id: 2299f6a41d417afb467795864c5b61c3a5f9f0ca
prerequisite-patch-id: cae81655b0bfa395f898148fc1d0d36edf7a8193
prerequisite-patch-id: 536ec4c2b03517f7dba70a41aede81bf6ae5ff7a
prerequisite-patch-id: aaab2c2cc7a4a6f49698e53b44cdfc8607c8a376
prerequisite-patch-id: 670d9d7ff5df66b84ff27bcce9dd01a7532a2ba8
prerequisite-patch-id: 19b180164e39c5608ff6902ab5ee553b748f5859
prerequisite-patch-id: dfbd93a818d3f5eed596c4687835dac991d166f3
prerequisite-patch-id: 8b22664e85536beb02d22879fab98fdf28315618
prerequisite-patch-id: bffb029a8cd6501e407602cd148d5c21e25eb965
prerequisite-patch-id: a32b4d2f8d7184031c0a306976e4cef229347f3b
prerequisite-patch-id: 9017fe93144820e71d2cefb72fcb03ce7313ca99
prerequisite-patch-id: 34312d59de349a80a376206b3404437677b7f120
prerequisite-patch-id: ebe4bb17027660572ae9658cd8905bdba0c16e9a
prerequisite-patch-id: d692bb75ef1969172adeb099a6386c1235013153
prerequisite-patch-id: 9a3f301ecc93d23af91a8fe8fa6e714343ead32a
prerequisite-patch-id: 5e6cb0983183e036b55f4dbc6094117166ecb7cc
prerequisite-patch-id: 95c6751a65b543906730039b811bcee257a3f3ab
prerequisite-patch-id: 54bff55d537cc871a230bb15bdc225e7a61c2b26
prerequisite-patch-id: 79fb07650546965c020b4eebff80eec5efa57bf7
prerequisite-patch-id: cf16d2b93d7faf1cdddca0080daf80545b82d661
prerequisite-patch-id: e5c5aeb4fa79e524855202494d7b3b2cf1651a36
prerequisite-patch-id: f5396c4fc6e4040f291daf3f84035070dfe38271
prerequisite-patch-id: f6ddc0842121b48f63b5fb7734ba813db8674ca4
prerequisite-patch-id: 432b69e0a862428f8fc11ae6a0fc5e41853f015c
prerequisite-patch-id: 1af2cd1ad1c428e398f0414f9cc273848352bd90
prerequisite-patch-id: 3e5613ed437bdc0657edfe87c943176f74ff0b3f
prerequisite-patch-id: 89b164ae83d3673a8f1216eff71ad9788005f3ed
prerequisite-patch-id: 26944c7c5b305eba9ff4e35712c43284e26e211c
prerequisite-patch-id: 3038246646d7e5d23907dfb79b7f82ad5deb8805
prerequisite-patch-id: 1ce089814d735fd92bdbdbf48ddf761b6413f655
prerequisite-patch-id: 83125519e4583cf56e4b6dda892833ea7ced750c
prerequisite-patch-id: 290cee975ff773fa261fb21c0545f13c1ab235dd
prerequisite-patch-id: 19c282c8895c4b32baa31d9198d4b82c344060da
prerequisite-patch-id: 63801c6984e518bd7b57631020492c2aca4f425e
prerequisite-patch-id: ab1a0ed3805aa3944aa6c70a3b94a208ab7c45f1
prerequisite-patch-id: f4d1b4c03fa7bd5291d5f35ebdaf28eab69aeef6
prerequisite-patch-id: 3897c590116da23981b9b7f3b1fd6916ed41d432
prerequisite-patch-id: 722f38a8ebd79f6ee8a19535f5a95ee46a87ccf2
prerequisite-patch-id: 8f773daf68d7d46894e54f701866f38184a0f7c2
prerequisite-patch-id: dac81a32f5cfb6328b31f352470bf8a9567c4d3b
prerequisite-patch-id: f1a0f7dfc35e59e81c69c294a7feb51d58592989
prerequisite-patch-id: 089055482caf7a20f1661dbb33aeef6636f9252c
prerequisite-patch-id: 389ee5b8e985636736446b23f5f601e4fb15475c
prerequisite-patch-id: 384a3037d947723c09c54aa5502911614e273765
prerequisite-patch-id: 9941250aabcd893faa88e89d4140241827159d46
prerequisite-patch-id: 0975a519fb8192ebaf82a6e308c3ccac3f32b450
prerequisite-patch-id: a029a87a1d19c67dfb33d10749c1336ecfc6ba1f
prerequisite-patch-id: af738eb988982b72cf32553b30bb18ee27360dac
prerequisite-patch-id: 69f4cb485d3b5d01be21a3c78c494aef1e1c0fac
prerequisite-patch-id: bacc53a7aa217954866d08dcf10a52348be86760
prerequisite-patch-id: 746f6ab8bbebfa83d44b710b18f25e0c693cc227
prerequisite-patch-id: d1ee1c0a8dcb68c8e4adddc0eaf20484adb765bd
prerequisite-patch-id: 0915d1ff12b43ee9982a8d420acf1ac9c3f28e34
prerequisite-patch-id: 86538de475f1ce84853771cb0cb3348b66c559ee
prerequisite-patch-id: 9409dfa4ab865c51c697f573dc1574c38d032385
prerequisite-patch-id: 9db4775859dce41e343a7a231a1a55928b0a6e0d
prerequisite-patch-id: 57b2b865515799e3f903ebf860c75ffb1a3821c6
prerequisite-patch-id: e9f12cda0765307acaac3aa00e93fd0080329ad4
prerequisite-patch-id: 28c6a5c9c0794adf089c24e5f59586631c5d6b4c
prerequisite-patch-id: 9c603e2a4d0559a6884f896b09d1c8c0589da1ad
prerequisite-patch-id: 3a01250499d35e1757d36f7fdbf1190632b6cdac
prerequisite-patch-id: 92ca7f1db806b24e9695770e923643b850fadb52
prerequisite-patch-id: 5ec5fef9fafbc91fb5785cd215d8da0bcef4d574
prerequisite-patch-id: 6e3441b16c01cfb8efd3f938adcf55a784b5e1d4
prerequisite-patch-id: 33c3e95ef39d41155b602a214fe9f8d5ca4917b7
prerequisite-patch-id: a5e40abb91a8a9c90d130fc5af7ea42559c5d7f7
prerequisite-patch-id: d27b7c7462ff417e351bcb0d7c41949af2ac7afc
prerequisite-patch-id: 12ac470a51ff8c96801e6fd047ab7441077268b9
prerequisite-patch-id: 6e3536e64c991c1d710b855d65a2e25a4fb9fdc0
prerequisite-patch-id: fc051e6207dd4376fd7b7706c54d098b0f818f74
prerequisite-patch-id: f5e2519a7be4d136a6515be6cd9ea4571cf6abd3
prerequisite-patch-id: 8f3ada3b8e14e06422dea35453f08a0d51d15cff
prerequisite-patch-id: 2f968d1f224a034addcd9df6c3b030e4e28af5fa
prerequisite-patch-id: 1794f68df5baa90b3a527f4f4fe53e59b018d401
prerequisite-patch-id: 2ec31d5e0d80527e0c23b08de5821263d4a0075c
prerequisite-patch-id: d151afc82ec8745b93c1ea0105f3b0bba3a1ddd4
prerequisite-patch-id: bba9a199ccc2440600386e0457bce4f80ebe99bf
prerequisite-patch-id: e78a4c5a6af7fc4b22f9bfcf64277037ea49b384
prerequisite-patch-id: 3edb87cbfbdce464089b9c1060cf840a69c7ea1b
prerequisite-patch-id: 5934e18518001a89e3cfe5cbe756b3d9a6eb1166
prerequisite-patch-id: 7c019a15cadd978cb479633000c0f2dacd10bb52
prerequisite-patch-id: 841dadb5f8a89fbcfe3f1bb424c4a60f78a77083
prerequisite-patch-id: e58d6acc2c142ed6ad1a0bf7c06b9dad18dc20c1
prerequisite-patch-id: 679adeae1a72afbce141e4d0218476d31aae2815
prerequisite-patch-id: 68d67a0a3cf0d58f6f58d74517e63f53e93505fd
prerequisite-patch-id: 066f669c9af54b5c645deef1b0c4570a9e6bbf65
prerequisite-patch-id: d5daf8d8f195b54ef670e65f4d219aa7c660fffe
prerequisite-patch-id: bcac5b73c5cbae987864f550021c2f82d3d9ee8b
prerequisite-patch-id: 0b665a0ba6a980db2dca7645febb7219691664c6
prerequisite-patch-id: b460f0f90227717309d566c3a72ad09ff9593cb7
prerequisite-patch-id: 1862f1d2586c0fa27bee90b63f4b54f4d920d032
prerequisite-patch-id: e974c1119d570de40c3f3361afbd6e3a456c8338
prerequisite-patch-id: 303a591a800893f730b616de8e4c4e64497ead57
prerequisite-patch-id: 1fcad282fe5a71275f9ee54eaa4cb8519dcd142a
prerequisite-patch-id: b879726293513fcbc4b7df92bcc976404416b695
prerequisite-patch-id: cb9e1e08eef99b55a9d4a642593e2124b1d59bf3
prerequisite-patch-id: cabb5c5f62947e5b8aa76ad81dbbea20d989304e
prerequisite-patch-id: 992aa11e3fa7d5825d3323e5402387d0b363540d
prerequisite-patch-id: fc8faa8f143a7288e2091443118568a052b6e6d2
prerequisite-patch-id: 4f644256e92f677bba88b723c9247e4bb5594ad6
prerequisite-patch-id: 6312ff8ca67c4fed6c7f2fe706393ed60dc0242e
prerequisite-patch-id: f0bc9598cbaafd91f50a8d92b97c8fc4bb7e559e
prerequisite-patch-id: 25ec3e05b340c787a34b4e255578cb125a1834f2
prerequisite-patch-id: 22bf77ebd8e2347fe690234b649367cc34739fec
prerequisite-patch-id: 0ef3de8f8c951a075dc085a6595a57586f989cb6
prerequisite-patch-id: c606a1320ab84cef1659abe68fbd4eab3f7bdeff
prerequisite-patch-id: c82d465fbca8610df881657b72f7d8dae3b0e79c
prerequisite-patch-id: cdb1275fd6bfe29f07353bd90f54951503886c4b
prerequisite-patch-id: 5b95e0663182a21e01f88e4501b4ac243ce177d1
prerequisite-patch-id: 20e8a12e4aa42674af00439dd442ffc38440e751
prerequisite-patch-id: 0d1e9e307840fb071022df8c4e9cb4d9e88f2b56
prerequisite-patch-id: efdd1ebfca9594bfa429c9bd93f59dbe224b4aa8
prerequisite-patch-id: bc8b9e35515808437851054d99c804028ecdf6bf
prerequisite-patch-id: 9755ff232b993329cdd266b7ef0e1b401ed5b4b9
prerequisite-patch-id: aeb939939e9383d00f242a9cd1839fc41f1a4256
prerequisite-patch-id: a2651fce169be1c8c31e1d9e0e9ba9373dd5a0b5
prerequisite-patch-id: 7a2866a45590b5465a62329b2e7831005a5632f1
prerequisite-patch-id: 1749abaa42e89597316db4a2998f6ae4de6947f0
prerequisite-patch-id: 6fa71c7c79ed25c70a17490f0e3ab86101d9d024
prerequisite-patch-id: 9b7d6d38423a56cf42b0ccc45ac41b2c0522d2ff
prerequisite-patch-id: 2498825797ee2bda24bcb244144737ba069b7930
prerequisite-patch-id: 25293df4400faea32b554dc32475992582dd06b4
prerequisite-patch-id: 3ca576b60af50d8cf4ba78a6a8a8aa6cb90139bc
prerequisite-patch-id: 6e5bc789ad2ac22931789cd28d5449c953c2ca8c
prerequisite-patch-id: 7dad009046e8104b69e6d253e54f6f8db59313e4
prerequisite-patch-id: 9eeb9bd1ac6d76aaa4e4591256fe073526f38a04
prerequisite-patch-id: ed0fd0b37fe8c2e66338774106febc8cddc29931
prerequisite-patch-id: 66083e5f3f4ec4642f94252b242e49b790b8129a
prerequisite-patch-id: 698bd67ad1caaa862d66239a0be98c2e409db6e2
prerequisite-patch-id: 45e37b374a981429338bc38158fce475a0db7924
prerequisite-patch-id: 5a11d6a33add844132489eeb175817f388695e2d
prerequisite-patch-id: 9edf1e582dcac29f4033833b400a4c52f3857161
prerequisite-patch-id: 6e9772f7e705dd3580e5868fa4e248c61be96e30
prerequisite-patch-id: 3f4b587ba344283c7841db9d3d97f449629493d7
prerequisite-patch-id: aa862b30a9fea7a89f6131b294c2932f0bcc78f4
prerequisite-patch-id: 8d852707a4a2eb203205c5465987d1e1d8939450
prerequisite-patch-id: 532af578825a58ac9c295fc8db429cea3b277098
prerequisite-patch-id: c8a27cad31f849aef57325ce65d5ebe285dcf4c7
prerequisite-patch-id: d8b7650cfa3814c5a0cc5c8e0ab39d6336c2b33e
prerequisite-patch-id: 87c4a2643ae883dbb8501900425ae977ad150306
prerequisite-patch-id: 4fbd11c27b6b7daebb9a5dea3c719fcc2262798f
prerequisite-patch-id: ee3f6fe89e83f486e6b8ef6efdc6b2db45a72864
prerequisite-patch-id: ea6519809e16b0782415f7bec2cd5a935d9c73a5
prerequisite-patch-id: 7dd6748c710479f19aaf218b9f5686af15855c2c
prerequisite-patch-id: 77dbec0c65ba3797ed41790dfbaa78203329bf39
prerequisite-patch-id: cc15520a1cd5b1bc5769b51a3e9eb85c2d393188
prerequisite-patch-id: 0732b9cb53a202093b3d9b7750a7f5f1b4f1f3b5
prerequisite-patch-id: 79894442b1be8ca9e078ea88fa13ccbb3df28550
prerequisite-patch-id: d4a137a8f49975f2c6c20fa267a2d9cac61d26fb
prerequisite-patch-id: 06ca55f1a01829ec7afc5b47985686f908afe8d4
prerequisite-patch-id: b9528a32154ccee95e1b0c2b68c96f42c3b1f9f7
prerequisite-patch-id: 48e29f71eb0fe4df5c6a42cd1e8567399d264ffc
prerequisite-patch-id: 1a6a233a806dfd05b93b9a622ea6171ae36417ae
prerequisite-patch-id: ee8f15ff1d084d334c8acaaa451de7d421ae37a6
prerequisite-patch-id: fab180f96e075818a3bf36bb50c35d9a0ff6fe4c
prerequisite-patch-id: f020c4f16e6cb53e014dd3371932b06674d424e0
prerequisite-patch-id: 04dba0554f700b6dae0732976d233bad95182e59
prerequisite-patch-id: dfe758dad73e9c94b243927b0a0e5e3aa19c4842
prerequisite-patch-id: 3e8c0d29569f8e29d5bfa3870a96bc341b8ed084
prerequisite-patch-id: 8ff38cd9ec3cc8d1bd46ea9f09f6abb0f9feea64
prerequisite-patch-id: 284048587c1b428540c43c712ce4e3ba0e53ac22
prerequisite-patch-id: cdf9cc5669dc2f9ed9b86dbb5cb8378ee8e2dffd
prerequisite-patch-id: d002d2307e6117d0b9529616b612c7f49efa9c1f
prerequisite-patch-id: 62483f5db9805228e548613b2e3699b31cfb059b
prerequisite-patch-id: 50995631250545c1952e7885776230edb0de8203
prerequisite-patch-id: 420ac7064075cb87ebac3955096a96c57b88c8c4
prerequisite-patch-id: 44f502402b740e6cb75becf6b4c8a65660cc379f
prerequisite-patch-id: 0c898ffb8b42d2f9f9adce3bf8f5c7c9f9b1d46a
prerequisite-patch-id: b27b8c4f0be54edfa12f2e2d751ee9446d74c6c5
prerequisite-patch-id: c6a01dd5341e303968c6703c098a9d28e30b1894
prerequisite-patch-id: e4e268a418266086339eb9bb4b7eb89a26e5297c
prerequisite-patch-id: a801338ef99c377b3a39bed175649d001463c0d1
prerequisite-patch-id: 35aecf539a386edb1d08f2845cf0af4eef3a1b48
prerequisite-patch-id: bfa07db433e94539f3e376de5d64e54bba2eb3b0
prerequisite-patch-id: e15b50a62e24983d78627dcdb37da674978f2626
prerequisite-patch-id: 75cb7cfee66c5202941eb878d75485393e802545
prerequisite-patch-id: 5e1fc713a9a14275ceec5a3ba41fc951789f3967
prerequisite-patch-id: d59fa648686b5ac19ffd72832cca3ecfe9766d02
prerequisite-patch-id: cea0196f4c053094c5b316cf0a2f1f3c74b63cec
prerequisite-patch-id: 423c19d2e540f684e6815c0f72635c5c39745c1a
prerequisite-patch-id: af78cc216f04520eb441883a5bedfb19dddb9933
prerequisite-patch-id: 38e3c498d39bff4f67130f13c6f27021c39bb54d
prerequisite-patch-id: 57ab685b78ab971efdef882d4c35d6c472be6151
prerequisite-patch-id: 4ba4c4b49dc72df9a1b137fe7a267072c220984a
prerequisite-patch-id: b4e9bb4915ecea620b32d86c21659299efabb56c
prerequisite-patch-id: 69722f3b1418464d0d6a780be1c6e4b74346320a
prerequisite-patch-id: 35822013e41cf00f69fd1ce7e81c2a585beb6e8d
prerequisite-patch-id: 9411fd133b93e2259f5628b2c275cb27c6ad094b
prerequisite-patch-id: 204ac5f376f25945e0c1eb7b52c473a85e058c24
prerequisite-patch-id: 5e305314ab8c43dcc298d8b39b3ea280d045d77c
prerequisite-patch-id: b9ea61092da07e7a0da4aa6fb79e16ae77afa2ae
prerequisite-patch-id: ed80f84b02532fe41d93af19603aebcfd65e949b
prerequisite-patch-id: 2e90de4ef45e00a74fb1aea3f6a1ec727329ae52
prerequisite-patch-id: 5a1ea5e2712fdec1f43728133c456f502c4028af
prerequisite-patch-id: e908105a9e435cd7971675758d2d67d442121ffb
prerequisite-patch-id: 7f30da70196e31f543db1a9ffbe533f7756378e5
prerequisite-patch-id: 5a75b6ea4c4dffd65c4f9f0e7bf171be4109aa3b
prerequisite-patch-id: f7ac979062c0e1379f24fb14a3578e98fcfa9a13
prerequisite-patch-id: 770d132a909d713467f62791d58f74e4effa4a23
prerequisite-patch-id: faee6556ff141b783fc0fca0b0c157f895ae6589
prerequisite-patch-id: 01c0b55cfae6d841cf7bade83264509470325de7
prerequisite-patch-id: ecae17791d171a5cf3eb157297fc9661ece9849e
prerequisite-patch-id: 7402bf8989dddb67dd1559acca2e01aa83140123
prerequisite-patch-id: 043b6dc70a1a301eb9511defc7750860ebc38668
prerequisite-patch-id: 10b57e8866610c0978c4260d916afd5b9e32e224
prerequisite-patch-id: 064b7e196812cf4717d12f88a7a93e66cc1617ec
prerequisite-patch-id: 463d0143cfef3c628a74ade9bcf56acab9fd4efe
prerequisite-patch-id: 0cb3298cf43138b45117f0e87bec3d9ed9f01760
prerequisite-patch-id: eaad7f4cdc7d5390417dabba6771d6c151a485df
prerequisite-patch-id: 812df4210b4b43ae324b90cab8b158be0d09b987
prerequisite-patch-id: bda5e6da3341aae3c94d81fdf8937656793b9659
prerequisite-patch-id: 5a879e86be9fa4b863804ded656c63473d115724
prerequisite-patch-id: d3fa701ee4724557a60d142988d909766d9af499
prerequisite-patch-id: 0015fc2de3fee67993686950687a6fb4c8f7cb49
prerequisite-patch-id: 9f9528ecf9562d9d7ddd8956a4516a57ece6af67
prerequisite-patch-id: 559437e82d7d5f23cfb297f28d4c17ff4ec4900b
prerequisite-patch-id: 73bd56454ee4f5f889f9935763274fdd487f002a
prerequisite-patch-id: cef5431cff055e4afd69f344019cbae2bfe8a7f3
prerequisite-patch-id: d12c6031c57e09ebbd9fcfe62110e4ee9c4cb8bf
prerequisite-patch-id: 637cc1434130d5decc696cf531f9c178d73364ac
prerequisite-patch-id: 8aa89e07b8c417913b1c8f7ee7dd4fc1a16b2014
prerequisite-patch-id: 5eda1bad1a6cc0c1d3110881393ed61ebc7bf130
prerequisite-patch-id: f69230a62e0698f3b01adfb08dfc83e6a987c67d
prerequisite-patch-id: e6b1301238a8a536adba8d2523b0e8ca04119a79
prerequisite-patch-id: 29b8ae49eab547a8c4269dfd4b4a95e9e25f0edc
prerequisite-patch-id: 4487b604781dcd0eeda7b650fb0b6f094f64fc90
prerequisite-patch-id: 0c84b2c06ff3f041a0e70454c6616d9020fdb8dd
prerequisite-patch-id: 827903f984b3fc64441d2b456c35b752d2a901c0
prerequisite-patch-id: 27cea095be6f2b29179c8e17eaa9605c2bad0a7c
prerequisite-patch-id: 9d4bc46a26cfbdc0c44b3c562fda3c0410a2edcd
prerequisite-patch-id: 1188748be98a08984b9a92f77ea22c2f56b6c337
prerequisite-patch-id: a8fe90de44bb1c6d3e1b11ef6d4ef6b86094730e
prerequisite-patch-id: 929c07df466d1ae09ce6a5a62b608d01dedfb17c
prerequisite-patch-id: 8cba3e5d39aa47cda6d3447e775530598ea688c2
prerequisite-patch-id: 3ecfbaf5a4e0ea34cd09211604eaf7407d022bb4
prerequisite-patch-id: f4e6a64dcc187752faa22121b3fa1102d1d64cb9
prerequisite-patch-id: c36a33fbedc157f2c7a9668bddcf36f74ca10032
prerequisite-patch-id: 5aceb6a0b11d6c227597e835adee1848f240021b
prerequisite-patch-id: 273dad87c9a1e1fd0db881dc2d9c4c4d98ff1eb5
prerequisite-patch-id: cd516605e1a2161fa346010b92c909134ac03768
prerequisite-patch-id: 458e821bb39bdae89de21464d6a7bc6c543bb80e
prerequisite-patch-id: c81057935daebd4bc9b53c3bc290cfa9cdedaaff
prerequisite-patch-id: f4be4148aa65423a07cded146922e48b00709140
prerequisite-patch-id: 66571b3afb78e5d74fd0536a138df22c2bdbdfed
prerequisite-patch-id: 721dbecea86184a8538971f6fc3672dd354e9739
prerequisite-patch-id: 4e196ade903b1743d6a8d7bdc0c8cfeca62ecacf
prerequisite-patch-id: 0044313c793b63dd002469f13ede022a16b15196
prerequisite-patch-id: e2d7963a8b58ca242338c0867a8f40ec1c9682ff
prerequisite-patch-id: e4a2a37bba772ad118014208a84db41c22897b4b
prerequisite-patch-id: 775264cc01b43db7e672aac416c806245b00ebbe
prerequisite-patch-id: 675a9b3d9f94d184582df5e740cf211d3957a8a7
prerequisite-patch-id: 7ae711430addd14f3b28fe0a862ef92f643ada7b
prerequisite-patch-id: 84f417e95f2e83cf3d223919fbad3174dea31bf6
prerequisite-patch-id: 08fb8c1651a1af3fc9bff59bc7e2eaa964b6b493
prerequisite-patch-id: ef4f7ea666f0a0b5adb19a364f1d48dfcc83361e
prerequisite-patch-id: a1d44a3efdd35f14db2168891897560f9721f9ed
prerequisite-patch-id: ec1e1b2355b7b33d949b842698ea91acce1a1dc2
prerequisite-patch-id: 7723c4642968049a3f04c2902699067fbaac0f50
prerequisite-patch-id: 5c169a5312e9bf76aa1a7a6b21b986ff90569296
prerequisite-patch-id: 84118148cd324aa548c37fe8591406cec6be7e45
prerequisite-patch-id: eb6b0ffa74114db95b945e6e674f5de62cce654c
prerequisite-patch-id: 85d99764ba65f88aaaed956c140ca9d78ecb42df
prerequisite-patch-id: 8f7bcbf08c92bde3f88f204365c99b964684e881
prerequisite-patch-id: b4bac73cd17eb4646d3ef4ea6b98012eaab59115
prerequisite-patch-id: bbc44946d192b9a42ced16a60c5ed006dfb49500
prerequisite-patch-id: d6a6de83750fa5671312b686a92d3bfa6cf99e60
prerequisite-patch-id: 6f9d54bda524f819c1110c2fce7cd3ac69836815
prerequisite-patch-id: 5923021d7d6119d2846b1479d4ab486013d3ac84
prerequisite-patch-id: a7c1bcd386c91cde581f4802d00b715821a3ba8e
prerequisite-patch-id: e07a228fc5deee1aa04fb4c2b5129fd1dc74ad4d
prerequisite-patch-id: a38023788f3b62b52d8351c450cc44557895a091
prerequisite-patch-id: b390badc1f867b23c5b7d005512c14b545fa9328
prerequisite-patch-id: d7c543308f6de2af847fc4515d9b517bf4e79fd0
prerequisite-patch-id: 736973d8f4393af59e8b01c5618a4175d16777ae
prerequisite-patch-id: 345bd7fed23f85891d17963600888f5267cb4f14
prerequisite-patch-id: d0a8ff04b6df0310a2a8f06bba522cc0115787a5
prerequisite-patch-id: ca308c5f4f9b123b941d09c394681d57152a4ef3
prerequisite-patch-id: e715a03c2180127d509d032f1e3aec7cc96797a9
prerequisite-patch-id: b1dddf090f67bd6234db9caee3c1976b00a966cc
prerequisite-patch-id: 32170e4f396b1bac984c7f14dd5f8d9bf731278e
prerequisite-patch-id: 62d79aff969f2180c506ddb1eddcc8b449300466
prerequisite-patch-id: c3a41abc55ee6837c3447e252d9bbae2a701da25
prerequisite-patch-id: 4b7c2b796f27a75518ad80b67f7bedff59568d47
prerequisite-patch-id: 0ccfae411cd31fb7472b749d2b18b011378780e4
prerequisite-patch-id: f05c48b3a1eb17cf525ac2a7e7464a2ee7eae4eb
prerequisite-patch-id: f4178398794e25ace228166552bba0a42e6c96d5
prerequisite-patch-id: 3336fe52ec48b76a5f502fac43c14573c87a19d3
prerequisite-patch-id: dac8b0987cb0281feddbfb697a1005bdc9b5a6cc
prerequisite-patch-id: 909e6a82e7d87b0cf7c63027cc258688550f939a
prerequisite-patch-id: 6b83a5bbf40f858d8a4e7de23df8624664c3d2ae
prerequisite-patch-id: 5c5b98e274ba9d7c6458084f02d305f7ad6190c7
prerequisite-patch-id: b3e53553fc24a74860f235c66c6ac1b188a94bf9
prerequisite-patch-id: f82ba3d3672a91b693918541e0773b750034a2f3
prerequisite-patch-id: 5bfe61eb10a4487f288be402e64f323dbaf425fa
prerequisite-patch-id: ad0628d1ffa66b02a021bd854153da1185b00d50
prerequisite-patch-id: 16293c19a434bab1ffc5be012555bfb739ac3391
prerequisite-patch-id: 23a38e6b1ac8ee96d4cea92a74902e22bf32ac30
prerequisite-patch-id: ac38629d757701ac70d1b2b7fb66f9f08433390c
prerequisite-patch-id: 0cddb92816cb457d7124bca2c24aafba416acd1c
prerequisite-patch-id: 4a97ed85ac3f78d2121edb09637a11ed5e7b8873
prerequisite-patch-id: 1611c315eda9405844c3651e15543578f7b224a8
prerequisite-patch-id: e296a07614e247b600d652c5f47648c56badf16b
prerequisite-patch-id: 920da6b4be03a7de3bb3bbcecb986a7109d2e88f
prerequisite-patch-id: 58d9efa3f306004890c6a68d32c97300ba5180ae
prerequisite-patch-id: 4abe7b5687fd3dea136cabde00865c45d04ee391
prerequisite-patch-id: 39518cb25ed1a552c55250e36288ad75ed7048f7
prerequisite-patch-id: 54db3a330c4454446a0c0523aba8af5f30996f49
prerequisite-patch-id: 919ad5993d9120bb3c4cd0d7f43cdc8ba6218d58
prerequisite-patch-id: 343176e16afa0bb301f5c93b909e3668694e9d92
prerequisite-patch-id: 1fb12a9e29bd641088d0466a47596efea2d07f48
prerequisite-patch-id: 808d4a397508766ed8ac2d7728a48cf713495f98
prerequisite-patch-id: acfc18bb4adf4240557880c14aae49f43b976cf5
prerequisite-patch-id: bd57f75c5e5b8e2af553c73b63be19e10152c262
prerequisite-patch-id: 1ad9b41bbb319e58757f90b9e563eb43e151358a
prerequisite-patch-id: 3fdabca66aa3ac5584b162cd0183eff4b17aa741
prerequisite-patch-id: 2a81917cf088150d4d6f5b20cfd3ba145476724f
prerequisite-patch-id: 34c1427ba334ab96ac055460e55efc5bb76c7151
prerequisite-patch-id: 0d36d0f0da4e00a2368bb94e1c249e7fd5e6ef18
prerequisite-patch-id: 5e75644f27c9f4067e9f89f882a1c57ebc938498
prerequisite-patch-id: 06fe903704bdf8747b1e84776a3a92a039991659
prerequisite-patch-id: d0486d7b596c3f49de3d082fe4422f1e39138e72
prerequisite-patch-id: e37599d7ad7ef6997f910c94c2ebd9585f969e70
prerequisite-patch-id: 208beb78b05c57d9423069dced05a27033859f6d
prerequisite-patch-id: 7cf208632c7ebd159f6d4d1374217b873c757f8e
prerequisite-patch-id: 964089b505c690a9487a1273cfc65ce0d52dfac4
prerequisite-patch-id: f19036152be4bb6d15d216625a2c4f1b15734f2c
prerequisite-patch-id: 5cf81fa47f82869fd1bbf655a6d8ba36881d808a
prerequisite-patch-id: f67f22060b349ebd9baa0358b710f468bf8c6c1c
prerequisite-patch-id: c36c5ab719431af026901e9d9d3f799ba6924b60
prerequisite-patch-id: b9eed72efe1a4f6452e796e9647e28d7d5a808d4
prerequisite-patch-id: 14c5eb3c626b3d15b4217eea85ebfd8dcd1d87f5
prerequisite-patch-id: a6776c5f48f0febf24959106a2d014eae9f8b4b4
prerequisite-patch-id: 18d63501962b4eaed57704c632f054da0efe6949
prerequisite-patch-id: b6830a9e790f22794beee604d42220354645e91f
prerequisite-patch-id: cf505be91555743cc09c340d36d48eeec02d338c
prerequisite-patch-id: c61a507e8ab1180b0b1a214b36f5a05e4fa178ca
prerequisite-patch-id: 6c22308847a70b35aeedd50f509f60f46f252852
prerequisite-patch-id: 93dbf91fcd77f1cc18a465b7d5bb99118c28f7a3
prerequisite-patch-id: 9c750ce8bb0b85c51b0ac9fb5e22222c05d89ce2
prerequisite-patch-id: 4f1d97a625200f9f0ba8eef3086d7aae8fe8ab42
prerequisite-patch-id: 636c79a16d12680b279ff6f30d89c63161cabbb9
prerequisite-patch-id: 9abb0279f60d77a375d6c71f98be174789b3a122
prerequisite-patch-id: b6e3e0d6ff0d46c457f2ebf5d1fd67aa07cf6ff5
prerequisite-patch-id: 04c619729c4854f2a2961f499a2b4d6c4cec20da
prerequisite-patch-id: 3e727c4294e5a0636a30f963bbfd6617a71c199a
prerequisite-patch-id: b41ce3788f60be3a5ddf32a4d14aa2eaa472bee6
prerequisite-patch-id: 54601fb89b1fe018c42cbb0ea6ed0914c192511d
prerequisite-patch-id: 33c6e88051526501f86d2578e5fce7d1397426e1
prerequisite-patch-id: b482501b487f34702061445220fb4af1978c0dc8
prerequisite-patch-id: 189a84cbdc72923ac43619343ecac4ed1b3d2475
prerequisite-patch-id: fa4d175bd937ee97a4f27ad0e9b7cbead8f10e43
prerequisite-patch-id: 10e07b0b32881dc346dd786d411bdf7e75647999
prerequisite-patch-id: e5d0560693233bfd7af769951e44c7c1abee5732
prerequisite-patch-id: b145b357d4dbc4093c246d71b65e5a1453678eb3
prerequisite-patch-id: ddcba15da6d020cbac920e13fc7f1b712cb099d6
prerequisite-patch-id: 45f85cd2fdcecb6d33445da1d255b4f6805ed9a2
prerequisite-patch-id: 750582bb3966ed52aadbe79d8e46086751d076a9
prerequisite-patch-id: 0edad4a58b5c2b81c59d321557f2b7c8b39de7e0
prerequisite-patch-id: 793578aae1101c723532bc6a89a933ef3491c1d5
prerequisite-patch-id: 50a57121b0aaaefed61f7a47eee6f1f293bbe0ac
prerequisite-patch-id: c0bf569a88695247336214bc177755eab9dcd37a
prerequisite-patch-id: a4711cb4bbbd5809c0d0eb9954e691c41ff402d7
prerequisite-patch-id: 172eb89b296c37dbd893ddbe9fd74399eb3930c5
prerequisite-patch-id: 65a5a5e1bcb7272a48420ef071131f9854848c1b
prerequisite-patch-id: 897bfad1fc960213d45bae461f91304f0e5e0f8d
prerequisite-patch-id: 16663f9fbb7b2ea0d97442de934e8e2befb6c5bc
prerequisite-patch-id: d23ebaa2c035b285b7dcded40e4e724f740bd9c6
prerequisite-patch-id: db9e6168806fb39fbee8e89171933d387ee40c3c
prerequisite-patch-id: 859928c8fb5a8361e86f83d0bd8a1d24b2093a9b
prerequisite-patch-id: 1121e8b41831ed76d2a84f205dcd2ee39f32b8f2
prerequisite-patch-id: c9c5f889ce6abbd0c7f50694acdb043dbe4fdbbc
prerequisite-patch-id: f1f28e18996ce7ddae50e47ea31b52d85aef6c51
prerequisite-patch-id: 8d5d086cb0a4d654e58e5e15e540401d6d1a3208
prerequisite-patch-id: 61559b627ce865c148ca1629f34ef8fbf0651ff6
prerequisite-patch-id: 0e42fcf9c151abcbd78cf7344bc776d977c0120f
prerequisite-patch-id: 3aaabe701d2536c8516539885ccf35a203920fc6
prerequisite-patch-id: b8f9037e98fabe53d3af1a8dc4a645bf426d4c30
prerequisite-patch-id: 3146d134618e7ab0ba40ccf34a8c091c5d34e261
prerequisite-patch-id: e0a045470e49c1d2a47dd43a7219d3244fce6a49
prerequisite-patch-id: 876766b9d75e2a383ba96696194cd29022fd21b1
prerequisite-patch-id: 0e5f52d34a92fd6f2d5c7f7937cbac406cdba5ca
prerequisite-patch-id: cbe73e71941327c7d5e9ede18b034da2e57bccd2
prerequisite-patch-id: 2084c6728c978bc6a7c941fc5c81ae0aef020630
prerequisite-patch-id: d37301b6ee1e426a956adbb524ffa3a21c6ab3da
prerequisite-patch-id: fa93754fff6fcdae87bfed33ce8dd938e4d0cd37
prerequisite-patch-id: e06eadfb7d62823832c851e715dec54834f0e6ef
prerequisite-patch-id: 6ce71cfbc4711e8e6156e49ff222bc973d61d90e
prerequisite-patch-id: 765bfb42f8eaee869ccdc6abb8524f746f92a25f
prerequisite-patch-id: 8fbf5cfe6cc532d5257b2a7317947cd330ab6b1e
prerequisite-patch-id: fffbaeb0a21813057e38bf522bb494142ddd8b31
prerequisite-patch-id: 29d8a4d847b3f51e9ac11f60fd9abf65729966f8
prerequisite-patch-id: effa379aef07c069f790261357912fe897f13666
prerequisite-patch-id: 353a6b86d029c5cb3595957d6da954ff8e52b6fd
prerequisite-patch-id: b79d6327a1785179639dfb6581cc39bca514d7f1
prerequisite-patch-id: d11a218ebe3ca3307df98d3b70ea9c45018f292a
prerequisite-patch-id: 5ac3c829b0aed3e8aed61027065cfd09bba9a51f
prerequisite-patch-id: 2cdff38a1410f827400327622f4f3293afe02d39
prerequisite-patch-id: b537b3e0e655c3e65ce282d5fce8e284a66ef58d
prerequisite-patch-id: d43f9a516f0cd9a87852dee50307da48ef368348
prerequisite-patch-id: c5461f69fe4b088eee864c4acd7a42217d39ce5d
prerequisite-patch-id: 483e4dcde2fd73e4fe20658ae91ef85cd06bad2f
prerequisite-patch-id: c7f2f908744d941f2013c98f03a03c0246017577
prerequisite-patch-id: 0594b138076ebca0f8b48851f2ac4ee4049b8818
prerequisite-patch-id: e4ff1abee02721a2e5bbca2ace2c3fd8f9a629e9
prerequisite-patch-id: 2c6e2519cdfebb76a3d0bf0a0cd2a2ea5fe870ca
prerequisite-patch-id: 8b9c5cb45d0198cf9256957e280b7126d34c1f45
prerequisite-patch-id: cd6d19ba950e546bb4d8b9cf0a68f716f521b64b
prerequisite-patch-id: 8e2b664ac007941389d32ee88765656a4bb617eb
prerequisite-patch-id: 284f66b9ff740f87e3ad6a6827eb91b36f22ee6d
prerequisite-patch-id: be7d0ee535032b5f3668cfe69c3d77678c606149
prerequisite-patch-id: a1825339f4c4c061d36eba9fc4be23740b51b7c5
prerequisite-patch-id: 06cc4118d31968433e1f85b044c4a7e26cd69d3d
prerequisite-patch-id: efcdc3a29ca101accaa04a07c63dbd20d2fadbff
prerequisite-patch-id: 84cf32aa322156c703ad3857fefa1594bbcfd81d
prerequisite-patch-id: 2079f118308171a0f867ea86da790e8c915a6d02
prerequisite-patch-id: eda3b01a0262a1a53d84725a75f7c8fdbf018072
prerequisite-patch-id: eebcd1c3a373e5abd86aef70175e832b8ea48500
prerequisite-patch-id: cfa0b6d218cb742b5cd1dd95ac61187ad430c229
prerequisite-patch-id: 8b6bba2a3450495f6a09d4f6446599a03893f3a2
prerequisite-patch-id: fe2b50fff6bb39600d0456df23474b1c50e360e5
prerequisite-patch-id: e3af097c3c725a940f2a27c2ac027010ac65a9b7
prerequisite-patch-id: f1c4fdd3a84993c3a7b8bf796068b59daff53818
prerequisite-patch-id: f8bb119d26d88f0757d10173563b14a23e66d0b9
prerequisite-patch-id: 32796f891cb8e2012cf734b6d7cd94a88f2293f3
prerequisite-patch-id: a0df0a9b04a5d0f252ea54a39969926af2e7ed9a
prerequisite-patch-id: a7d56fb9c4b0ce829c13f826520b87a55f9be295
prerequisite-patch-id: 12836b2a35c4cd551dd3af6578fde4e7119ea443
prerequisite-patch-id: 6f29316cb5b085a4d04063df64743ea8e333374b
prerequisite-patch-id: 636b27aad27b36fa64257e9496ab0104ad59b6eb
prerequisite-patch-id: a38e4989bc1042688c4b63184dffe33ce322eae4
prerequisite-patch-id: 64735ae9913c3a4c13fbb20a7ffe2defc2a2a83b
prerequisite-patch-id: 95a760abab906df016bed3f902b7e132a5622a18
prerequisite-patch-id: d122b3e22dd2e0684db4b727d851d04206c8394e
prerequisite-patch-id: 192a6382bccaa3d91f07a79da43b3ea6ff80e402
prerequisite-patch-id: 8c4f3a6e487548720fc1c36e3b67d869043970c1
prerequisite-patch-id: 7c4380cc52f8541a6e787a53da8d1bd51aff9961
prerequisite-patch-id: 3637a1078531745ca31b78ff19d9036365d97e44
prerequisite-patch-id: 6f7d037dade4d0f21014984d798f6341dcd2358b
prerequisite-patch-id: 01f1b46c8a709308e7d53e70ad220712b7dcb5f2
prerequisite-patch-id: 883b473fa39a043f7222c1fd6ad5132fa4b80e6c
prerequisite-patch-id: 3268e4d57017e38ddff42d16a2e1be7c112c8ceb
prerequisite-patch-id: 7ac4059bf34412de9016fd9bd94b2fc08118f22e
prerequisite-patch-id: c230ee1c98b8842a3a6d31cb5a76e15bea915c15
prerequisite-patch-id: 30f170206d7446f77b7d75522f364cb3c3a45bbe
prerequisite-patch-id: 572238245ae722fc2e324d6d391439f1cd7d4afa
prerequisite-patch-id: 2707bf58107c8bfee589f46bafb1b868bacb90fb
prerequisite-patch-id: c9beeca324e8bd984cd61d3a3c606854d6168d69
prerequisite-patch-id: 983dc1b200d748bb3416d7b7a81a59086ccc3984
prerequisite-patch-id: 8b7408ca5c667854e37342a2e2680eb43735887f
prerequisite-patch-id: b7b521cd42011d1631f6612dbf35e0f160bd0f02
prerequisite-patch-id: 4740b95e57df759c7a23fbac770ecb8410fb912d
prerequisite-patch-id: 63fa6c30408a0aafe0a43d5d8e487d78b9dda89b
prerequisite-patch-id: ea83ca31d98748db013eb292bd71aaa5cfc736c2
prerequisite-patch-id: 80281570d9be74471565e79bc2b0b93fdf29b672
prerequisite-patch-id: 6c790f45688043e020e438436c7c14e276fe1443
prerequisite-patch-id: 18041719de9481b6dcde0e670a8a38fb47934146
prerequisite-patch-id: 53a48c64d56aa28f143e1304b2242877ae16d7be
prerequisite-patch-id: 62a1d1d5b13d8da7c94ad4b23a58162a5e2d92aa
prerequisite-patch-id: 2c2b6d2373669a575852f2a99e7c97e4a660a88b
prerequisite-patch-id: e9ae2aeb6fc391d840d902d0ab58ecdbcb820aad
prerequisite-patch-id: bea87ad5c9ddd7bf3f3bd1b505249e491f3273c9
prerequisite-patch-id: 0d312791e970833b2d488bd3f0159339bd58d5bb
prerequisite-patch-id: 648d4f9daacdbb405404b9a52f75e17c99959a2c
prerequisite-patch-id: 4d1d1a62f504ce842a7daf4e4458425276a5b093
prerequisite-patch-id: 85bea0e329abfc46faa33aabaf3806b425eba7f3
prerequisite-patch-id: 63f6b9c80cc911f19c9b0584f27538a3ca9d4001
prerequisite-patch-id: 7f04c14f63aa50e011361fba1c2c0b179ae89926
prerequisite-patch-id: 619d191d7e7718d0fc5a6d354689e3f310d64383
prerequisite-patch-id: 325562f375e21d8988c73f5096dd719c2ecda2c7
prerequisite-patch-id: 22f3ed17298f6e6f0c14a9faa363ab8df9401e60
prerequisite-patch-id: d67f92a7e3b612fd78c1c83f35b527add683beb8
prerequisite-patch-id: 0c040b72c513e969a6f61edc2057e1abb47a3f43
prerequisite-patch-id: 2602a564a4b8fb30a0145ad876395515db731db5
prerequisite-patch-id: 2b5703d9ac3ceea4d636853c813ff923c98c6202
prerequisite-patch-id: 86a2055b71f842342859c47a9a209415c9b09089
prerequisite-patch-id: bb6ed87141f4644c1033d7335fc0e9ba7efa788d
prerequisite-patch-id: 986694be3716eec824eb3c90ff92952d47d4315e
prerequisite-patch-id: 47b08a71c6d77bb2fb3952a1af627337da46c54c
prerequisite-patch-id: bf8891e49e7bbf498b8798adf158df96cf2ebf77
prerequisite-patch-id: 6e442be0319ad6c4ac79de559d8f9148d68af382
prerequisite-patch-id: e8ab6c424bc2d040ca07ccd501091350307f88d2
prerequisite-patch-id: d818403fbd427b4623b9723341d1978c487b6937
prerequisite-patch-id: 628c5a386b73c4efe71dd8113d4e83c4ee99552b
prerequisite-patch-id: 1ac395bb2e3903fade69caf3cd2ad66e9a685d15
prerequisite-patch-id: e3885688316e1d6071239d3823b01ddcad1844d9
prerequisite-patch-id: ce49633294b4c8ca6fa1b1da0598bb4552ea033c
prerequisite-patch-id: e0b34570bad66275336678803a1a590a2bd32696
prerequisite-patch-id: c402c9fc9d70e6790f3284a04986c171e7ebd969
prerequisite-patch-id: ace8a9c9db11025bc588fcc5a59b2d21963aa9da
prerequisite-patch-id: 6577196b66dd29305f316c6dd02b86bf33810b03
prerequisite-patch-id: f8a6cd179b73cd21533daa98d45957ca937a507a
prerequisite-patch-id: 9e07e1e5d9bc9a2195f0dc58696777939e6ed69f
prerequisite-patch-id: a3628a8b2edc024958f241a29a92c0588933702a
prerequisite-patch-id: d48c9dede9b6f9784b20605f62d9531c3d971f93
prerequisite-patch-id: de5f2c4a44ab2d3f898349db687614286bfffa7f
prerequisite-patch-id: d3cbbd51fcb4f4f8aaac9bed3c458cf5d8b022c5
prerequisite-patch-id: 74f7e6fb0707e3e5731f5d973ce06ae17c7b21f3
prerequisite-patch-id: a9c7853850971165e1310cd92bfdb2eec3205117
prerequisite-patch-id: 8aa179f7b2e5c013172ee0f8da95241adc50d351
prerequisite-patch-id: 902aa81e545f70a4d3eab8b3aa280273f4654065
prerequisite-patch-id: 29557a772d2c30af1673716dc2c13ae188a784ee
prerequisite-patch-id: acd909a2ee2624597d40b8cb422c3f9c001f6b60
prerequisite-patch-id: 01ec98820e7db115bead39fb3a1c3837645d36b9
prerequisite-patch-id: 5fc388311016e26ebecefd4142b9ca89436e5512
prerequisite-patch-id: e4357bc1d7d0240fabf9513cd5fea57999b69479
prerequisite-patch-id: f7e65a1bff1f561e26752f4c0f17c55702baa310
prerequisite-patch-id: ed30ae46d50e8f906a84ca0c5b7488c904814f5b
prerequisite-patch-id: 291b66a40bc69ef88224a484ff49bd46c75d7dd2
prerequisite-patch-id: be6c4f862c4eeac3e92b150598c1b114e81da43d
prerequisite-patch-id: 55b3e43eaf882f4e466096a31182433d4b3cd94b
prerequisite-patch-id: 3566e8a1f298f5feb878ac68b26b9822b41a1a89
prerequisite-patch-id: f92c80a987c8ed66df0edf9f5aa566af4b2962e3
prerequisite-patch-id: 3e245507aacd5c79bfb309c1c551df3d5d6617a5
prerequisite-patch-id: 21cba613fdce456f845033af9745e871b6a48938
prerequisite-patch-id: a00de59f7c735d4593a791b969c5f08a47634be5
prerequisite-patch-id: 101b5bc377a0dce612b7f8656afd16ab6c5b3cef
prerequisite-patch-id: 3e1b32a1a2dc6df1892e63b8fe502fdf7e28e439
prerequisite-patch-id: 509c58c079dca695fa54bf9257f95102b3ebeac8
prerequisite-patch-id: c107c1fd0e7d2e78d7ea1d58361f1b4de1a032ca
prerequisite-patch-id: d77f90914d8748ab2ec36082b8412d4ebc1dcf53
prerequisite-patch-id: a32802598208de685d76f2df127dfbfa55945de1
prerequisite-patch-id: 20bfed2d4f255213c1f42c0ed32e4efc0da2b328
prerequisite-patch-id: a4377d84a909785cd93c00e138adbfd3fa94fc82
prerequisite-patch-id: fbc0e4f7dfe136d85b2c4ff3675a6d3dac303c22
prerequisite-patch-id: 1bdec01df9d06ef60968ecaaf83490b2ca1f9aec
prerequisite-patch-id: c1ecd39d746a60d923f6783cb0ee0be5653c7584
prerequisite-patch-id: 51f5bfe1e3512971864a684f8c27ffe24af63576
prerequisite-patch-id: 22544cb1088d02f7ddf389f3e9c9f5fc53ee765d
prerequisite-patch-id: 257c83615a2ea293ce814dd81637b698b2978eeb
prerequisite-patch-id: dd98a0e2d23e65f9fddbfd41cc58f62071366482
prerequisite-patch-id: 732628a32a667bdc4c43aadaf79f882e11a203cb
prerequisite-patch-id: 4f94da71920f3ef6f3df3d16d526bf179c8da467
prerequisite-patch-id: 3feab955d207448d61962cac418577ee16c9ef9d
prerequisite-patch-id: d03a0478a0cfb5c0459985566118a32225e6d856
prerequisite-patch-id: f8899d5c36554a3f551aad8e452c2d331f031cd8
prerequisite-patch-id: b2e5c24e8563b91d1c9b52c21e782e543f4e553b
prerequisite-patch-id: 4c2665d2c01a0b982cc3e6baa2c1733afd20a870
prerequisite-patch-id: 97db0c5ecacd41faa4beaf2b17b9f7a43d6a1c1d
prerequisite-patch-id: 74102b9ae89faab80b42229aa6cf080b73341c20
prerequisite-patch-id: 9be5e927848387f50d81f5604a57090e6077c158
prerequisite-patch-id: 3cbd3874faca8c9ab7e6c5c2a1545883efd1afa6
prerequisite-patch-id: a35b5ac12cf6eb7737716f4b035cc5f47f7e531d
prerequisite-patch-id: 1bf1b4abcc3f950d6d42bd93a4f970123cc8020b
prerequisite-patch-id: d6af42c821a57b642f62dff617bcc1127f321b78
prerequisite-patch-id: cef02a09ced689c3f1ca4531372c2a3c6c8e620d
prerequisite-patch-id: 484f431a72a0c205ba02e715b630ac856517c914
prerequisite-patch-id: 4f12f3232a3d566c0626eb857d2abc2e40f6ad3b
prerequisite-patch-id: a3586a90f44843b4dbefa8f8372c6fe83010b157
prerequisite-patch-id: d76da7eefa99d562ae7655a63e3ae1a62ce7b0a4
prerequisite-patch-id: 1a89c07341f663812ea6b4e3fb7fda568cb4266f
prerequisite-patch-id: 0533a2005658b3573463e12b38b83a10cb2a8f7d
prerequisite-patch-id: d045f9c9c7b760c7d39971d090e43cc34c630d82
prerequisite-patch-id: f908a2d645a5cfe42901a9d3b5af0d86f098de31
prerequisite-patch-id: a3142600f59ad0bd821390ad3bb618138e85fd5f
prerequisite-patch-id: 54047af7a588f4b8cc9099c53d99d1cddb48eda1
prerequisite-patch-id: 6e14dca5e345d1ce3301a285a8c21eb7b30a52ea
prerequisite-patch-id: 90eeb7a4167b3cfbc84788e0045fc6dfa6002e6e
prerequisite-patch-id: 20538041ea440598c44bc93ac4031123a8fa1eaf
prerequisite-patch-id: 8f5e0268cee6bb09d451ec5e79829811b519ba55
prerequisite-patch-id: af24e2aa712e0da72c83d23bcb29cfa14279f499
prerequisite-patch-id: f18e257b03a192ddb87c2db1538d7ff2fffcd019
prerequisite-patch-id: fcb3bf8e9d064d9f8d60384a42667b98f2b5352b
prerequisite-patch-id: 12e48c72fa8f79a428426db6650a1ee74428a8ac
prerequisite-patch-id: 0ce0d142e76a74b556f08c9784614960d7ca2c7a
prerequisite-patch-id: eb094216b11316fedcfdb9c4e2d913fe9bafcf96
prerequisite-patch-id: 1d8dd0210ad21905dd1211928d411a2e85536b07
prerequisite-patch-id: a662561009f7623305c9829060437fd8426797f2
prerequisite-patch-id: c470194823f82c5ab21e726bb8576100db14a307
prerequisite-patch-id: 91dccb672a8128d61499828eccdb493300d7c4ea
prerequisite-patch-id: e9f323aa01b38a30030dfc5309e3ba82598045e0
prerequisite-patch-id: 74770e15f409988c8ac61ebcd4cdeabb36d20230
prerequisite-patch-id: cfdd4c1224cc2034c74bd274ad5eab68f2f3494a
prerequisite-patch-id: b7fb6694825cfdbe06c35c88dfc846bff3e89447
prerequisite-patch-id: c40cf1f798f019a995e68f9948152f0a7d742114
prerequisite-patch-id: 5953c505fc6146637149f765ae1c9bfa25d92f72
prerequisite-patch-id: 02b147160fd099c3ff6c5a9ed06b2b9cad6ecc20
prerequisite-patch-id: b9dc616db5bec917356afec776db5427488d54ee
prerequisite-patch-id: 94cf53ec71503faf1c3757c30f744f0f79e64394
prerequisite-patch-id: 299215ed5af78a515bd887a1cb1ed3f75e92a455
prerequisite-patch-id: 879f9f976f85843bfee73f512fd1faec1293598c
prerequisite-patch-id: c55603fa8127aa78ec3b566e1a8cf4a007aaf354
prerequisite-patch-id: bc805518b8f8c62e9314406645f20691e3f0608e
prerequisite-patch-id: 04411d10601bda0195324738b5d615be84bb4663
prerequisite-patch-id: f625709036dccf0748525b2ef3c39d8abc72b923
prerequisite-patch-id: 9688ad13e09132aac36723b44dcb3b3e02397c52
prerequisite-patch-id: 6094dba1c2c27e872879dd007c1b64b4a34f607e
prerequisite-patch-id: a5cda78b0761b1df9c7d7f49c2cb25c932cf2e9e
prerequisite-patch-id: 0a56ff479947dcc75a0f97bbbfaeaf5f4f1fd289
prerequisite-patch-id: 46e3902621b83af797b5699b35c4419963de98d9
prerequisite-patch-id: 04316dce352d637b8c246dd313c6f08ac1fe11f4
prerequisite-patch-id: fac85c182391d105014207e15a678c1aa724cee2
prerequisite-patch-id: c87f8502c4bb487f970c6598f31071837958d272
prerequisite-patch-id: 7b4cfa99e3ef34d282a31d67f127dba19ef557f6
prerequisite-patch-id: 7159354471f1e17ee6e920cb3dac8e6649ef8846
prerequisite-patch-id: ec13cc10be14ad928e3618e572f1c3cc6b118ee7
prerequisite-patch-id: d19bcc10e81adf8af9660aec6552955355fd3939
prerequisite-patch-id: 93e862a1b3a8f0bd45f726edc7e3286d314f0b1e
prerequisite-patch-id: 15e8f40beebdd32a09b20d05873281b32bdacf0c
prerequisite-patch-id: 8af6738c2531587244a099c1f9ac3f47388e1af5
prerequisite-patch-id: de7371c3f91ba2225cb89abb2a8c53fd1f341fe3
prerequisite-patch-id: d1c08c269db3a3179cd7b92db37f4b1617677a0f
prerequisite-patch-id: ded763abaa96c9c5c56a7e6c4275e9777eb4bb0f
prerequisite-patch-id: 7a5de3b8edbb4cc915768080bd25705225454a9b
prerequisite-patch-id: 3e2170029e314759541cb18b9911cb1f35d36fce
prerequisite-patch-id: 2b4bfb92a2b38df9dd09ce6bf4ca955f45c32188
prerequisite-patch-id: 2e904136d3f1ebaa5b7d48513d570ba2808a0932
prerequisite-patch-id: ffe5b23260f8ab2fa5e05e3e09cf7964328e85a9
prerequisite-patch-id: 19378bab4205f1d860a7844303b0f15e07400b5d
prerequisite-patch-id: c2b3e3f1ac6497f0b6cc74ff0d651c9a2bad9b34
prerequisite-patch-id: c90027987d943b6c59ce2750bd3f184c7d5c8185
prerequisite-patch-id: b770c7ec1f7bedef2c1d73d2c678c49c64a7aeee
prerequisite-patch-id: 8daf565c297852369b758116d4dba029e5ac3a52
prerequisite-patch-id: 8c339b0add5d57790d4dccbc8fd77dfc21f57d1e
prerequisite-patch-id: 1ff73f7bae91c98ac7b7d0f9f98a1f370d1680ec
prerequisite-patch-id: dadf3841aad46b07421bc9777e68e66029c4876d
prerequisite-patch-id: 84d3024e36e5ae65ad760dc63162b69b4c32a401
prerequisite-patch-id: ccc414960ca4a8f70213ae221096ba84523d5fb9
prerequisite-patch-id: 8756f492878fb23f3b386499261c699febd0f2d8
prerequisite-patch-id: f161383494740947fdfe7f017397b3f97a3207f4
prerequisite-patch-id: a7056951429c16eed376f1c1eb7054032115ef9e
prerequisite-patch-id: 37c994fd42ff102640c65b8244c042a5155c5761
prerequisite-patch-id: 5ab420dc6ec07bd4be62b98d963aedf2cf0fbb2d
prerequisite-patch-id: e9bc6195f5d05d19881194dce9d34cae8aa95bb3
prerequisite-patch-id: 9ea2ebec5d021b5fa082a70ad23a86890a66abf9
prerequisite-patch-id: 5b4c3a89194c414736cc40272e2e6a0f9f435411
prerequisite-patch-id: 8dc9b3bb62014d3d743c728604f387d5032d26be
prerequisite-patch-id: 0ca5aedfe43a8033e3b580d3c87bd1a709c51ab8
prerequisite-patch-id: 3ed6bd5d285246540719f943190a91d88dea43ad
prerequisite-patch-id: 589f678214f7d3829b9c7c8c17de16d19fe3e618
prerequisite-patch-id: 145526d8b67ccc9e6850867ec79410e59e902694
prerequisite-patch-id: ae1a18e8bf6e2d1208b91d722debe71c7e3480d8
prerequisite-patch-id: f7684c465eef3391344b27397000ff1b9d9b7f27
prerequisite-patch-id: 3f15198ea83724195d891e8c8975499eff6a1db5
prerequisite-patch-id: 4f5d98a816ea35ad87bf30f890a3807d285e1a8b
prerequisite-patch-id: 2cd9dc0811e5613e14684c09f0e682ce5dec1d85
prerequisite-patch-id: 092028c8734d6ce55e3d8643f3d2166f58228864
prerequisite-patch-id: 2fe993b480df54e681c9752b021230aef35c583f
prerequisite-patch-id: a25d3aa7dbf953cee7a3651e6a8f291bca74f359
prerequisite-patch-id: 64458792b1b192e799b9d9f519b89b65ddb8e5c5
prerequisite-patch-id: d3595d91ed82610d9188a1be15c17e9dff3b998a
prerequisite-patch-id: 0cea5038c8b57ee9471dd25145dcddf4f7888962
prerequisite-patch-id: 0a4e76f6fb643d418d43c7795a11154b15c1fa23
prerequisite-patch-id: 7b4eb3fb690bb9757de4ca22f9509e246d621cd5
prerequisite-patch-id: 7386a9281a73f0e0687726341d3954c98033bf7a
prerequisite-patch-id: c8444fb06db687a7501f9ce9345e665b00fd133f
prerequisite-patch-id: 3e611415873ccc841e24004f68e5c6e282b9412e
prerequisite-patch-id: 4a00f70b775d979167570eb161c21fe0461c9166
prerequisite-patch-id: 061bd08f9b5702009dc8a692a123675bde15793a
prerequisite-patch-id: dccfc82218ccaa4fad357cf5cebd1c89372dff34
prerequisite-patch-id: a38f1f10635f3b2c683e7d3589a7a3a4e76068e2
prerequisite-patch-id: 2aefd777b3120b263e82ad9f078d34646e69c420
prerequisite-patch-id: 7af7b7dcfea2305837e20e1447fd6913474f11b8
prerequisite-patch-id: 5b3fcb913ab82da2f34753cf435a01f029235cec
prerequisite-patch-id: fe23792dce94f73e58672b48e7d648a561ae696b
prerequisite-patch-id: b36ebaca40e89e7311283295eacdab168a33f9fc
prerequisite-patch-id: 5949cc30210a2cd533e2fe3d5271167f87552de5
prerequisite-patch-id: ffc7155d5c142c37aaa3e8ab7ea7169a3e495099
prerequisite-patch-id: 256dd6bc11b1a54433459b6685b45af067a98f43
prerequisite-patch-id: 6620c2bf909451dbca060a0bbd1b0b00874ef7c3
prerequisite-patch-id: 6180283915904b42ac281af10fc885c0c9c76adc
prerequisite-patch-id: daf105aa715ea99b4cec9adb41c7504d70b88d8a
prerequisite-patch-id: eee74983072be9f833678af7d130966537664443
prerequisite-patch-id: a7160ae8e97c5ee7aa3d97cd07ae1cb2b4e20cd4
prerequisite-patch-id: 7a1faeb151663039718b566184ce3ddc30665162
prerequisite-patch-id: e61ec58bd9d204a7672a54b5f59246ab471db929
prerequisite-patch-id: 9bf158d7dbab321b5f66fc337db6c16b43ca8965
prerequisite-patch-id: 23269123477dabc909023a908eaebc27e33f70a0
prerequisite-patch-id: f995967e0a6bcd64d0031c348a7ffe426f37c04b
prerequisite-patch-id: 8e9f20e196a2794ae337e22294c7a83556b7ba60
prerequisite-patch-id: 5d475629446b445f8ebfdf0bdee77d20e58ba5d6
prerequisite-patch-id: 7c823f926df87299ae41fca2feb0cab7303dc459
prerequisite-patch-id: d5d085ba4b0dccd71426283e2963b83aa8ddd889
prerequisite-patch-id: 4ec9e858f3a0d64c7049670a01927fbe6cf10fb3
prerequisite-patch-id: 2285acb7895ea1bd60e1b53d734fc07da35c184f
prerequisite-patch-id: 3d4e74e45801099943fe9e688214f3b8a60980f8
prerequisite-patch-id: 6b49ea2296bb191a8cc940c93daf31b5d472fb2d
prerequisite-patch-id: c5233d71f445624d104f700f12c4e721797e1d9d
prerequisite-patch-id: 43ac887f08ac4df7b127bd0d3acdb55ec08bf9ae
prerequisite-patch-id: 3abd225254fa426dff3abf5baf8c62d392d9ed81
prerequisite-patch-id: 27f443352dadf303b2443c5f2632610728de6165
prerequisite-patch-id: f38fed9ef190059f86979f41da6a131608e9c303
prerequisite-patch-id: d8a7d2850d5cf5678fdce707555c22358974f643
prerequisite-patch-id: cf2df0e07b95e2cbec2d18ba6c1a0ac473c76d91
prerequisite-patch-id: 0fcc9abb4d245634538f7385703d4af996fa951c
prerequisite-patch-id: 7e42b1ae500ed53779d2129eced553ce28c2fbc6
prerequisite-patch-id: 6e1c101a2a08cf900a453231b8259216efc625aa
prerequisite-patch-id: 365eb7b9a9c8f2da80f2e8ce8baace8690ba4ad7
prerequisite-patch-id: 528142feb865d728566ab1697acab67f0cd46ac7
prerequisite-patch-id: 071097e169c72c3892504e010c126a837c9d6294
prerequisite-patch-id: 49ed34c1c281aef200bdb4e950195015ee459d26
prerequisite-patch-id: 6b54fdf5816509b431a557e7a394e6ee4495a5cc
prerequisite-patch-id: 1420469904f265f8bdddb422517dd5e713cee0e4
prerequisite-patch-id: 027f5b7d551d1ca4698f2b0063f29651c919feee
prerequisite-patch-id: a4a53279264f84cc00aa21e5c74625ac52741bb7
prerequisite-patch-id: 36f018e76d0c7923a8259c8a8fb244ad92bd0947
prerequisite-patch-id: d37edf776f79670c0053d9ad71ff4f7029293cff
prerequisite-patch-id: 8de06b65fd34ae59f194d15eec39a73cd9be1fee
prerequisite-patch-id: 2bca096d5cf1564f13f981efa0c9878bd0666f3c
prerequisite-patch-id: f6ae1e3545eba5c4ae3d57068763a68c3fa0a09e
prerequisite-patch-id: 5ac84de269639d408016ee8a4fbb5b04b87d10dc
prerequisite-patch-id: 4f9e954d51bf098324169b45c4377723ed8aff29
prerequisite-patch-id: 9e5e58bd47d1f35aa49ce7ceda78757320f6ba31
prerequisite-patch-id: 8cab8eccd5c1de7cec9a55bf06429e03639da9c1
prerequisite-patch-id: c784f2158188cc1f994dbf29bb0bc8cba2cb76bb
prerequisite-patch-id: 8c864522e29d602f96253f97ec113ea4bc9f82e3
prerequisite-patch-id: 777bbae287549bb3e9e6b3ad807f32b6c09f9fbb
prerequisite-patch-id: 9dec602593087b787f841d986826c14401eaf494
prerequisite-patch-id: bc940c03f2f415636659acf25720ddda4d73b1ff
prerequisite-patch-id: f71a0da68709f095ab264267d6a5751efbca323b
prerequisite-patch-id: 456ea2965f749c582481f400ccea0f76b0aa3b6f
prerequisite-patch-id: 8a7f8e3d272e0b07fea018ff026142601937c269
prerequisite-patch-id: 342c770b197398ff5fd8a601e8a4b3ca7b413959
prerequisite-patch-id: 23b6d25833a041982757a1d64ffab7714b073682
prerequisite-patch-id: 08cec7d85fb4138f26445f87d60e0a7cae937a91
prerequisite-patch-id: 4c88dbe0746d1581e44885e1a036ac7ce8cfecb6
prerequisite-patch-id: 229ee96b1574c243cbf117a14786586146128fbf
prerequisite-patch-id: aaecab0d557468295a3021eadc5b950f0098ac31
prerequisite-patch-id: 3c70dd9b8587b1434bd6d48c7364be8a94438b04
prerequisite-patch-id: 2adf8bc5bffabc6811432d791fad5a29f34509ff
prerequisite-patch-id: f8d94fb2f075b843f854a165128184f2efd6adb5
prerequisite-patch-id: c1948e6e0310c267da0da8b1878711d160b2e435
prerequisite-patch-id: f43e2895cc83204cc528f121710f95ca2a186ce6
prerequisite-patch-id: 60793bb53de9bf494142cc7599c5729fbef47e45
prerequisite-patch-id: 7edc23530c3235f4c1f8c124329817051bb753c4
prerequisite-patch-id: 84f9ff82134b39c942e5065220940f52180fd66b
prerequisite-patch-id: ad358e4c31a36ad6e4901a53680ff68fc2657f03
prerequisite-patch-id: 2b41debac0e4c60bc3234a232e94591f8b5c909b
prerequisite-patch-id: d0f0e32f456d2e98ed23b85c7c0cbfd78e018890
prerequisite-patch-id: 8f014f277d998f7a058b871d1def3d0ae99d74bc
prerequisite-patch-id: fe0a5898429255a5fc81dc236025ba90dced7c1d
prerequisite-patch-id: 91b21615cee8f3048e3960a4c4d352bc97437a4c
prerequisite-patch-id: 8fbaa402ded833464d2d317b63223abb5311f824
prerequisite-patch-id: acd58232f973a42903bdc43784e987f3aa8a7571
prerequisite-patch-id: 74024d9c97053cd113c9f2e493afba7c1f4fea2e
prerequisite-patch-id: 75e2bc5a17116679261a9017f146d9bb50873b14
prerequisite-patch-id: f1e16568c726d2cd8b686e73c122555d41f46b29
prerequisite-patch-id: d768dfb5184f17c74186a852d22702e911e9b390
prerequisite-patch-id: 705ab214e727227c72dabb59a68daa541550209d
prerequisite-patch-id: 7ebfe7a5ba012826771b589312b3ef056a0c3054
prerequisite-patch-id: a1f0d3a2b51efb06873d7c022b3c13dc71ee8027
prerequisite-patch-id: be95390271b76fa32e7af24d925798b981156dc4
prerequisite-patch-id: 4ce1693fa4302a55f2d72f6d94142422cb416f42
prerequisite-patch-id: 2362435e32decea4b1c18e8a3db5d266882d136c
prerequisite-patch-id: 6422a287e8a781dc469ab1642928f71a2d9c64d0
prerequisite-patch-id: 7795c7f718d99be9cfcc50aa3439e93e3a8897a6
prerequisite-patch-id: 281a26655e3292be28912adcce54d6c835f33771
prerequisite-patch-id: 76350633625ea8ebf6642d0e961fc95bcd395252
prerequisite-patch-id: e1d24b44b42065a4ce6627478ad37e465851e104
prerequisite-patch-id: 0bc53145a1073b4d78ff020e00f8b9af59dc6b16
prerequisite-patch-id: 027d3f74eaa16dfdfed9bd0d59a7812cf8c18af8
prerequisite-patch-id: c97dcbe9dda3dbd7cff20495e9e42e4c7b154be1
prerequisite-patch-id: 63d7b6fac5158a7d2bfe2bab267ae2662abd3976
prerequisite-patch-id: 6f506235689cb5b52719cca4709b5c630463019f
prerequisite-patch-id: 209fffe7f8d5bc12c06ef079b92d5a51d87a4760
prerequisite-patch-id: d88b14e89333f66c1c95d4b4796e2516da0dbc1d
prerequisite-patch-id: 8fa3fddf5c3d61dbbf48479f927ff5805d076db5
prerequisite-patch-id: 0d29d6790b6bafcdfc7e6562e3103d18633ff20c
prerequisite-patch-id: 7607499c7743b4f51becaed9346af7bfb565840f
prerequisite-patch-id: a465be9fded8db8a75c65fe836309bfe21713329
prerequisite-patch-id: 3d93d01c89c7af2d831e1314f17a677a027908d0
prerequisite-patch-id: 4c17c39017ede021e6bb12be517cc7d58a5de188
prerequisite-patch-id: 06097d3ef33f31854bfa082fb6eb702be2fbfd3a
prerequisite-patch-id: 5263bb04d2c542aefa400923c95389fe0d4bf915
prerequisite-patch-id: 2ae098b6da3d1f63b13b21b6572cdf3e81ef924f
prerequisite-patch-id: df5577a13db780e938d0aaa1b5e9897bbf3cc6dc
prerequisite-patch-id: 2f031bfd9f6db91a237be996cf563b1a79540bda
prerequisite-patch-id: e2900107249d0f1602a89abebafde22fd4129afe
prerequisite-patch-id: 427b66fa5ace402a2304b90b4e2fbe4b32b738cc
prerequisite-patch-id: 19eb53c51c834cd2190d6050fb29c95e1695c7d0
prerequisite-patch-id: e3c489a5b3badc2df780933cebffa4a19c2684ea
prerequisite-patch-id: 3c33f641c2cb131fcfecc0958a8fb7f5505c5a99
prerequisite-patch-id: 3d009a7765b1853fbefffa07efe9f2b1459d096f
prerequisite-patch-id: d2b970d8e7c931526432d43f422d7ea119b7f0e4
prerequisite-patch-id: 520fdbdce08db94d3ccd5dde1a6197f25c55b798
prerequisite-patch-id: 1432717911dac32b702e78ef342054e2c1eadd55
prerequisite-patch-id: b4bbaff724447deb6f346447fd47eb6d505de2dd
prerequisite-patch-id: c9abcb49eee93fe01e4b27cb0341f61966fef292
prerequisite-patch-id: f72614047ed0b922ac8dde569544785a4624e3d4
prerequisite-patch-id: 3f839e93b5b8934edce6af77b29494fdca8955a4
prerequisite-patch-id: 596c2a947dd1bd947a406da7dff12a6ec13aeeed
prerequisite-patch-id: d58d988d6ad5c520513ae89e5d249b9566c89234
prerequisite-patch-id: d43daa271aad64d2bf9ae85df5279431b0963a22
prerequisite-patch-id: 32c59f28517b44b6ea0fc83b2d9f4af1a66bb669
prerequisite-patch-id: 205ff6200cfe0fbf5447710dd80940ba47eb4445
prerequisite-patch-id: eca6d0ab73c9078ec82a3a9821ae7f8e29a2635a
prerequisite-patch-id: 7600dcc6bf999fab9607d4c2cba27189ee0564a5
prerequisite-patch-id: 4a6cb0cce2cc24af241f779ad881851088605dc1
prerequisite-patch-id: 04a71ea7635d63c49b42a8e0a944b91660af3db0
prerequisite-patch-id: 4fddd83d752bf7a43e6a11625c09b4bd827cdbd5
prerequisite-patch-id: b78967f514ed500e0817c01000e255cbdb71273e
prerequisite-patch-id: 3d84b50143749a9c4d3c8a38193ddf0a78e7701d
prerequisite-patch-id: e8f40430a2e068c47537bfa54e8933653609d822
prerequisite-patch-id: c708e73d09e916fc8a145ec939653921bc4417a2
prerequisite-patch-id: ec440d05b20f6bf89a85020f3484318438746d31
prerequisite-patch-id: e285aa1cbf2a4e243d14e4cdff950f30a5789c71
prerequisite-patch-id: 2778af856a867977ce3311c150115e7e5a2969af
prerequisite-patch-id: 2ceeeb1d2826c8d9ddc1df5842f3d3755931e906
prerequisite-patch-id: b6c1ce4ac2f6ffbc5d2c7dedde005f2a3e909646
prerequisite-patch-id: cb50e6ab01a3864ce5bcc65580f436cae2cdd76c
prerequisite-patch-id: cfea7aa3c6017fdbfc11f1a08806db122fc5295c
prerequisite-patch-id: c0bc5648259f0b745e0904853bc62f380fab8c05
prerequisite-patch-id: e57d2bf04e59d595bc9f5da243079e0e68bf598a
prerequisite-patch-id: 8774b8a75713d87218fb556cf955f8e5fbc6a3c7
prerequisite-patch-id: 83c8eda5576ddaba715d879155bba2646e0e1920
prerequisite-patch-id: 7983ab7a22793db463263cc1577ff995f9f38f03
prerequisite-patch-id: 71a4c33fd4f7df455483caed45966b3b40c1c71c
prerequisite-patch-id: f228c836107b884053c995e20370273584dd3216
prerequisite-patch-id: 7a3d86bfa6f5d573cb20a6bb287a497a2c30343e
prerequisite-patch-id: f7c9821614f04628c2ed347391b0522c1b195e09
prerequisite-patch-id: 0e2f9afa421887cd55959cffea9b0b0307750782
prerequisite-patch-id: 9f8d035a609f8d6c32c98c655f4a487316c069ad
prerequisite-patch-id: 5b2348bc499c5cd2d527cffb4b9c072d2cd00936
prerequisite-patch-id: c0bec91eb90ef0d33da54af3a448691fae70b841
prerequisite-patch-id: b5d91f1149ba1cc214f6a962e1ed4f95d4786e25
prerequisite-patch-id: 77820380f86729009bc9c2adb2543c60d280b6df
prerequisite-patch-id: 450914fb250c999acb285ff59abf511d68bb85bd
prerequisite-patch-id: 847a8ca23e451cc1f1469c9b55903b0d0bf3a6a9
prerequisite-patch-id: 8d1afd20261e46cbbdac851baafc455e5526d91b
prerequisite-patch-id: 5abafd3e73de29f93605c9a63e90c6c1b8369253
prerequisite-patch-id: 3b2e202fdcba2eb6fc4336474cee154981af1f33
prerequisite-patch-id: a230ad456ad018aaf8e26a3f5a62c9efcab25f95
prerequisite-patch-id: 52f052d37e14c94b58398779c5adca404dfa69ca
prerequisite-patch-id: 2008b7871a57cacc9b2f2a6dd5e0e9d141adc1e3
prerequisite-patch-id: 6d42133839570199760d10ee4f53cb486bf9da1f
prerequisite-patch-id: 329bebec9244fd3db26a3f42e330446aea54330e
prerequisite-patch-id: ceefb9b420823f10df231998ff0cec81ff404539
prerequisite-patch-id: 60acfd91f36236c0494ec4f6360f258c0b7c5684
prerequisite-patch-id: 792e4153c1c6d268f5b1e67a0711ed415ff7e44b
prerequisite-patch-id: cdd032b589e3a97d0136d9b35fa823be3f6321e9
prerequisite-patch-id: bb9bcb09f9621ef0ed6cd07de9e53d8b33aa5781
prerequisite-patch-id: b17842bb654628562abd02e707c2176e05aca06f
prerequisite-patch-id: adba72eed4b88fca5ab095f4da48c04b17cb22fd
prerequisite-patch-id: 7f22145ec135fe4f7d1fe54b9f0c2f451035fbeb
prerequisite-patch-id: bbe7de23a364dd79fdf2bdd47e1b6dedbc043e8a
prerequisite-patch-id: 4cf02d886326663d253423c18835b23fdb6cc2c2
prerequisite-patch-id: 1beb4e85f616e76e27501f1fb196cbdc5b256a3f
prerequisite-patch-id: ce229b728cd7ffda125fa81567a0741bee3c1ec4
prerequisite-patch-id: d62768cf0d8e1aab34b2c658d1bbad274270a099
prerequisite-patch-id: 6ae6a81140360b18efc09b1a4c5546d3549f5d4c
prerequisite-patch-id: 3b66fdde063bd4dda9cb4e9fcebbc82217eaa854
prerequisite-patch-id: f0ecf07be04265cf171d028fda7cb780442b0e36
prerequisite-patch-id: e7867003d05b18e233ebbb977073f25329d784fc
prerequisite-patch-id: c6e1050494ab95bcb5b33ebfa34f7af69da0c1b0
prerequisite-patch-id: 67b1848a27231a88122a2441723f27eebd76cb97
prerequisite-patch-id: 38b6f10b4fb196c4717809ba7f1b3a2fc4c8b07a
prerequisite-patch-id: 597c4dc1569749a930f26061d53cb32f52defd76
prerequisite-patch-id: b2f8111f78edeb6d7b96e0f94f61fd5e655bb9ae
prerequisite-patch-id: 367b3e3946ec215a8be41b719830f3b85710101b
prerequisite-patch-id: 03b0f85d471861565bf20aa212650852dea00ffa
prerequisite-patch-id: dc0911fc241a72fd322495d240e0b828cfbb3ede
prerequisite-patch-id: f8864129c6c9546b19c768ad357edf9055e8034b
prerequisite-patch-id: 4f09ef1bdefbdfa8d5d89639de28b35c31666efb
prerequisite-patch-id: 7df2ba8110f2e56217ad61fc5082ca1291bdc844
prerequisite-patch-id: 9e2538496d48ee88c8bc71a455a8f7cbea90fd27
prerequisite-patch-id: 96a4240916b4b391de25dd169179499214b94157
prerequisite-patch-id: f169df2bc0fe7673df3c05760680a5777a3a7fda
prerequisite-patch-id: 59b16431e1e9786c7301b4fd23d89bd680d4fdcd
prerequisite-patch-id: dc9c3f292e1da0a9fc668aacf4f860613c1ea2e4
prerequisite-patch-id: aff07ad3a153b522f5edb5e36e1d1e2321bf4166
prerequisite-patch-id: c7895392b8e55b91765c9013f7fbb1f3f3bc6c8b
prerequisite-patch-id: c20a7fa90f95d3208bd4f0234cf78b46a78681aa
prerequisite-patch-id: d4b9d9780a66a808a9a74c801ab88b9353447bc0
prerequisite-patch-id: 7dbd76172bc5c4cf7dbd0c472d423050e6181202
prerequisite-patch-id: 3a1061d7edd49bf57dc634a5f1b8b56b1c603576
prerequisite-patch-id: 66f1e5d96cca04839376d42f18e69cd01ba48529
prerequisite-patch-id: 0cc1fb87b280d5db3215b56b7b7a92f2620b0766
prerequisite-patch-id: c5fbd24d91ff1835ad0151bd92e342048e47c6bf
-- 
2.45.2


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 318+ messages in thread

* [PATCH v16b 1/4] contrib/: Add support for Cc: and Link: tags
  2024-10-16 12:09 [PATCH v16b 0/4] c: Add __countof__ operator Alejandro Colomar
  2024-07-28 14:15 ` [RFC v1 0/2] c: Add _Lengthof operator Alejandro Colomar
  2024-10-16 12:10 ` [PATCH v16b 0/4] c: Add __countof__ operator Alejandro Colomar
@ 2024-10-16 12:10 ` Alejandro Colomar
  2024-10-16 12:10 ` [PATCH v16b 2/4] gcc/: Rename array_type_nelts => array_type_nelts_minus_one Alejandro Colomar
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 318+ messages in thread
From: Alejandro Colomar @ 2024-10-16 12:10 UTC (permalink / raw)
  To: gcc-patches, Joseph Myers
  Cc: Alejandro Colomar, Gabriel Ravier, Jakub Jelinek, Kees Cook,
	Qing Zhao, David Brown, Florian Weimer, Andreas Schwab,
	Timm Baeder, Daniel Plakosh, A. Jiang, Eugene Zelenko,
	Aaron Ballman, Paul Koning, Daniel Lundin, Nikolaos Strimpas,
	JeanHeyd Meneide, Fernando Borretti, Jonathan Protzenko,
	Chris Bazley, Ville Voutilainen, Alex Celeste,
	Jakub Łukasiewicz, Douglas McIlroy, Jason Merrill,
	Siddhesh Poyarekar, DJ Delorie, Carlos O'Donell,
	Martin Uecker, Gustavo A. R. Silva, Patrizia Kaye, Ori Bernstein,
	Robert Seacord, James K. Lowden, Marek Polacek, Sam James,
	corentinjabot, Richard Biener

[-- Attachment #1: Type: text/plain, Size: 1258 bytes --]

contrib/ChangeLog:

	* gcc-changelog/git_commit.py (GitCommit):
	Add support for 'Cc: ' and 'Link: ' tags.

Cc: Jason Merrill <jason@redhat.com>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
---
 contrib/gcc-changelog/git_commit.py | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/contrib/gcc-changelog/git_commit.py b/contrib/gcc-changelog/git_commit.py
index 87ecb9e1a17..64fb986b74c 100755
--- a/contrib/gcc-changelog/git_commit.py
+++ b/contrib/gcc-changelog/git_commit.py
@@ -182,7 +182,8 @@ CO_AUTHORED_BY_PREFIX = 'co-authored-by: '
 
 REVIEW_PREFIXES = ('reviewed-by: ', 'reviewed-on: ', 'signed-off-by: ',
                    'acked-by: ', 'tested-by: ', 'reported-by: ',
-                   'suggested-by: ')
+                   'suggested-by: ', 'cc: ')
+LINK_PREFIXES = ('link: ')
 DATE_FORMAT = '%Y-%m-%d'
 
 
@@ -524,6 +525,8 @@ class GitCommit:
                     continue
                 elif lowered_line.startswith(REVIEW_PREFIXES):
                     continue
+                elif lowered_line.startswith(LINK_PREFIXES):
+                    continue
                 else:
                     m = cherry_pick_regex.search(line)
                     if m:
-- 
2.45.2


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 318+ messages in thread

* [PATCH v16b 2/4] gcc/: Rename array_type_nelts => array_type_nelts_minus_one
  2024-10-16 12:09 [PATCH v16b 0/4] c: Add __countof__ operator Alejandro Colomar
                   ` (2 preceding siblings ...)
  2024-10-16 12:10 ` [PATCH v16b 1/4] contrib/: Add support for Cc: and Link: tags Alejandro Colomar
@ 2024-10-16 12:10 ` Alejandro Colomar
  2024-10-16 17:21   ` Joseph Myers
  2024-10-16 12:10 ` [PATCH v16b 3/4] gcc/: Merge definitions of array_type_nelts_top Alejandro Colomar
  2024-10-16 12:10 ` [PATCH v16b 4/4] c: Add __countof__ operator Alejandro Colomar
  5 siblings, 1 reply; 318+ messages in thread
From: Alejandro Colomar @ 2024-10-16 12:10 UTC (permalink / raw)
  To: gcc-patches, Joseph Myers
  Cc: Alejandro Colomar, Gabriel Ravier, Jakub Jelinek, Kees Cook,
	Qing Zhao, David Brown, Florian Weimer, Andreas Schwab,
	Timm Baeder, Daniel Plakosh, A. Jiang, Eugene Zelenko,
	Aaron Ballman, Paul Koning, Daniel Lundin, Nikolaos Strimpas,
	JeanHeyd Meneide, Fernando Borretti, Jonathan Protzenko,
	Chris Bazley, Ville Voutilainen, Alex Celeste,
	Jakub Łukasiewicz, Douglas McIlroy, Jason Merrill,
	Siddhesh Poyarekar, DJ Delorie, Carlos O'Donell,
	Martin Uecker, Gustavo A. R. Silva, Patrizia Kaye, Ori Bernstein,
	Robert Seacord, James K. Lowden, Marek Polacek, Sam James,
	corentinjabot, Richard Biener

[-- Attachment #1: Type: text/plain, Size: 12729 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>

gcc/ChangeLog:

	* tree.cc (array_type_nelts, array_type_nelts_minus_one)
	* tree.h (array_type_nelts, array_type_nelts_minus_one)
	* expr.cc (count_type_elements)
	* config/aarch64/aarch64.cc
	(pure_scalable_type_info::analyze_array)
	* config/i386/i386.cc (ix86_canonical_va_list_type):
	Rename array_type_nelts => array_type_nelts_minus_one
	The old name was misleading.

gcc/c/ChangeLog:

	* c-decl.cc (one_element_array_type_p, get_parm_array_spec)
	* c-fold.cc (c_fold_array_ref):
	Rename array_type_nelts => array_type_nelts_minus_one

gcc/cp/ChangeLog:

	* decl.cc (reshape_init_array)
	* init.cc
	(build_zero_init_1)
	(build_value_init_noctor)
	(build_vec_init)
	(build_delete)
	* lambda.cc (add_capture)
	* tree.cc (array_type_nelts_top):
	Rename array_type_nelts => array_type_nelts_minus_one

gcc/fortran/ChangeLog:

	* trans-array.cc (structure_alloc_comps)
	* trans-openmp.cc
	(gfc_walk_alloc_comps)
	(gfc_omp_clause_linear_ctor):
	Rename array_type_nelts => array_type_nelts_minus_one

gcc/rust/ChangeLog:

	* backend/rust-tree.cc (array_type_nelts_top):
	Rename array_type_nelts => array_type_nelts_minus_one

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>
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 888966cb710..c91edaa8975 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -5367,7 +5367,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]".  */
@@ -6315,15 +6315,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 5770491b30c..c3bd6f3339d 100644
--- a/gcc/config/aarch64/aarch64.cc
+++ b/gcc/config/aarch64/aarch64.cc
@@ -1081,7 +1081,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 a1f0ae7a7e1..5d5022bf1c5 100644
--- a/gcc/config/i386/i386.cc
+++ b/gcc/config/i386/i386.cc
@@ -24629,7 +24629,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 0c5b5c06a12..7281818be8f 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -6956,7 +6956,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 f785015e477..10b83efa850 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.  */
@@ -4526,7 +4526,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;
@@ -5191,7 +5191,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 e17c00217b2..d51b513f0fa 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 0a7a56cc6e2..3cac8ac4df1 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -3085,7 +3085,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 ed64ccea766..5397c6fa380 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 0b8ef0b5e01..160a543bda2 100644
--- a/gcc/fortran/trans-array.cc
+++ b/gcc/fortran/trans-array.cc
@@ -9695,7 +9695,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 d3783f56a69..f4c93148400 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 392c3dc879e..94c6d086bd7 100644
--- a/gcc/tree.cc
+++ b/gcc/tree.cc
@@ -3701,7 +3701,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;
 
@@ -14800,7 +14800,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 d324a3f42a6..c996821c953 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -4929,7 +4929,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] 318+ messages in thread

* [PATCH v16b 3/4] gcc/: Merge definitions of array_type_nelts_top
  2024-10-16 12:09 [PATCH v16b 0/4] c: Add __countof__ operator Alejandro Colomar
                   ` (3 preceding siblings ...)
  2024-10-16 12:10 ` [PATCH v16b 2/4] gcc/: Rename array_type_nelts => array_type_nelts_minus_one Alejandro Colomar
@ 2024-10-16 12:10 ` Alejandro Colomar
  2024-10-18 22:43   ` Joseph Myers
  2024-10-16 12:10 ` [PATCH v16b 4/4] c: Add __countof__ operator Alejandro Colomar
  5 siblings, 1 reply; 318+ messages in thread
From: Alejandro Colomar @ 2024-10-16 12:10 UTC (permalink / raw)
  To: gcc-patches, Joseph Myers
  Cc: Alejandro Colomar, Gabriel Ravier, Jakub Jelinek, Kees Cook,
	Qing Zhao, David Brown, Florian Weimer, Andreas Schwab,
	Timm Baeder, Daniel Plakosh, A. Jiang, Eugene Zelenko,
	Aaron Ballman, Paul Koning, Daniel Lundin, Nikolaos Strimpas,
	JeanHeyd Meneide, Fernando Borretti, Jonathan Protzenko,
	Chris Bazley, Ville Voutilainen, Alex Celeste,
	Jakub Łukasiewicz, Douglas McIlroy, Jason Merrill,
	Siddhesh Poyarekar, DJ Delorie, Carlos O'Donell,
	Martin Uecker, Gustavo A. R. Silva, Patrizia Kaye, Ori Bernstein,
	Robert Seacord, James K. Lowden, Marek Polacek, Sam James,
	corentinjabot, Richard Biener

[-- Attachment #1: Type: text/plain, Size: 4880 bytes --]

There were two identical definitions, and none of them are available
where they are needed for implementing __nelementsof__.  Merge them, and
provide the single definition in gcc/tree.{h,cc}, where it's available
for __nelementsof__, 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 94ee550bd9c..a44100a2bc4 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -8121,7 +8121,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 3cac8ac4df1..c80ee068958 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -3076,19 +3076,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 94c6d086bd7..b40f4d31b2f 100644
--- a/gcc/tree.cc
+++ b/gcc/tree.cc
@@ -3732,6 +3732,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 c996821c953..f4c89f5477c 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -4930,6 +4930,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] 318+ messages in thread

* [PATCH v16b 4/4] c: Add __countof__ operator
  2024-10-16 12:09 [PATCH v16b 0/4] c: Add __countof__ operator Alejandro Colomar
                   ` (4 preceding siblings ...)
  2024-10-16 12:10 ` [PATCH v16b 3/4] gcc/: Merge definitions of array_type_nelts_top Alejandro Colomar
@ 2024-10-16 12:10 ` Alejandro Colomar
  5 siblings, 0 replies; 318+ messages in thread
From: Alejandro Colomar @ 2024-10-16 12:10 UTC (permalink / raw)
  To: gcc-patches, Joseph Myers
  Cc: Alejandro Colomar, Gabriel Ravier, Jakub Jelinek, Kees Cook,
	Qing Zhao, David Brown, Florian Weimer, Andreas Schwab,
	Timm Baeder, Daniel Plakosh, A. Jiang, Eugene Zelenko,
	Aaron Ballman, Paul Koning, Daniel Lundin, Nikolaos Strimpas,
	JeanHeyd Meneide, Fernando Borretti, Jonathan Protzenko,
	Chris Bazley, Ville Voutilainen, Alex Celeste,
	Jakub Łukasiewicz, Douglas McIlroy, Jason Merrill,
	Siddhesh Poyarekar, DJ Delorie, Carlos O'Donell,
	Martin Uecker, Gustavo A. R. Silva, Patrizia Kaye, Ori Bernstein,
	Robert Seacord, James K. Lowden, Marek Polacek, Sam James,
	corentinjabot, Richard Biener

[-- Attachment #1: Type: text/plain, Size: 29820 bytes --]

This operator is similar to sizeof but can only be applied to an array,
and returns its number of elements.

FUTURE DIRECTIONS:

-  We should make it work with array parameters to functions,
   and somehow magically return the number of elements of the array,
   regardless of it being really a pointer.

-  Fix support for [0].

gcc/ChangeLog:

	* doc/extend.texi: Document __countof__ operator.

gcc/c-family/ChangeLog:

	* c-common.h
	* c-common.def
	* c-common.cc (c_countof_type): Add __countof__ operator.

gcc/c/ChangeLog:

	* c-tree.h
	(c_expr_countof_expr, c_expr_countof_type)
	* c-decl.cc
	(start_struct, finish_struct)
	(start_enum, finish_enum)
	* c-parser.cc
	(c_parser_sizeof_expression)
	(c_parser_countof_expression)
	(c_parser_sizeof_or_countof_expression)
	(c_parser_unary_expression)
	* c-typeck.cc
	(build_external_ref)
	(record_maybe_used_decl)
	(pop_maybe_used)
	(is_top_array_vla)
	(c_expr_countof_expr, c_expr_countof_type):
	Add __countof__ operator.

gcc/testsuite/ChangeLog:

	* gcc.dg/countof-compile.c
	* gcc.dg/countof-vla.c
	* gcc.dg/countof.c: Add tests for __countof__ operator.

Link: <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117025>
Link: <https://inbox.sourceware.org/gcc/M8S4oQy--3-2@tutanota.com/T/>
Link: <https://inbox.sourceware.org/gcc-patches/20240728141547.302478-1-alx@kernel.org/T/#t>
Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3313.pdf>
Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3325.pdf>
Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3369.pdf>
Link: <https://github.com/llvm/llvm-project/issues/102836>
Link: <https://stackoverflow.com/questions/37538/#57537491>
Suggested-by: Xavier Del Campo Romero <xavi.dcr@tutanota.com>
Co-authored-by: Martin Uecker <uecker@tugraz.at>
Acked-by: "James K. Lowden" <jklowden@schemamania.org>
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>
Cc: Daniel Plakosh <dplakosh@cert.org>
Cc: "A. Jiang" <de34@live.cn>
Cc: Eugene Zelenko <eugene.zelenko@gmail.com>
Cc: Aaron Ballman <aaron.ballman@intel.com>
Cc: Paul Koning <paulkoning@comcast.net>
Cc: Daniel Lundin <daniel.lundin.mail@gmail.com>
Cc: Nikolaos Strimpas <Strnik86@protonmail.com>
Cc: JeanHeyd Meneide <phdofthehouse@gmail.com>
Cc: Fernando Borretti <fernando@borretti.me>
Cc: Jonathan Protzenko <jonathan.protzenko@ens-lyon.org>
Cc: Chris Bazley <Chris.Bazley@arm.com>
Cc: Ville Voutilainen <ville.voutilainen@gmail.com>
Cc: Alex Celeste <alexg.nvfp@gmail.com>
Cc: Jakub Łukasiewicz <jakublukasiewicz@outlook.com>
Cc: Douglas McIlroy <douglas.mcilroy@dartmouth.edu>
Cc: Jason Merrill <jason@redhat.com>
Cc: "Gustavo A. R. Silva" <gustavoars@kernel.org>
Cc: Patrizia Kaye <patrizia@ethernull.org>
Cc: Ori Bernstein <ori@eigenstate.org>
Cc: Robert Seacord <rcseacord@gmail.com>
Cc: Marek Polacek <mpolacek@gcc.gnu.org>
Cc: Sam James <sam@gentoo.org>
Cc: Richard Biener <richard.guenther@gmail.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                        |  22 +++-
 gcc/c/c-parser.cc                      |  62 +++++++---
 gcc/c/c-tree.h                         |   4 +
 gcc/c/c-typeck.cc                      | 118 ++++++++++++++++++-
 gcc/doc/extend.texi                    |  30 +++++
 gcc/testsuite/gcc.dg/countof-compile.c | 115 +++++++++++++++++++
 gcc/testsuite/gcc.dg/countof-vla.c     |  46 ++++++++
 gcc/testsuite/gcc.dg/countof.c         | 150 +++++++++++++++++++++++++
 11 files changed, 554 insertions(+), 24 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/countof-compile.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-vla.c
 create mode 100644 gcc/testsuite/gcc.dg/countof.c

diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
index 7494a2dac0a..9f48fea6543 100644
--- a/gcc/c-family/c-common.cc
+++ b/gcc/c-family/c-common.cc
@@ -466,6 +466,7 @@ const struct c_common_resword c_common_reswords[] =
   { "__inline",		RID_INLINE,	0 },
   { "__inline__",	RID_INLINE,	0 },
   { "__label__",	RID_LABEL,	0 },
+  { "__countof__",	RID_COUNTOF,	0 },
   { "__null",		RID_NULL,	0 },
   { "__real",		RID_REALPART,	0 },
   { "__real__",		RID_REALPART,	0 },
@@ -4071,6 +4072,31 @@ c_alignof_expr (location_t loc, tree expr)
 
   return fold_convert_loc (loc, size_type_node, t);
 }
+
+/* Implement the countof keyword:
+   Return the number of elements of an array.  */
+
+tree
+c_countof_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 %<__countof__%> to type %qT", type);
+      return error_mark_node;
+    }
+  if (!COMPLETE_TYPE_P (type))
+    {
+      error_at (loc,
+		"invalid application of %<__countof__%> 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 dc49ad09e2f..f2ae784cefe 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 'countof' expression.  */
+DEFTREECODE (COUNTOF_EXPR, "countof_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 1e80939d379..6c6ee08925e 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_COUNTOF,
   RID_VA_ARG,
   RID_EXTENSION, RID_IMAGPART, RID_REALPART, RID_LABEL,    RID_CHOOSE_EXPR,
   RID_TYPES_COMPATIBLE_P,      RID_BUILTIN_COMPLEX,	   RID_BUILTIN_SHUFFLE,
@@ -889,6 +890,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_countof_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 c91edaa8975..eb749efeb29 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -9001,12 +9001,17 @@ 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_countof))
     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"
+		       : "__countof__"))));
 
   if (in_underspecified_init)
     error_at (loc, "%qT defined in underspecified object initializer", ref);
@@ -9970,7 +9975,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_countof)
 	struct_parse_info->struct_types.safe_push (t);
      }
 
@@ -10144,12 +10149,17 @@ 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_countof))
     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"
+		       : "__countof__"))));
 
   if (in_underspecified_init)
     error_at (loc, "%qT defined in underspecified object initializer",
@@ -10343,7 +10353,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_countof)
     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 120f2b289c0..f615d8bfca8 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_countof_expression (parser, RID_SIZEOF)                  \
+)
 
+#define c_parser_countof_expression(parser)                                   \
+(                                                                             \
+  c_parser_sizeof_or_countof_expression (parser, RID_COUNTOF)                 \
+)
+\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
@@ -1695,7 +1705,8 @@ 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_countof_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 *,
@@ -10181,6 +10192,8 @@ c_parser_unary_expression (c_parser *parser)
     case CPP_KEYWORD:
       switch (c_parser_peek_token (parser)->keyword)
 	{
+	case RID_COUNTOF:
+	  return c_parser_countof_expression (parser);
 	case RID_SIZEOF:
 	  return c_parser_sizeof_expression (parser);
 	case RID_ALIGNOF:
@@ -10220,12 +10233,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_countof_expression (c_parser *parser, enum rid rid)
 {
+  const char *op_name = (rid == RID_COUNTOF) ? "__countof__" : "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;
@@ -10234,7 +10248,10 @@ c_parser_sizeof_expression (c_parser *parser)
 
   c_parser_consume_token (parser);
   c_inhibit_evaluation_warnings++;
-  in_sizeof++;
+  if (rid == RID_COUNTOF)
+    in_countof++;
+  else
+    in_sizeof++;
   if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)
       && c_token_starts_compound_literal (c_parser_peek_2nd_token (parser)))
     {
@@ -10253,7 +10270,10 @@ c_parser_sizeof_expression (c_parser *parser)
 	{
 	  struct c_expr ret;
 	  c_inhibit_evaluation_warnings--;
-	  in_sizeof--;
+	  if (rid == RID_COUNTOF)
+	    in_countof--;
+	  else
+	    in_sizeof--;
 	  ret.set_error ();
 	  ret.original_code = ERROR_MARK;
 	  ret.original_type = NULL;
@@ -10265,31 +10285,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_COUNTOF)
+	{
+	  in_countof--;
+	  result = c_expr_countof_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_COUNTOF)
+	in_countof--;
+      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_COUNTOF)
+	result = c_expr_countof_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 bfdcb78bbcc..4a7356a70fc 100644
--- a/gcc/c/c-tree.h
+++ b/gcc/c/c-tree.h
@@ -760,6 +760,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_countof;
 extern int in_typeof;
 extern bool c_in_omp_for;
 extern bool c_omp_array_section_p;
@@ -811,6 +812,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_countof_expr (location_t, struct c_expr);
+extern struct c_expr c_expr_countof_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 108ea5ca3e8..14313e9d649 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 "countof".  */
+int in_countof;
+
 /* The level of nesting inside "typeof".  */
 int in_typeof;
 
@@ -3273,7 +3276,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_countof)
 	C_DECL_USED (ref) = 1;
       else if (DECL_INITIAL (ref) == NULL_TREE
 	       && DECL_EXTERNAL (ref)
@@ -3329,7 +3332,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_countof).  */
   int level;
   /* The next one at this level or above, or NULL.  */
   struct maybe_used_decl *next;
@@ -3347,7 +3350,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_countof;
   t->next = maybe_used_decls;
   maybe_used_decls = t;
 }
@@ -3361,7 +3364,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_countof;
   while (p && p->level > cur_level)
     {
       if (used)
@@ -3471,6 +3474,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 countof applied to EXPR.  */
+
+struct c_expr
+c_expr_countof_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_countof_type (loc, TREE_TYPE (folded_expr));
+      c_last_sizeof_arg = expr.value;
+      c_last_sizeof_loc = loc;
+      ret.original_code = COUNTOF_EXPR;
+      ret.original_type = NULL;
+      ret.m_decimal = 0;
+      if (is_top_array_vla (TREE_TYPE (folded_expr)))
+	{
+	  /* countof 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 countof applied to T, a structure for the type
+   name passed to countof (rather than the type itself).  LOC is the
+   location of the original expression.  */
+
+struct c_expr
+c_expr_countof_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_countof_type (loc, type);
+  c_last_sizeof_arg = type;
+  c_last_sizeof_loc = loc;
+  ret.original_code = COUNTOF_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 countof does not get folded to a constant by
+	 c_fully_fold, because if the number of elements is evaluated
+	 the result is not constant and so
+	 constraints on zero or negative size arrays must not be applied
+	 when this countof 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/doc/extend.texi b/gcc/doc/extend.texi
index 9bb263f9510..290da955cff 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -10555,6 +10555,36 @@ 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 __countof__
+@section Determining the Number of Elements of Arrays
+@cindex __countof__
+@cindex number of elements
+
+The keyword @code{__countof__} determines
+the number of elements of an array operand.
+Its syntax is similar to @code{sizeof}.
+The operand must be
+a parenthesized complete array type name
+or an expression of such a type.
+For example:
+
+@smallexample
+int a[n];
+__countof__ (a);  // returns n
+__countof__ (int [7][3]);  // returns 7
+@end smallexample
+
+The result of this operator is an integer constant expression,
+unless the array has a variable number of elements.
+The operand is only evaluated
+if the array has a variable number of elements.
+For example:
+
+@smallexample
+__countof__ (int [7][n++]);  // integer constant expression
+__countof__ (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/testsuite/gcc.dg/countof-compile.c b/gcc/testsuite/gcc.dg/countof-compile.c
new file mode 100644
index 00000000000..6e2592edbb0
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/countof-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[__countof__(z)];
+
+void
+automatic(void)
+{
+  __countof__ (w);
+}
+
+void
+incomplete (int p[])
+{
+  __countof__ (x);  /* { dg-error "incomplete" } */
+
+  /* We want to support the following one in the future,
+     but for now it should fail.  */
+  __countof__ (p);  /* { dg-error "invalid" } */
+}
+
+void
+fam (void)
+{
+  struct {
+    int x;
+    int fam[];
+  } s;
+
+  __countof__ (s.fam); /* { dg-error "incomplete" } */
+}
+
+void fix_fix (int i, char (*a)[3][5], int (*x)[__countof__ (*a)]);
+void fix_var (int i, char (*a)[3][i], int (*x)[__countof__ (*a)]);
+void fix_uns (int i, char (*a)[3][*], int (*x)[__countof__ (*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;
+
+  __countof__ (x); /* { dg-error "invalid" } */
+  __countof__ (int); /* { dg-error "invalid" } */
+  __countof__ (s); /* { dg-error "invalid" } */
+  __countof__ (struct s); /* { dg-error "invalid" } */
+  __countof__ (&x); /* { dg-error "invalid" } */
+  __countof__ (p); /* { dg-error "invalid" } */
+  __countof__ (int *); /* { dg-error "invalid" } */
+  __countof__ (&s.x); /* { dg-error "invalid" } */
+  __countof__ (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];
+
+  __countof__ (a[f1()]);
+  __countof__ (b[f2()]);
+}
+
+void
+no_parens(void)
+{
+  __countof__ a;
+  __countof__ *a;
+  __countof__ (int [3]) {};
+
+  __countof__ int [3]; /* { dg-error "expected expression before" } */
+}
+
+void
+const_expr(void)
+{
+  int n = 7;
+
+  _Static_assert (__countof__ (int [3][n]) == 3);
+  _Static_assert (__countof__ (int [n][3]) == 7); /* { dg-error "not constant" } */
+  _Static_assert (__countof__ (int [0][3]) == 0);
+  _Static_assert (__countof__ (int [0]) == 0);
+
+  /* FIXME: countof(int [0][n]) should result in a constant expression.  */
+  _Static_assert (__countof__ (int [0][n]) == 0); /* { dg-error "not constant" } */
+}
diff --git a/gcc/testsuite/gcc.dg/countof-vla.c b/gcc/testsuite/gcc.dg/countof-vla.c
new file mode 100644
index 00000000000..5a82aeed782
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/countof-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)[__countof__ (*a)]);
+void fix_var (int i,
+	      char (*a)[3][i], /* dg-warn "variable" */
+	      int (*x)[__countof__ (*a)]);
+void fix_uns (int i,
+	      char (*a)[3][*],
+	      int (*x)[__countof__ (*a)]);
+
+void zro_fix (int i,
+	      char (*a)[0][5],
+	      int (*x)[__countof__ (*a)]);
+void zro_var (int i,
+	      char (*a)[0][i], /* dg-warn "variable" */
+	      int (*x)[__countof__ (*a)]);
+void zro_uns (int i,
+	      char (*a)[0][*],
+	      int (*x)[__countof__ (*a)]);
+
+void var_fix (int i,
+	      char (*a)[i][5], /* dg-warn "variable" */
+	      int (*x)[__countof__ (*a)]); /* dg-warn "variable" */
+void var_var (int i,
+	      char (*a)[i][i], /* dg-warn "variable" */
+	      int (*x)[__countof__ (*a)]); /* dg-warn "variable" */
+void var_uns (int i,
+	      char (*a)[i][*], /* dg-warn "variable" */
+	      int (*x)[__countof__ (*a)]); /* dg-warn "variable" */
+
+void uns_fix (int i,
+	      char (*a)[*][5],
+	      int (*x)[__countof__ (*a)]);
+void uns_var (int i,
+	      char (*a)[*][i], /* dg-warn "variable" */
+	      int (*x)[__countof__ (*a)]);
+void uns_uns (int i,
+	      char (*a)[*][*],
+	      int (*x)[__countof__ (*a)]);
+
+// Can't test due to bug: <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=116284>
+//static int z2[0];
+//static int y2[__countof__(z2)];
diff --git a/gcc/testsuite/gcc.dg/countof.c b/gcc/testsuite/gcc.dg/countof.c
new file mode 100644
index 00000000000..063a207fb6b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/countof.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 (__countof__ (a) == 7);
+  static_assert (__countof__ (long [0]) == 0);
+  static_assert (__countof__ (unsigned [99]) == 99);
+}
+
+void
+automatic(void)
+{
+  int a[] = {1, 2, 3};
+  int z[] = {};
+
+  static_assert (__countof__ (a) == 3);
+  static_assert (__countof__ (z) == 0);
+}
+
+void
+vla (void)
+{
+  unsigned n;
+
+  n = 99;
+  assert (__countof__ (short [n - 10]) == 99 - 10);
+
+  int v[n / 2];
+  assert (__countof__ (v) == 99 / 2);
+
+  n = 0;
+  int z[n];
+  assert (__countof__ (z) == 0);
+}
+
+void
+member (void)
+{
+  struct {
+    int a[8];
+  } s;
+
+  static_assert (__countof__ (s.a) == 8);
+}
+
+void
+vla_eval (void)
+{
+  int i;
+
+  i = 7;
+  assert (__countof__ (struct {int x;}[i++]) == 7);
+  assert (i == 7 + 1);
+
+  int v[i];
+  int (*p)[i];
+  p = &v;
+  assert (__countof__ (*p++) == i);
+  assert (p - 1 == &v);
+}
+
+void
+inner_vla_noeval (void)
+{
+  int i;
+
+  i = 3;
+  static_assert (__countof__ (struct {int x[i++];}[3]) == 3);
+  assert (i == 3);
+}
+
+void
+array_noeval (void)
+{
+  long a[5];
+  long (*p)[__countof__ (a)];
+
+  p = &a;
+  static_assert (__countof__ (*p++) == 5);
+  assert (p == &a);
+}
+
+void
+matrix_zero (void)
+{
+  int i;
+
+  static_assert (__countof__ (int [0][4]) == 0);
+  i = 3;
+  assert (__countof__ (int [0][i]) == 0);
+}
+
+void
+matrix_fixed (void)
+{
+  int i;
+
+  static_assert (__countof__ (int [7][4]) == 7);
+  i = 3;
+  static_assert (__countof__ (int [7][i]) == 7);
+}
+
+void
+matrix_vla (void)
+{
+  int i, j;
+
+  i = 7;
+  assert (__countof__ (int [i++][4]) == 7);
+  assert (i == 7 + 1);
+
+  i = 9;
+  j = 3;
+  assert (__countof__ (int [i++][j]) == 9);
+  assert (i == 9 + 1);
+}
+
+void
+no_parens(void)
+{
+  int n = 3;
+  int a[7];
+  int v[n];
+
+  static_assert (__countof__ a == 7); 
+  assert (__countof__ 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] 318+ messages in thread

* Re: [PATCH v16b 2/4] gcc/: Rename array_type_nelts => array_type_nelts_minus_one
  2024-10-16 12:10 ` [PATCH v16b 2/4] gcc/: Rename array_type_nelts => array_type_nelts_minus_one Alejandro Colomar
@ 2024-10-16 17:21   ` Joseph Myers
  2024-10-16 18:02     ` Alejandro Colomar
  0 siblings, 1 reply; 318+ messages in thread
From: Joseph Myers @ 2024-10-16 17:21 UTC (permalink / raw)
  To: Alejandro Colomar; +Cc: gcc-patches, Jakub Jelinek, Richard Biener

On Wed, 16 Oct 2024, Alejandro Colomar wrote:

> The old name was misleading.
> 
> While at it, also rename some temporary variables that are used with
> this function, for consistency.

This patch is OK and should be committed (assuming it has passed bootstrap 
and regression testing).

-- 
Joseph S. Myers
josmyers@redhat.com


^ permalink raw reply	[flat|nested] 318+ messages in thread

* Re: [PATCH v16b 2/4] gcc/: Rename array_type_nelts => array_type_nelts_minus_one
  2024-10-16 17:21   ` Joseph Myers
@ 2024-10-16 18:02     ` Alejandro Colomar
  2024-10-18  8:25       ` Alejandro Colomar
  0 siblings, 1 reply; 318+ messages in thread
From: Alejandro Colomar @ 2024-10-16 18:02 UTC (permalink / raw)
  To: Joseph Myers; +Cc: gcc-patches, Jakub Jelinek, Richard Biener

[-- Attachment #1: Type: text/plain, Size: 716 bytes --]

Hi Joseph,

On Wed, Oct 16, 2024 at 05:21:39PM GMT, Joseph Myers wrote:
> On Wed, 16 Oct 2024, Alejandro Colomar wrote:
> 
> > The old name was misleading.
> > 
> > While at it, also rename some temporary variables that are used with
> > this function, for consistency.
> 
> This patch is OK and should be committed (assuming it has passed bootstrap 
> and regression testing).

Thanks!

I did bootstrap + regression testing in v15.  In v16 I got lazy and
since the changes were small, I only checked that the new tests all
pass.

Since it looks like it's close to merging, I'll run bootstrap +
regression testing again.

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] 318+ messages in thread

* Re: [PATCH v16b 2/4] gcc/: Rename array_type_nelts => array_type_nelts_minus_one
  2024-10-16 18:02     ` Alejandro Colomar
@ 2024-10-18  8:25       ` Alejandro Colomar
  2024-10-18 11:22         ` Alejandro Colomar
  0 siblings, 1 reply; 318+ messages in thread
From: Alejandro Colomar @ 2024-10-18  8:25 UTC (permalink / raw)
  To: Joseph Myers; +Cc: gcc-patches, Jakub Jelinek, Richard Biener

[-- Attachment #1: Type: text/plain, Size: 5925 bytes --]

Hi Joseph,

On Wed, Oct 16, 2024 at 08:02:05PM GMT, Alejandro Colomar wrote:
> Hi Joseph,
> 
> On Wed, Oct 16, 2024 at 05:21:39PM GMT, Joseph Myers wrote:
> > On Wed, 16 Oct 2024, Alejandro Colomar wrote:
> > 
> > > The old name was misleading.
> > > 
> > > While at it, also rename some temporary variables that are used with
> > > this function, for consistency.
> > 
> > This patch is OK and should be committed (assuming it has passed bootstrap 
> > and regression testing).
> 
> Thanks!
> 
> I did bootstrap + regression testing in v15.  In v16 I got lazy and
> since the changes were small, I only checked that the new tests all
> pass.
> 
> Since it looks like it's close to merging, I'll run bootstrap +
> regression testing again.

I've finished with regression testing.  It's all good for the entire
patch set.  See below.

Have a lovely day!
Alex


$ find | grep sum$ | while read f; do diff -u ../len16b_b4/$f $f; done
--- ../len16b_b4/./gcc/testsuite/gcc/gcc.sum	2024-10-16 22:35:00.073117065 +0200
+++ ./gcc/testsuite/gcc/gcc.sum	2024-10-18 01:03:29.717522166 +0200
@@ -1,4 +1,4 @@
-Test run by alx on Wed Oct 16 20:49:15 2024
+Test run by alx on Thu Oct 17 23:17:38 2024
 Native configuration is x86_64-pc-linux-gnu
 
 		=== gcc tests ===
@@ -77826,6 +77826,29 @@
 PASS: gcc.dg/conv-2.c (test for excess errors)
 PASS: gcc.dg/conv-3.c (test for excess errors)
 PASS: gcc.dg/conv-3.c execution test
+PASS: gcc.dg/countof-compile.c  (test for errors, line 20)
+PASS: gcc.dg/countof-compile.c  (test for errors, line 24)
+PASS: gcc.dg/countof-compile.c  (test for errors, line 35)
+PASS: gcc.dg/countof-compile.c  (test for errors, line 50)
+PASS: gcc.dg/countof-compile.c  (test for errors, line 53)
+PASS: gcc.dg/countof-compile.c  (test for errors, line 56)
+PASS: gcc.dg/countof-compile.c  (test for errors, line 68)
+PASS: gcc.dg/countof-compile.c  (test for errors, line 69)
+PASS: gcc.dg/countof-compile.c  (test for errors, line 70)
+PASS: gcc.dg/countof-compile.c  (test for errors, line 71)
+PASS: gcc.dg/countof-compile.c  (test for errors, line 72)
+PASS: gcc.dg/countof-compile.c  (test for errors, line 73)
+PASS: gcc.dg/countof-compile.c  (test for errors, line 74)
+PASS: gcc.dg/countof-compile.c  (test for errors, line 75)
+PASS: gcc.dg/countof-compile.c  (test for errors, line 76)
+PASS: gcc.dg/countof-compile.c  (test for warnings, line 80)
+PASS: gcc.dg/countof-compile.c  (test for errors, line 100)
+PASS: gcc.dg/countof-compile.c  (test for errors, line 109)
+PASS: gcc.dg/countof-compile.c  (test for errors, line 114)
+PASS: gcc.dg/countof-compile.c (test for excess errors)
+PASS: gcc.dg/countof-vla.c (test for excess errors)
+PASS: gcc.dg/countof.c (test for excess errors)
+PASS: gcc.dg/countof.c execution test
 PASS: gcc.dg/cr-decimal-dig-1.c (test for excess errors)
 PASS: gcc.dg/cr-decimal-dig-2.c (test for excess errors)
 PASS: gcc.dg/cr-decimal-dig-3.c (test for excess errors)
@@ -208273,7 +208296,7 @@
 
 		=== gcc Summary ===
 
-# of expected passes		203197
+# of expected passes		203220
 # of unexpected failures	47
 # of unexpected successes	2
 # of expected failures		1467
--- ../len16b_b4/./gcc/testsuite/gfortran/gfortran.sum	2024-10-17 00:13:36.027361156 +0200
+++ ./gcc/testsuite/gfortran/gfortran.sum	2024-10-18 02:42:26.303591286 +0200
@@ -1,4 +1,4 @@
-Test run by alx on Wed Oct 16 23:38:34 2024
+Test run by alx on Fri Oct 18 02:07:15 2024
 Native configuration is x86_64-pc-linux-gnu
 
 		=== gfortran tests ===
--- ../len16b_b4/./gcc/testsuite/objc/objc.sum	2024-10-17 00:14:42.583978154 +0200
+++ ./gcc/testsuite/objc/objc.sum	2024-10-18 02:43:33.504187051 +0200
@@ -1,4 +1,4 @@
-Test run by alx on Thu Oct 17 00:13:36 2024
+Test run by alx on Fri Oct 18 02:42:26 2024
 Native configuration is x86_64-pc-linux-gnu
 
 		=== objc tests ===
--- ../len16b_b4/./gcc/testsuite/g++/g++.sum	2024-10-16 23:38:33.908171142 +0200
+++ ./gcc/testsuite/g++/g++.sum	2024-10-18 02:07:14.745543661 +0200
@@ -1,4 +1,4 @@
-Test run by alx on Wed Oct 16 22:35:00 2024
+Test run by alx on Fri Oct 18 01:03:30 2024
 Native configuration is x86_64-pc-linux-gnu
 
 		=== g++ tests ===
--- ../len16b_b4/./x86_64-pc-linux-gnu/libitm/testsuite/libitm.sum	2024-10-17 03:41:54.781371501 +0200
+++ ./x86_64-pc-linux-gnu/libitm/testsuite/libitm.sum	2024-10-18 06:08:27.040788653 +0200
@@ -1,4 +1,4 @@
-Test run by alx on Thu Oct 17 03:41:52 2024
+Test run by alx on Fri Oct 18 06:08:24 2024
 Native configuration is x86_64-pc-linux-gnu
 
 		=== libitm tests ===
--- ../len16b_b4/./x86_64-pc-linux-gnu/libgomp/testsuite/libgomp.sum	2024-10-17 03:41:52.169347276 +0200
+++ ./x86_64-pc-linux-gnu/libgomp/testsuite/libgomp.sum	2024-10-18 06:08:24.288765717 +0200
@@ -1,4 +1,4 @@
-Test run by alx on Thu Oct 17 03:27:33 2024
+Test run by alx on Fri Oct 18 05:54:08 2024
 Native configuration is x86_64-pc-linux-gnu
 
 		=== libgomp tests ===
--- ../len16b_b4/./x86_64-pc-linux-gnu/libatomic/testsuite/libatomic.sum	2024-10-17 03:41:56.989391978 +0200
+++ ./x86_64-pc-linux-gnu/libatomic/testsuite/libatomic.sum	2024-10-18 06:08:29.288807393 +0200
@@ -1,4 +1,4 @@
-Test run by alx on Thu Oct 17 03:41:55 2024
+Test run by alx on Fri Oct 18 06:08:27 2024
 Native configuration is x86_64-pc-linux-gnu
 
 		=== libatomic tests ===
--- ../len16b_b4/./x86_64-pc-linux-gnu/libstdc++-v3/testsuite/libstdc++.sum	2024-10-17 03:27:10.237000409 +0200
+++ ./x86_64-pc-linux-gnu/libstdc++-v3/testsuite/libstdc++.sum	2024-10-18 05:53:44.801155283 +0200
@@ -1,4 +1,4 @@
-Test run by alx on Thu Oct 17 00:15:11 2024
+Test run by alx on Fri Oct 18 02:43:39 2024
 Native configuration is x86_64-pc-linux-gnu
 
 		=== libstdc++ tests ===


> 
> Have a lovely night!
> 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] 318+ messages in thread

* Re: [PATCH v16b 2/4] gcc/: Rename array_type_nelts => array_type_nelts_minus_one
  2024-10-18  8:25       ` Alejandro Colomar
@ 2024-10-18 11:22         ` Alejandro Colomar
  0 siblings, 0 replies; 318+ messages in thread
From: Alejandro Colomar @ 2024-10-18 11:22 UTC (permalink / raw)
  To: Joseph Myers; +Cc: gcc-patches, Jakub Jelinek, Richard Biener

[-- Attachment #1: Type: text/plain, Size: 6506 bytes --]

On Fri, Oct 18, 2024 at 10:25:59AM GMT, Alejandro Colomar wrote:
> Hi Joseph,
> 
> On Wed, Oct 16, 2024 at 08:02:05PM GMT, Alejandro Colomar wrote:
> > Hi Joseph,
> > 
> > On Wed, Oct 16, 2024 at 05:21:39PM GMT, Joseph Myers wrote:
> > > On Wed, 16 Oct 2024, Alejandro Colomar wrote:
> > > 
> > > > The old name was misleading.
> > > > 
> > > > While at it, also rename some temporary variables that are used with
> > > > this function, for consistency.
> > > 
> > > This patch is OK and should be committed (assuming it has passed bootstrap 
> > > and regression testing).

This patch (2/4) needs patch 1/4 for the commit message.  Otherwise
`git gcc-verify` reports a problem (Cc: tags).  Please revise patch 1/4
too.

Cheers,
Alex

> > 
> > Thanks!
> > 
> > I did bootstrap + regression testing in v15.  In v16 I got lazy and
> > since the changes were small, I only checked that the new tests all
> > pass.
> > 
> > Since it looks like it's close to merging, I'll run bootstrap +
> > regression testing again.
> 
> I've finished with regression testing.  It's all good for the entire
> patch set.  See below.
> 
> Have a lovely day!
> Alex
> 
> 
> $ find | grep sum$ | while read f; do diff -u ../len16b_b4/$f $f; done
> --- ../len16b_b4/./gcc/testsuite/gcc/gcc.sum	2024-10-16 22:35:00.073117065 +0200
> +++ ./gcc/testsuite/gcc/gcc.sum	2024-10-18 01:03:29.717522166 +0200
> @@ -1,4 +1,4 @@
> -Test run by alx on Wed Oct 16 20:49:15 2024
> +Test run by alx on Thu Oct 17 23:17:38 2024
>  Native configuration is x86_64-pc-linux-gnu
>  
>  		=== gcc tests ===
> @@ -77826,6 +77826,29 @@
>  PASS: gcc.dg/conv-2.c (test for excess errors)
>  PASS: gcc.dg/conv-3.c (test for excess errors)
>  PASS: gcc.dg/conv-3.c execution test
> +PASS: gcc.dg/countof-compile.c  (test for errors, line 20)
> +PASS: gcc.dg/countof-compile.c  (test for errors, line 24)
> +PASS: gcc.dg/countof-compile.c  (test for errors, line 35)
> +PASS: gcc.dg/countof-compile.c  (test for errors, line 50)
> +PASS: gcc.dg/countof-compile.c  (test for errors, line 53)
> +PASS: gcc.dg/countof-compile.c  (test for errors, line 56)
> +PASS: gcc.dg/countof-compile.c  (test for errors, line 68)
> +PASS: gcc.dg/countof-compile.c  (test for errors, line 69)
> +PASS: gcc.dg/countof-compile.c  (test for errors, line 70)
> +PASS: gcc.dg/countof-compile.c  (test for errors, line 71)
> +PASS: gcc.dg/countof-compile.c  (test for errors, line 72)
> +PASS: gcc.dg/countof-compile.c  (test for errors, line 73)
> +PASS: gcc.dg/countof-compile.c  (test for errors, line 74)
> +PASS: gcc.dg/countof-compile.c  (test for errors, line 75)
> +PASS: gcc.dg/countof-compile.c  (test for errors, line 76)
> +PASS: gcc.dg/countof-compile.c  (test for warnings, line 80)
> +PASS: gcc.dg/countof-compile.c  (test for errors, line 100)
> +PASS: gcc.dg/countof-compile.c  (test for errors, line 109)
> +PASS: gcc.dg/countof-compile.c  (test for errors, line 114)
> +PASS: gcc.dg/countof-compile.c (test for excess errors)
> +PASS: gcc.dg/countof-vla.c (test for excess errors)
> +PASS: gcc.dg/countof.c (test for excess errors)
> +PASS: gcc.dg/countof.c execution test
>  PASS: gcc.dg/cr-decimal-dig-1.c (test for excess errors)
>  PASS: gcc.dg/cr-decimal-dig-2.c (test for excess errors)
>  PASS: gcc.dg/cr-decimal-dig-3.c (test for excess errors)
> @@ -208273,7 +208296,7 @@
>  
>  		=== gcc Summary ===
>  
> -# of expected passes		203197
> +# of expected passes		203220
>  # of unexpected failures	47
>  # of unexpected successes	2
>  # of expected failures		1467
> --- ../len16b_b4/./gcc/testsuite/gfortran/gfortran.sum	2024-10-17 00:13:36.027361156 +0200
> +++ ./gcc/testsuite/gfortran/gfortran.sum	2024-10-18 02:42:26.303591286 +0200
> @@ -1,4 +1,4 @@
> -Test run by alx on Wed Oct 16 23:38:34 2024
> +Test run by alx on Fri Oct 18 02:07:15 2024
>  Native configuration is x86_64-pc-linux-gnu
>  
>  		=== gfortran tests ===
> --- ../len16b_b4/./gcc/testsuite/objc/objc.sum	2024-10-17 00:14:42.583978154 +0200
> +++ ./gcc/testsuite/objc/objc.sum	2024-10-18 02:43:33.504187051 +0200
> @@ -1,4 +1,4 @@
> -Test run by alx on Thu Oct 17 00:13:36 2024
> +Test run by alx on Fri Oct 18 02:42:26 2024
>  Native configuration is x86_64-pc-linux-gnu
>  
>  		=== objc tests ===
> --- ../len16b_b4/./gcc/testsuite/g++/g++.sum	2024-10-16 23:38:33.908171142 +0200
> +++ ./gcc/testsuite/g++/g++.sum	2024-10-18 02:07:14.745543661 +0200
> @@ -1,4 +1,4 @@
> -Test run by alx on Wed Oct 16 22:35:00 2024
> +Test run by alx on Fri Oct 18 01:03:30 2024
>  Native configuration is x86_64-pc-linux-gnu
>  
>  		=== g++ tests ===
> --- ../len16b_b4/./x86_64-pc-linux-gnu/libitm/testsuite/libitm.sum	2024-10-17 03:41:54.781371501 +0200
> +++ ./x86_64-pc-linux-gnu/libitm/testsuite/libitm.sum	2024-10-18 06:08:27.040788653 +0200
> @@ -1,4 +1,4 @@
> -Test run by alx on Thu Oct 17 03:41:52 2024
> +Test run by alx on Fri Oct 18 06:08:24 2024
>  Native configuration is x86_64-pc-linux-gnu
>  
>  		=== libitm tests ===
> --- ../len16b_b4/./x86_64-pc-linux-gnu/libgomp/testsuite/libgomp.sum	2024-10-17 03:41:52.169347276 +0200
> +++ ./x86_64-pc-linux-gnu/libgomp/testsuite/libgomp.sum	2024-10-18 06:08:24.288765717 +0200
> @@ -1,4 +1,4 @@
> -Test run by alx on Thu Oct 17 03:27:33 2024
> +Test run by alx on Fri Oct 18 05:54:08 2024
>  Native configuration is x86_64-pc-linux-gnu
>  
>  		=== libgomp tests ===
> --- ../len16b_b4/./x86_64-pc-linux-gnu/libatomic/testsuite/libatomic.sum	2024-10-17 03:41:56.989391978 +0200
> +++ ./x86_64-pc-linux-gnu/libatomic/testsuite/libatomic.sum	2024-10-18 06:08:29.288807393 +0200
> @@ -1,4 +1,4 @@
> -Test run by alx on Thu Oct 17 03:41:55 2024
> +Test run by alx on Fri Oct 18 06:08:27 2024
>  Native configuration is x86_64-pc-linux-gnu
>  
>  		=== libatomic tests ===
> --- ../len16b_b4/./x86_64-pc-linux-gnu/libstdc++-v3/testsuite/libstdc++.sum	2024-10-17 03:27:10.237000409 +0200
> +++ ./x86_64-pc-linux-gnu/libstdc++-v3/testsuite/libstdc++.sum	2024-10-18 05:53:44.801155283 +0200
> @@ -1,4 +1,4 @@
> -Test run by alx on Thu Oct 17 00:15:11 2024
> +Test run by alx on Fri Oct 18 02:43:39 2024
>  Native configuration is x86_64-pc-linux-gnu
>  
>  		=== libstdc++ tests ===
> 
> 
> > 
> > Have a lovely night!
> > 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] 318+ messages in thread

* Re: [PATCH v16b 3/4] gcc/: Merge definitions of array_type_nelts_top
  2024-10-16 12:10 ` [PATCH v16b 3/4] gcc/: Merge definitions of array_type_nelts_top Alejandro Colomar
@ 2024-10-18 22:43   ` Joseph Myers
  0 siblings, 0 replies; 318+ messages in thread
From: Joseph Myers @ 2024-10-18 22:43 UTC (permalink / raw)
  To: Alejandro Colomar; +Cc: gcc-patches, Jakub Jelinek, Richard Biener

On Wed, 16 Oct 2024, Alejandro Colomar wrote:

> There were two identical definitions, and none of them are available
> where they are needed for implementing __nelementsof__.  Merge them, and
> provide the single definition in gcc/tree.{h,cc}, where it's available
> for __nelementsof__, which will be added in the following commit.

Thanks, committed.

-- 
Joseph S. Myers
josmyers@redhat.com


^ permalink raw reply	[flat|nested] 318+ messages in thread

* [PATCH v17 0/2] c: Add __countof__ operator
  2024-07-28 14:15 ` [RFC v1 0/2] c: Add _Lengthof operator Alejandro Colomar
                     ` (20 preceding siblings ...)
  2024-10-16 10:13   ` [PATCH v15 0/4] " Alejandro Colomar
@ 2024-10-22 18:48   ` Alejandro Colomar
  2024-10-22 18:48     ` [PATCH v17 1/2] contrib/: Add support for Cc: and Link: tags Alejandro Colomar
                       ` (2 more replies)
  2024-11-10 10:32   ` [PATCH v18 " Alejandro Colomar
                     ` (6 subsequent siblings)
  28 siblings, 3 replies; 318+ messages in thread
From: Alejandro Colomar @ 2024-10-22 18:48 UTC (permalink / raw)
  To: gcc-patches, josmyers; +Cc: Alejandro Colomar

[-- Attachment #1: Type: text/plain, Size: 3135 bytes --]

Hi Joseph,

I found some tests that could be improved, so I've worked on that in the
last few days.  I'll post as a reply to this email the bootstrap and
regression testing results.


v17 changes:

-  Rebase (patches 2/4 and 3/4 from v16b have been merged already).
-  Improve and add tests.

Below is the range diff against v16b.


Have a lovely night!
Alex

Alejandro Colomar (2):
  contrib/: Add support for Cc: and Link: tags
  c: Add __countof__ operator

 contrib/gcc-changelog/git_commit.py    |   5 +-
 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                        |  22 +++-
 gcc/c/c-parser.cc                      |  62 +++++++---
 gcc/c/c-tree.h                         |   4 +
 gcc/c/c-typeck.cc                      | 118 ++++++++++++++++++-
 gcc/doc/extend.texi                    |  30 +++++
 gcc/testsuite/gcc.dg/countof-compile.c | 127 +++++++++++++++++++++
 gcc/testsuite/gcc.dg/countof-vla.c     |  46 ++++++++
 gcc/testsuite/gcc.dg/countof.c         | 150 +++++++++++++++++++++++++
 12 files changed, 570 insertions(+), 25 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/countof-compile.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-vla.c
 create mode 100644 gcc/testsuite/gcc.dg/countof.c

Range-diff against v16b:
1:  eac2d18d8a0 = 1:  d847dc4a795 contrib/: Add support for Cc: and Link: tags
2:  7418a11fcd6 < -:  ----------- gcc/: Rename array_type_nelts => array_type_nelts_minus_one
3:  0cfae0598b3 < -:  ----------- gcc/: Merge definitions of array_type_nelts_top
4:  12a30a2a6fd ! 2:  936f7945fae c: Add __countof__ operator
    @@ gcc/testsuite/gcc.dg/countof-compile.c (new)
     +static int y[__countof__(z)];
     +
     +void
    -+automatic(void)
    ++completed (void)
     +{
    -+  __countof__ (w);
    ++  int i = 42;
    ++  int a[] = {1, 2, i};
    ++
    ++  _Static_assert(__countof__ (w) == 3);
    ++  __countof__ (a);
     +}
     +
     +void
    @@ gcc/testsuite/gcc.dg/countof-compile.c (new)
     +{
     +  __countof__ (x);  /* { dg-error "incomplete" } */
     +
    -+  /* We want to support the following one in the future,
    -+     but for now it should fail.  */
    ++  /* We want to support array parameters in the future,
    ++     which should change this from "invalid" to "incomplete".  */
     +  __countof__ (p);  /* { dg-error "invalid" } */
     +}
     +
    @@ gcc/testsuite/gcc.dg/countof-compile.c (new)
     +  __countof__ (s.fam); /* { dg-error "incomplete" } */
     +}
     +
    ++void
    ++param (int n, int p[n])
    ++{
    ++  /* We want to support array parameters in the future,
    ++     which would make this work.  */
    ++  __countof__ (p);  /* { dg-error "invalid" } */
    ++}
    ++
     +void fix_fix (int i, char (*a)[3][5], int (*x)[__countof__ (*a)]);
     +void fix_var (int i, char (*a)[3][i], int (*x)[__countof__ (*a)]);
     +void fix_uns (int i, char (*a)[3][*], int (*x)[__countof__ (*a)]);

-- 
2.45.2


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 318+ messages in thread

* [PATCH v17 1/2] contrib/: Add support for Cc: and Link: tags
  2024-10-22 18:48   ` [PATCH v17 0/2] " Alejandro Colomar
@ 2024-10-22 18:48     ` Alejandro Colomar
  2024-10-22 18:48     ` [PATCH v17 2/2] c: Add __countof__ operator Alejandro Colomar
  2024-10-22 18:52     ` [PATCH v17 0/2] " Alejandro Colomar
  2 siblings, 0 replies; 318+ messages in thread
From: Alejandro Colomar @ 2024-10-22 18:48 UTC (permalink / raw)
  To: gcc-patches, josmyers; +Cc: Alejandro Colomar

[-- Attachment #1: Type: text/plain, Size: 1258 bytes --]

contrib/ChangeLog:

	* gcc-changelog/git_commit.py (GitCommit):
	Add support for 'Cc: ' and 'Link: ' tags.

Cc: Jason Merrill <jason@redhat.com>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
---
 contrib/gcc-changelog/git_commit.py | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/contrib/gcc-changelog/git_commit.py b/contrib/gcc-changelog/git_commit.py
index 87ecb9e1a17..64fb986b74c 100755
--- a/contrib/gcc-changelog/git_commit.py
+++ b/contrib/gcc-changelog/git_commit.py
@@ -182,7 +182,8 @@ CO_AUTHORED_BY_PREFIX = 'co-authored-by: '
 
 REVIEW_PREFIXES = ('reviewed-by: ', 'reviewed-on: ', 'signed-off-by: ',
                    'acked-by: ', 'tested-by: ', 'reported-by: ',
-                   'suggested-by: ')
+                   'suggested-by: ', 'cc: ')
+LINK_PREFIXES = ('link: ')
 DATE_FORMAT = '%Y-%m-%d'
 
 
@@ -524,6 +525,8 @@ class GitCommit:
                     continue
                 elif lowered_line.startswith(REVIEW_PREFIXES):
                     continue
+                elif lowered_line.startswith(LINK_PREFIXES):
+                    continue
                 else:
                     m = cherry_pick_regex.search(line)
                     if m:
-- 
2.45.2


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 318+ messages in thread

* [PATCH v17 2/2] c: Add __countof__ operator
  2024-10-22 18:48   ` [PATCH v17 0/2] " Alejandro Colomar
  2024-10-22 18:48     ` [PATCH v17 1/2] contrib/: Add support for Cc: and Link: tags Alejandro Colomar
@ 2024-10-22 18:48     ` Alejandro Colomar
  2024-10-25 20:44       ` Joseph Myers
  2024-10-22 18:52     ` [PATCH v17 0/2] " Alejandro Colomar
  2 siblings, 1 reply; 318+ messages in thread
From: Alejandro Colomar @ 2024-10-22 18:48 UTC (permalink / raw)
  To: gcc-patches, josmyers; +Cc: Alejandro Colomar

[-- Attachment #1: Type: text/plain, Size: 30129 bytes --]

This operator is similar to sizeof but can only be applied to an array,
and returns its number of elements.

FUTURE DIRECTIONS:

-  We should make it work with array parameters to functions,
   and somehow magically return the number of elements of the array,
   regardless of it being really a pointer.

-  Fix support for [0].

gcc/ChangeLog:

	* doc/extend.texi: Document __countof__ operator.

gcc/c-family/ChangeLog:

	* c-common.h
	* c-common.def
	* c-common.cc (c_countof_type): Add __countof__ operator.

gcc/c/ChangeLog:

	* c-tree.h
	(c_expr_countof_expr, c_expr_countof_type)
	* c-decl.cc
	(start_struct, finish_struct)
	(start_enum, finish_enum)
	* c-parser.cc
	(c_parser_sizeof_expression)
	(c_parser_countof_expression)
	(c_parser_sizeof_or_countof_expression)
	(c_parser_unary_expression)
	* c-typeck.cc
	(build_external_ref)
	(record_maybe_used_decl)
	(pop_maybe_used)
	(is_top_array_vla)
	(c_expr_countof_expr, c_expr_countof_type):
	Add __countof__ operator.

gcc/testsuite/ChangeLog:

	* gcc.dg/countof-compile.c
	* gcc.dg/countof-vla.c
	* gcc.dg/countof.c: Add tests for __countof__ operator.

Link: <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117025>
Link: <https://inbox.sourceware.org/gcc/M8S4oQy--3-2@tutanota.com/T/>
Link: <https://inbox.sourceware.org/gcc-patches/20240728141547.302478-1-alx@kernel.org/T/#t>
Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3313.pdf>
Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3325.pdf>
Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3369.pdf>
Link: <https://github.com/llvm/llvm-project/issues/102836>
Link: <https://stackoverflow.com/questions/37538/#57537491>
Suggested-by: Xavier Del Campo Romero <xavi.dcr@tutanota.com>
Co-authored-by: Martin Uecker <uecker@tugraz.at>
Acked-by: "James K. Lowden" <jklowden@schemamania.org>
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>
Cc: Daniel Plakosh <dplakosh@cert.org>
Cc: "A. Jiang" <de34@live.cn>
Cc: Eugene Zelenko <eugene.zelenko@gmail.com>
Cc: Aaron Ballman <aaron.ballman@intel.com>
Cc: Paul Koning <paulkoning@comcast.net>
Cc: Daniel Lundin <daniel.lundin.mail@gmail.com>
Cc: Nikolaos Strimpas <Strnik86@protonmail.com>
Cc: JeanHeyd Meneide <phdofthehouse@gmail.com>
Cc: Fernando Borretti <fernando@borretti.me>
Cc: Jonathan Protzenko <jonathan.protzenko@ens-lyon.org>
Cc: Chris Bazley <Chris.Bazley@arm.com>
Cc: Ville Voutilainen <ville.voutilainen@gmail.com>
Cc: Alex Celeste <alexg.nvfp@gmail.com>
Cc: Jakub Łukasiewicz <jakublukasiewicz@outlook.com>
Cc: Douglas McIlroy <douglas.mcilroy@dartmouth.edu>
Cc: Jason Merrill <jason@redhat.com>
Cc: "Gustavo A. R. Silva" <gustavoars@kernel.org>
Cc: Patrizia Kaye <patrizia@ethernull.org>
Cc: Ori Bernstein <ori@eigenstate.org>
Cc: Robert Seacord <rcseacord@gmail.com>
Cc: Marek Polacek <mpolacek@gcc.gnu.org>
Cc: Sam James <sam@gentoo.org>
Cc: Richard Biener <richard.guenther@gmail.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                        |  22 +++-
 gcc/c/c-parser.cc                      |  62 +++++++---
 gcc/c/c-tree.h                         |   4 +
 gcc/c/c-typeck.cc                      | 118 ++++++++++++++++++-
 gcc/doc/extend.texi                    |  30 +++++
 gcc/testsuite/gcc.dg/countof-compile.c | 127 +++++++++++++++++++++
 gcc/testsuite/gcc.dg/countof-vla.c     |  46 ++++++++
 gcc/testsuite/gcc.dg/countof.c         | 150 +++++++++++++++++++++++++
 11 files changed, 566 insertions(+), 24 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/countof-compile.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-vla.c
 create mode 100644 gcc/testsuite/gcc.dg/countof.c

diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
index 7494a2dac0a..9f48fea6543 100644
--- a/gcc/c-family/c-common.cc
+++ b/gcc/c-family/c-common.cc
@@ -466,6 +466,7 @@ const struct c_common_resword c_common_reswords[] =
   { "__inline",		RID_INLINE,	0 },
   { "__inline__",	RID_INLINE,	0 },
   { "__label__",	RID_LABEL,	0 },
+  { "__countof__",	RID_COUNTOF,	0 },
   { "__null",		RID_NULL,	0 },
   { "__real",		RID_REALPART,	0 },
   { "__real__",		RID_REALPART,	0 },
@@ -4071,6 +4072,31 @@ c_alignof_expr (location_t loc, tree expr)
 
   return fold_convert_loc (loc, size_type_node, t);
 }
+
+/* Implement the countof keyword:
+   Return the number of elements of an array.  */
+
+tree
+c_countof_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 %<__countof__%> to type %qT", type);
+      return error_mark_node;
+    }
+  if (!COMPLETE_TYPE_P (type))
+    {
+      error_at (loc,
+		"invalid application of %<__countof__%> 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 dc49ad09e2f..f2ae784cefe 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 'countof' expression.  */
+DEFTREECODE (COUNTOF_EXPR, "countof_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 1e80939d379..6c6ee08925e 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_COUNTOF,
   RID_VA_ARG,
   RID_EXTENSION, RID_IMAGPART, RID_REALPART, RID_LABEL,    RID_CHOOSE_EXPR,
   RID_TYPES_COMPATIBLE_P,      RID_BUILTIN_COMPLEX,	   RID_BUILTIN_SHUFFLE,
@@ -889,6 +890,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_countof_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 3733ecfc13f..23c620bbea7 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -9005,12 +9005,17 @@ 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_countof))
     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"
+		       : "__countof__"))));
 
   if (in_underspecified_init)
     error_at (loc, "%qT defined in underspecified object initializer", ref);
@@ -9974,7 +9979,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_countof)
 	struct_parse_info->struct_types.safe_push (t);
      }
 
@@ -10148,12 +10153,17 @@ 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_countof))
     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"
+		       : "__countof__"))));
 
   if (in_underspecified_init)
     error_at (loc, "%qT defined in underspecified object initializer",
@@ -10347,7 +10357,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_countof)
     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 090ab1cbc08..73e419ea7ee 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_countof_expression (parser, RID_SIZEOF)                  \
+)
 
+#define c_parser_countof_expression(parser)                                   \
+(                                                                             \
+  c_parser_sizeof_or_countof_expression (parser, RID_COUNTOF)                 \
+)
+\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
@@ -1695,7 +1705,8 @@ 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_countof_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 *,
@@ -10196,6 +10207,8 @@ c_parser_unary_expression (c_parser *parser)
     case CPP_KEYWORD:
       switch (c_parser_peek_token (parser)->keyword)
 	{
+	case RID_COUNTOF:
+	  return c_parser_countof_expression (parser);
 	case RID_SIZEOF:
 	  return c_parser_sizeof_expression (parser);
 	case RID_ALIGNOF:
@@ -10235,12 +10248,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_countof_expression (c_parser *parser, enum rid rid)
 {
+  const char *op_name = (rid == RID_COUNTOF) ? "__countof__" : "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;
@@ -10249,7 +10263,10 @@ c_parser_sizeof_expression (c_parser *parser)
 
   c_parser_consume_token (parser);
   c_inhibit_evaluation_warnings++;
-  in_sizeof++;
+  if (rid == RID_COUNTOF)
+    in_countof++;
+  else
+    in_sizeof++;
   if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)
       && c_token_starts_compound_literal (c_parser_peek_2nd_token (parser)))
     {
@@ -10268,7 +10285,10 @@ c_parser_sizeof_expression (c_parser *parser)
 	{
 	  struct c_expr ret;
 	  c_inhibit_evaluation_warnings--;
-	  in_sizeof--;
+	  if (rid == RID_COUNTOF)
+	    in_countof--;
+	  else
+	    in_sizeof--;
 	  ret.set_error ();
 	  ret.original_code = ERROR_MARK;
 	  ret.original_type = NULL;
@@ -10280,31 +10300,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_COUNTOF)
+	{
+	  in_countof--;
+	  result = c_expr_countof_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_COUNTOF)
+	in_countof--;
+      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_COUNTOF)
+	result = c_expr_countof_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 a1435e7cb0c..9bdce690374 100644
--- a/gcc/c/c-tree.h
+++ b/gcc/c/c-tree.h
@@ -764,6 +764,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_countof;
 extern int in_typeof;
 extern bool c_in_omp_for;
 extern bool c_omp_array_section_p;
@@ -815,6 +816,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_countof_expr (location_t, struct c_expr);
+extern struct c_expr c_expr_countof_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 108ea5ca3e8..14313e9d649 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 "countof".  */
+int in_countof;
+
 /* The level of nesting inside "typeof".  */
 int in_typeof;
 
@@ -3273,7 +3276,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_countof)
 	C_DECL_USED (ref) = 1;
       else if (DECL_INITIAL (ref) == NULL_TREE
 	       && DECL_EXTERNAL (ref)
@@ -3329,7 +3332,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_countof).  */
   int level;
   /* The next one at this level or above, or NULL.  */
   struct maybe_used_decl *next;
@@ -3347,7 +3350,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_countof;
   t->next = maybe_used_decls;
   maybe_used_decls = t;
 }
@@ -3361,7 +3364,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_countof;
   while (p && p->level > cur_level)
     {
       if (used)
@@ -3471,6 +3474,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 countof applied to EXPR.  */
+
+struct c_expr
+c_expr_countof_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_countof_type (loc, TREE_TYPE (folded_expr));
+      c_last_sizeof_arg = expr.value;
+      c_last_sizeof_loc = loc;
+      ret.original_code = COUNTOF_EXPR;
+      ret.original_type = NULL;
+      ret.m_decimal = 0;
+      if (is_top_array_vla (TREE_TYPE (folded_expr)))
+	{
+	  /* countof 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 countof applied to T, a structure for the type
+   name passed to countof (rather than the type itself).  LOC is the
+   location of the original expression.  */
+
+struct c_expr
+c_expr_countof_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_countof_type (loc, type);
+  c_last_sizeof_arg = type;
+  c_last_sizeof_loc = loc;
+  ret.original_code = COUNTOF_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 countof does not get folded to a constant by
+	 c_fully_fold, because if the number of elements is evaluated
+	 the result is not constant and so
+	 constraints on zero or negative size arrays must not be applied
+	 when this countof 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/doc/extend.texi b/gcc/doc/extend.texi
index 42bd567119d..4bd1f637657 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -10555,6 +10555,36 @@ 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 __countof__
+@section Determining the Number of Elements of Arrays
+@cindex __countof__
+@cindex number of elements
+
+The keyword @code{__countof__} determines
+the number of elements of an array operand.
+Its syntax is similar to @code{sizeof}.
+The operand must be
+a parenthesized complete array type name
+or an expression of such a type.
+For example:
+
+@smallexample
+int a[n];
+__countof__ (a);  // returns n
+__countof__ (int [7][3]);  // returns 7
+@end smallexample
+
+The result of this operator is an integer constant expression,
+unless the array has a variable number of elements.
+The operand is only evaluated
+if the array has a variable number of elements.
+For example:
+
+@smallexample
+__countof__ (int [7][n++]);  // integer constant expression
+__countof__ (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/testsuite/gcc.dg/countof-compile.c b/gcc/testsuite/gcc.dg/countof-compile.c
new file mode 100644
index 00000000000..bfb51109496
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/countof-compile.c
@@ -0,0 +1,127 @@
+/* { 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[__countof__(z)];
+
+void
+completed (void)
+{
+  int i = 42;
+  int a[] = {1, 2, i};
+
+  _Static_assert(__countof__ (w) == 3);
+  __countof__ (a);
+}
+
+void
+incomplete (int p[])
+{
+  __countof__ (x);  /* { dg-error "incomplete" } */
+
+  /* We want to support array parameters in the future,
+     which should change this from "invalid" to "incomplete".  */
+  __countof__ (p);  /* { dg-error "invalid" } */
+}
+
+void
+fam (void)
+{
+  struct {
+    int x;
+    int fam[];
+  } s;
+
+  __countof__ (s.fam); /* { dg-error "incomplete" } */
+}
+
+void
+param (int n, int p[n])
+{
+  /* We want to support array parameters in the future,
+     which would make this work.  */
+  __countof__ (p);  /* { dg-error "invalid" } */
+}
+
+void fix_fix (int i, char (*a)[3][5], int (*x)[__countof__ (*a)]);
+void fix_var (int i, char (*a)[3][i], int (*x)[__countof__ (*a)]);
+void fix_uns (int i, char (*a)[3][*], int (*x)[__countof__ (*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;
+
+  __countof__ (x); /* { dg-error "invalid" } */
+  __countof__ (int); /* { dg-error "invalid" } */
+  __countof__ (s); /* { dg-error "invalid" } */
+  __countof__ (struct s); /* { dg-error "invalid" } */
+  __countof__ (&x); /* { dg-error "invalid" } */
+  __countof__ (p); /* { dg-error "invalid" } */
+  __countof__ (int *); /* { dg-error "invalid" } */
+  __countof__ (&s.x); /* { dg-error "invalid" } */
+  __countof__ (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];
+
+  __countof__ (a[f1()]);
+  __countof__ (b[f2()]);
+}
+
+void
+no_parens(void)
+{
+  __countof__ a;
+  __countof__ *a;
+  __countof__ (int [3]) {};
+
+  __countof__ int [3]; /* { dg-error "expected expression before" } */
+}
+
+void
+const_expr(void)
+{
+  int n = 7;
+
+  _Static_assert (__countof__ (int [3][n]) == 3);
+  _Static_assert (__countof__ (int [n][3]) == 7); /* { dg-error "not constant" } */
+  _Static_assert (__countof__ (int [0][3]) == 0);
+  _Static_assert (__countof__ (int [0]) == 0);
+
+  /* FIXME: countof(int [0][n]) should result in a constant expression.  */
+  _Static_assert (__countof__ (int [0][n]) == 0); /* { dg-error "not constant" } */
+}
diff --git a/gcc/testsuite/gcc.dg/countof-vla.c b/gcc/testsuite/gcc.dg/countof-vla.c
new file mode 100644
index 00000000000..5a82aeed782
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/countof-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)[__countof__ (*a)]);
+void fix_var (int i,
+	      char (*a)[3][i], /* dg-warn "variable" */
+	      int (*x)[__countof__ (*a)]);
+void fix_uns (int i,
+	      char (*a)[3][*],
+	      int (*x)[__countof__ (*a)]);
+
+void zro_fix (int i,
+	      char (*a)[0][5],
+	      int (*x)[__countof__ (*a)]);
+void zro_var (int i,
+	      char (*a)[0][i], /* dg-warn "variable" */
+	      int (*x)[__countof__ (*a)]);
+void zro_uns (int i,
+	      char (*a)[0][*],
+	      int (*x)[__countof__ (*a)]);
+
+void var_fix (int i,
+	      char (*a)[i][5], /* dg-warn "variable" */
+	      int (*x)[__countof__ (*a)]); /* dg-warn "variable" */
+void var_var (int i,
+	      char (*a)[i][i], /* dg-warn "variable" */
+	      int (*x)[__countof__ (*a)]); /* dg-warn "variable" */
+void var_uns (int i,
+	      char (*a)[i][*], /* dg-warn "variable" */
+	      int (*x)[__countof__ (*a)]); /* dg-warn "variable" */
+
+void uns_fix (int i,
+	      char (*a)[*][5],
+	      int (*x)[__countof__ (*a)]);
+void uns_var (int i,
+	      char (*a)[*][i], /* dg-warn "variable" */
+	      int (*x)[__countof__ (*a)]);
+void uns_uns (int i,
+	      char (*a)[*][*],
+	      int (*x)[__countof__ (*a)]);
+
+// Can't test due to bug: <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=116284>
+//static int z2[0];
+//static int y2[__countof__(z2)];
diff --git a/gcc/testsuite/gcc.dg/countof.c b/gcc/testsuite/gcc.dg/countof.c
new file mode 100644
index 00000000000..063a207fb6b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/countof.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 (__countof__ (a) == 7);
+  static_assert (__countof__ (long [0]) == 0);
+  static_assert (__countof__ (unsigned [99]) == 99);
+}
+
+void
+automatic(void)
+{
+  int a[] = {1, 2, 3};
+  int z[] = {};
+
+  static_assert (__countof__ (a) == 3);
+  static_assert (__countof__ (z) == 0);
+}
+
+void
+vla (void)
+{
+  unsigned n;
+
+  n = 99;
+  assert (__countof__ (short [n - 10]) == 99 - 10);
+
+  int v[n / 2];
+  assert (__countof__ (v) == 99 / 2);
+
+  n = 0;
+  int z[n];
+  assert (__countof__ (z) == 0);
+}
+
+void
+member (void)
+{
+  struct {
+    int a[8];
+  } s;
+
+  static_assert (__countof__ (s.a) == 8);
+}
+
+void
+vla_eval (void)
+{
+  int i;
+
+  i = 7;
+  assert (__countof__ (struct {int x;}[i++]) == 7);
+  assert (i == 7 + 1);
+
+  int v[i];
+  int (*p)[i];
+  p = &v;
+  assert (__countof__ (*p++) == i);
+  assert (p - 1 == &v);
+}
+
+void
+inner_vla_noeval (void)
+{
+  int i;
+
+  i = 3;
+  static_assert (__countof__ (struct {int x[i++];}[3]) == 3);
+  assert (i == 3);
+}
+
+void
+array_noeval (void)
+{
+  long a[5];
+  long (*p)[__countof__ (a)];
+
+  p = &a;
+  static_assert (__countof__ (*p++) == 5);
+  assert (p == &a);
+}
+
+void
+matrix_zero (void)
+{
+  int i;
+
+  static_assert (__countof__ (int [0][4]) == 0);
+  i = 3;
+  assert (__countof__ (int [0][i]) == 0);
+}
+
+void
+matrix_fixed (void)
+{
+  int i;
+
+  static_assert (__countof__ (int [7][4]) == 7);
+  i = 3;
+  static_assert (__countof__ (int [7][i]) == 7);
+}
+
+void
+matrix_vla (void)
+{
+  int i, j;
+
+  i = 7;
+  assert (__countof__ (int [i++][4]) == 7);
+  assert (i == 7 + 1);
+
+  i = 9;
+  j = 3;
+  assert (__countof__ (int [i++][j]) == 9);
+  assert (i == 9 + 1);
+}
+
+void
+no_parens(void)
+{
+  int n = 3;
+  int a[7];
+  int v[n];
+
+  static_assert (__countof__ a == 7); 
+  assert (__countof__ 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] 318+ messages in thread

* Re: [PATCH v17 0/2] c: Add __countof__ operator
  2024-10-22 18:48   ` [PATCH v17 0/2] " Alejandro Colomar
  2024-10-22 18:48     ` [PATCH v17 1/2] contrib/: Add support for Cc: and Link: tags Alejandro Colomar
  2024-10-22 18:48     ` [PATCH v17 2/2] c: Add __countof__ operator Alejandro Colomar
@ 2024-10-22 18:52     ` Alejandro Colomar
  2 siblings, 0 replies; 318+ messages in thread
From: Alejandro Colomar @ 2024-10-22 18:52 UTC (permalink / raw)
  To: gcc-patches, josmyers

[-- Attachment #1: Type: text/plain, Size: 11890 bytes --]

On Tue, Oct 22, 2024 at 08:48:10PM GMT, Alejandro Colomar wrote:
> Hi Joseph,
> 
> I found some tests that could be improved, so I've worked on that in the
> last few days.  I'll post as a reply to this email the bootstrap and
> regression testing results.


alx@debian:~/src/gnu/gcc/len$ git tag len17
alx@debian:~/src/gnu/gcc/len$ git log --oneline gnu/master^..len17 
936f7945fae (HEAD -> len, tag: len17) c: Add __countof__ operator
d847dc4a795 contrib/: Add support for Cc: and Link: tags
01f50ebfd97 (gnu/trunk, gnu/master) Revert "[PATCH 7/7] RISC-V: Disable by pieces for ve>
alx@debian:~/src/gnu/gcc/len$ git reset gnu/master --h
HEAD is now at 01f50ebfd97 Revert "[PATCH 7/7] RISC-V: Disable by pieces for vector setmem length > UNITS_PER_WORD"
alx@debian:~/src/gnu/gcc/len$ mkdir ../len17
alx@debian:~/src/gnu/gcc/len$ cd ../len17
alx@debian:~/src/gnu/gcc/len17$ /bin/time ../len/configure --disable-multilib --prefix=/opt/local/gnu/gcc/countof |& ts -s | ovr -n 3; echo $?
00:00:04 config.status: creating Makefile
00:00:04 2.86user 1.75system 0:04.17elapsed 110%CPU (0avgtext+0avgdata 26344maxresident)k
00:00:04 97984inputs+8000outputs (305major+280624minor)pagefaults 0swaps
0
alx@debian:~/src/gnu/gcc/len17$ /bin/time make -j24 bootstrap |& ts -s | ovr -n 3; echo $?
00:21:23 make[1]: Leaving directory '/home/alx/src/gnu/gcc/len17'
00:21:23 15132.07user 432.94system 21:23.16elapsed 1213%CPU (0avgtext+0avgdata 1571468maxresident)k
00:21:23 1548192inputs+30472720outputs (19209major+118824055minor)pagefaults 0swaps
0
alx@debian:~/src/gnu/gcc/len17$ /bin/time make check |& ts -s | ovr -n 3; echo $?
06:52:09 make[1]: Leaving directory '/home/alx/src/gnu/gcc/len17'
06:52:09 21407.35user 3424.85system 6:52:09elapsed 100%CPU (0avgtext+0avgdata 2326956maxresident)k
06:52:09 731976inputs+21637088outputs (2855major+994117616minor)pagefaults 0swaps
0
alx@debian:~/src/gnu/gcc/len17$ cd ../len
alx@debian:~/src/gnu/gcc/len$ git merge --ff-only len17
Updating 01f50ebfd97..936f7945fae
Fast-forward
 contrib/gcc-changelog/git_commit.py    |   5 +-
 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                        |  22 +++++--
 gcc/c/c-parser.cc                      |  62 +++++++++++++----
 gcc/c/c-tree.h                         |   4 ++
 gcc/c/c-typeck.cc                      | 118 +++++++++++++++++++++++++++++++--
 gcc/doc/extend.texi                    |  30 +++++++++
 gcc/testsuite/gcc.dg/countof-compile.c | 127 +++++++++++++++++++++++++++++++++++
 gcc/testsuite/gcc.dg/countof-vla.c     |  46 +++++++++++++
 gcc/testsuite/gcc.dg/countof.c         | 150 ++++++++++++++++++++++++++++++++++++++++++
 12 files changed, 570 insertions(+), 25 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/countof-compile.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-vla.c
 create mode 100644 gcc/testsuite/gcc.dg/countof.c
alx@debian:~/src/gnu/gcc/len17$ cd ..
alx@debian:~/src/gnu/gcc$ mv len17/ len17_b4
alx@debian:~/src/gnu/gcc/len$ mkdir len17
alx@debian:~/src/gnu/gcc/len$ cd len17
alx@debian:~/src/gnu/gcc/len17$ /bin/time ../len/configure --disable-multilib --prefix=/opt/local/gnu/gcc/countof |& ts -s | ovr; echo $?
00:00:03 232inputs+8000outputs (1major+278059minor)pagefaults 0swaps
0
alx@debian:~/src/gnu/gcc/len17$ /bin/time make -j24 bootstrap |& ts -s | ovr; echo $?
00:20:39 40992inputs+30487656outputs (561major+125063297minor)pagefaults 0swaps
0
alx@debian:~/src/gnu/gcc/len17$ /bin/time make check |& ts -s | ovr; echo $?
06:56:00 74496inputs+21640408outputs (2723major+991618593minor)pagefaults 0swaps
0
alx@debian:~/src/gnu/gcc/len17$ find -type f | grep '\.sum$' | while read f; do diff -u ../len17_b4/$f $f; done
--- ../len17_b4/./gcc/testsuite/gcc/gcc.sum	2024-10-20 21:28:04.131516030 +0200
+++ ./gcc/testsuite/gcc/gcc.sum	2024-10-22 13:06:18.877529401 +0200
@@ -1,4 +1,4 @@
-Test run by alx on Sun Oct 20 19:42:24 2024
+Test run by alx on Tue Oct 22 11:17:17 2024
 Native configuration is x86_64-pc-linux-gnu
 
 		=== gcc tests ===
@@ -78022,6 +78022,30 @@
 PASS: gcc.dg/conv-2.c (test for excess errors)
 PASS: gcc.dg/conv-3.c (test for excess errors)
 PASS: gcc.dg/conv-3.c execution test
+PASS: gcc.dg/countof-compile.c  (test for errors, line 24)
+PASS: gcc.dg/countof-compile.c  (test for errors, line 28)
+PASS: gcc.dg/countof-compile.c  (test for errors, line 39)
+PASS: gcc.dg/countof-compile.c  (test for errors, line 47)
+PASS: gcc.dg/countof-compile.c  (test for errors, line 62)
+PASS: gcc.dg/countof-compile.c  (test for errors, line 65)
+PASS: gcc.dg/countof-compile.c  (test for errors, line 68)
+PASS: gcc.dg/countof-compile.c  (test for errors, line 80)
+PASS: gcc.dg/countof-compile.c  (test for errors, line 81)
+PASS: gcc.dg/countof-compile.c  (test for errors, line 82)
+PASS: gcc.dg/countof-compile.c  (test for errors, line 83)
+PASS: gcc.dg/countof-compile.c  (test for errors, line 84)
+PASS: gcc.dg/countof-compile.c  (test for errors, line 85)
+PASS: gcc.dg/countof-compile.c  (test for errors, line 86)
+PASS: gcc.dg/countof-compile.c  (test for errors, line 87)
+PASS: gcc.dg/countof-compile.c  (test for errors, line 88)
+PASS: gcc.dg/countof-compile.c  (test for warnings, line 92)
+PASS: gcc.dg/countof-compile.c  (test for errors, line 112)
+PASS: gcc.dg/countof-compile.c  (test for errors, line 121)
+PASS: gcc.dg/countof-compile.c  (test for errors, line 126)
+PASS: gcc.dg/countof-compile.c (test for excess errors)
+PASS: gcc.dg/countof-vla.c (test for excess errors)
+PASS: gcc.dg/countof.c (test for excess errors)
+PASS: gcc.dg/countof.c execution test
 PASS: gcc.dg/cr-decimal-dig-1.c (test for excess errors)
 PASS: gcc.dg/cr-decimal-dig-2.c (test for excess errors)
 PASS: gcc.dg/cr-decimal-dig-3.c (test for excess errors)
@@ -208690,7 +208714,7 @@
 
 		=== gcc Summary ===
 
-# of expected passes		203598
+# of expected passes		203622
 # of unexpected failures	37
 # of unexpected successes	2
 # of expected failures		1471
--- ../len17_b4/./gcc/testsuite/gfortran/gfortran.sum	2024-10-20 23:07:39.361276662 +0200
+++ ./gcc/testsuite/gfortran/gfortran.sum	2024-10-22 14:45:01.978602257 +0200
@@ -1,4 +1,4 @@
-Test run by alx on Sun Oct 20 22:32:36 2024
+Test run by alx on Tue Oct 22 14:10:06 2024
 Native configuration is x86_64-pc-linux-gnu
 
 		=== gfortran tests ===
--- ../len17_b4/./gcc/testsuite/objc/objc.sum	2024-10-20 23:08:46.517872353 +0200
+++ ./gcc/testsuite/objc/objc.sum	2024-10-22 14:46:08.167200761 +0200
@@ -1,4 +1,4 @@
-Test run by alx on Sun Oct 20 23:07:39 2024
+Test run by alx on Tue Oct 22 14:45:02 2024
 Native configuration is x86_64-pc-linux-gnu
 
 		=== objc tests ===
--- ../len17_b4/./gcc/testsuite/g++/g++.sum	2024-10-20 22:32:35.602258071 +0200
+++ ./gcc/testsuite/g++/g++.sum	2024-10-22 14:10:05.487527382 +0200
@@ -1,4 +1,4 @@
-Test run by alx on Sun Oct 20 21:28:04 2024
+Test run by alx on Tue Oct 22 13:06:19 2024
 Native configuration is x86_64-pc-linux-gnu
 
 		=== g++ tests ===
--- ../len17_b4/./x86_64-pc-linux-gnu/libitm/testsuite/libitm.sum	2024-10-21 02:34:25.906785565 +0200
+++ ./x86_64-pc-linux-gnu/libitm/testsuite/libitm.sum	2024-10-22 18:13:10.216200995 +0200
@@ -1,4 +1,4 @@
-Test run by alx on Mon Oct 21 02:34:23 2024
+Test run by alx on Tue Oct 22 18:13:08 2024
 Native configuration is x86_64-pc-linux-gnu
 
 		=== libitm tests ===
--- ../len17_b4/./x86_64-pc-linux-gnu/libgomp/testsuite/libgomp.sum	2024-10-21 02:34:23.258761608 +0200
+++ ./x86_64-pc-linux-gnu/libgomp/testsuite/libgomp.sum	2024-10-22 18:13:07.608178686 +0200
@@ -1,4 +1,4 @@
-Test run by alx on Mon Oct 21 02:20:07 2024
+Test run by alx on Tue Oct 22 17:58:52 2024
 Native configuration is x86_64-pc-linux-gnu
 
 		=== libgomp tests ===
--- ../len17_b4/./x86_64-pc-linux-gnu/libatomic/testsuite/libatomic.sum2024-10-21 02:34:28.354807711 +0200
+++ ./x86_64-pc-linux-gnu/libatomic/testsuite/libatomic.sum	2024-10-22 18:13:12.560221047 +0200
@@ -1,4 +1,4 @@
-Test run by alx on Mon Oct 21 02:34:26 2024
+Test run by alx on Tue Oct 22 18:13:10 2024
 Native configuration is x86_64-pc-linux-gnu
 
 		=== libatomic tests ===
--- ../len17_b4/./x86_64-pc-linux-gnu/libstdc++-v3/testsuite/libstdc++.sum	2024-10-21 02:19:44.922761161 +0200
+++ ./x86_64-pc-linux-gnu/libstdc++-v3/testsuite/libstdc++.sum	2024-10-22 17:58:29.992819146 +0200
@@ -1,4 +1,4 @@
-Test run by alx on Sun Oct 20 23:09:16 2024
+Test run by alx on Tue Oct 22 14:46:37 2024
 Native configuration is x86_64-pc-linux-gnu
 
 		=== libstdc++ tests ===



> 
> 
> v17 changes:
> 
> -  Rebase (patches 2/4 and 3/4 from v16b have been merged already).
> -  Improve and add tests.
> 
> Below is the range diff against v16b.
> 
> 
> Have a lovely night!
> Alex
> 
> Alejandro Colomar (2):
>   contrib/: Add support for Cc: and Link: tags
>   c: Add __countof__ operator
> 
>  contrib/gcc-changelog/git_commit.py    |   5 +-
>  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                        |  22 +++-
>  gcc/c/c-parser.cc                      |  62 +++++++---
>  gcc/c/c-tree.h                         |   4 +
>  gcc/c/c-typeck.cc                      | 118 ++++++++++++++++++-
>  gcc/doc/extend.texi                    |  30 +++++
>  gcc/testsuite/gcc.dg/countof-compile.c | 127 +++++++++++++++++++++
>  gcc/testsuite/gcc.dg/countof-vla.c     |  46 ++++++++
>  gcc/testsuite/gcc.dg/countof.c         | 150 +++++++++++++++++++++++++
>  12 files changed, 570 insertions(+), 25 deletions(-)
>  create mode 100644 gcc/testsuite/gcc.dg/countof-compile.c
>  create mode 100644 gcc/testsuite/gcc.dg/countof-vla.c
>  create mode 100644 gcc/testsuite/gcc.dg/countof.c
> 
> Range-diff against v16b:
> 1:  eac2d18d8a0 = 1:  d847dc4a795 contrib/: Add support for Cc: and Link: tags
> 2:  7418a11fcd6 < -:  ----------- gcc/: Rename array_type_nelts => array_type_nelts_minus_one
> 3:  0cfae0598b3 < -:  ----------- gcc/: Merge definitions of array_type_nelts_top
> 4:  12a30a2a6fd ! 2:  936f7945fae c: Add __countof__ operator
>     @@ gcc/testsuite/gcc.dg/countof-compile.c (new)
>      +static int y[__countof__(z)];
>      +
>      +void
>     -+automatic(void)
>     ++completed (void)
>      +{
>     -+  __countof__ (w);
>     ++  int i = 42;
>     ++  int a[] = {1, 2, i};
>     ++
>     ++  _Static_assert(__countof__ (w) == 3);
>     ++  __countof__ (a);
>      +}
>      +
>      +void
>     @@ gcc/testsuite/gcc.dg/countof-compile.c (new)
>      +{
>      +  __countof__ (x);  /* { dg-error "incomplete" } */
>      +
>     -+  /* We want to support the following one in the future,
>     -+     but for now it should fail.  */
>     ++  /* We want to support array parameters in the future,
>     ++     which should change this from "invalid" to "incomplete".  */
>      +  __countof__ (p);  /* { dg-error "invalid" } */
>      +}
>      +
>     @@ gcc/testsuite/gcc.dg/countof-compile.c (new)
>      +  __countof__ (s.fam); /* { dg-error "incomplete" } */
>      +}
>      +
>     ++void
>     ++param (int n, int p[n])
>     ++{
>     ++  /* We want to support array parameters in the future,
>     ++     which would make this work.  */
>     ++  __countof__ (p);  /* { dg-error "invalid" } */
>     ++}
>     ++
>      +void fix_fix (int i, char (*a)[3][5], int (*x)[__countof__ (*a)]);
>      +void fix_var (int i, char (*a)[3][i], int (*x)[__countof__ (*a)]);
>      +void fix_uns (int i, char (*a)[3][*], int (*x)[__countof__ (*a)]);
> 
> -- 
> 2.45.2
> 



-- 
<https://www.alejandro-colomar.es/>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 318+ messages in thread

* Re: [PATCH v17 2/2] c: Add __countof__ operator
  2024-10-22 18:48     ` [PATCH v17 2/2] c: Add __countof__ operator Alejandro Colomar
@ 2024-10-25 20:44       ` Joseph Myers
  2024-10-25 22:10         ` Alejandro Colomar
  0 siblings, 1 reply; 318+ messages in thread
From: Joseph Myers @ 2024-10-25 20:44 UTC (permalink / raw)
  To: Alejandro Colomar; +Cc: gcc-patches

I don't see the use of pedwarn_c23 and associated tests (error with 
-std=c23 -pedantic-errors, warning with -std=c23 -pedantic, no diagnostic 
with -std=c23 -pedantic-errors -Wno-c23-c2y-compat, no diagnostic with 
-std=c2y -pedantic-errors, warning with -std=c2y -pedantic-errors 
-Wc23-c2y-compat), previously discussed in comments on v13, that would be 
appropriate before considering this for inclusion with an appropriate 
substitution of names.

-- 
Joseph S. Myers
josmyers@redhat.com


^ permalink raw reply	[flat|nested] 318+ messages in thread

* Re: [PATCH v17 2/2] c: Add __countof__ operator
  2024-10-25 20:44       ` Joseph Myers
@ 2024-10-25 22:10         ` Alejandro Colomar
  2024-11-08 14:00           ` Alejandro Colomar
  0 siblings, 1 reply; 318+ messages in thread
From: Alejandro Colomar @ 2024-10-25 22:10 UTC (permalink / raw)
  To: Joseph Myers; +Cc: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 1094 bytes --]

Hi Joseph,

On Fri, Oct 25, 2024 at 08:44:15PM GMT, Joseph Myers wrote:
> I don't see the use of pedwarn_c23 and associated tests (error with 
> -std=c23 -pedantic-errors, warning with -std=c23 -pedantic, no diagnostic 
> with -std=c23 -pedantic-errors -Wno-c23-c2y-compat, no diagnostic with 
> -std=c2y -pedantic-errors, warning with -std=c2y -pedantic-errors 
> -Wc23-c2y-compat), previously discussed in comments on v13, that would be 
> appropriate before considering this for inclusion with an appropriate 
> substitution of names.

I removed it because I renamed it to __countof__, which is a GNU
extension, and thus should not be warned by -Wpedantic.  As part of my
opposition to _Lengthof, I will not provide you with that part, which
would amount to basically giving you _Lengthof but not.  As part of the
editorialising process, you'll also have to add pedantic warnings, if
that's what you want to do.  Again, I will earnestly ask to once more to
consider __countof__, but it's up to you.

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] 318+ messages in thread

* Re: [PATCH v17 2/2] c: Add __countof__ operator
  2024-10-25 22:10         ` Alejandro Colomar
@ 2024-11-08 14:00           ` Alejandro Colomar
  2024-11-08 15:51             ` Joseph Myers
  0 siblings, 1 reply; 318+ messages in thread
From: Alejandro Colomar @ 2024-11-08 14:00 UTC (permalink / raw)
  To: Joseph Myers; +Cc: gcc-patches, JeanHeyd Meneide

[-- Attachment #1: Type: text/plain, Size: 1383 bytes --]

Hi Joseph,

This is a gentle ping about this patch set, 10 days before the start of
stage 3.

Have a lovely day!
Alex

On Sat, Oct 26, 2024 at 12:10:56AM GMT, Alejandro Colomar wrote:
> Hi Joseph,
> 
> On Fri, Oct 25, 2024 at 08:44:15PM GMT, Joseph Myers wrote:
> > I don't see the use of pedwarn_c23 and associated tests (error with 
> > -std=c23 -pedantic-errors, warning with -std=c23 -pedantic, no diagnostic 
> > with -std=c23 -pedantic-errors -Wno-c23-c2y-compat, no diagnostic with 
> > -std=c2y -pedantic-errors, warning with -std=c2y -pedantic-errors 
> > -Wc23-c2y-compat), previously discussed in comments on v13, that would be 
> > appropriate before considering this for inclusion with an appropriate 
> > substitution of names.
> 
> I removed it because I renamed it to __countof__, which is a GNU
> extension, and thus should not be warned by -Wpedantic.  As part of my
> opposition to _Lengthof, I will not provide you with that part, which
> would amount to basically giving you _Lengthof but not.  As part of the
> editorialising process, you'll also have to add pedantic warnings, if
> that's what you want to do.  Again, I will earnestly ask to once more to
> consider __countof__, but it's up to you.
> 
> Have a lovely night!
> 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] 318+ messages in thread

* Re: [PATCH v17 2/2] c: Add __countof__ operator
  2024-11-08 14:00           ` Alejandro Colomar
@ 2024-11-08 15:51             ` Joseph Myers
  0 siblings, 0 replies; 318+ messages in thread
From: Joseph Myers @ 2024-11-08 15:51 UTC (permalink / raw)
  To: Alejandro Colomar; +Cc: gcc-patches, JeanHeyd Meneide

On Fri, 8 Nov 2024, Alejandro Colomar wrote:

> Hi Joseph,
> 
> This is a gentle ping about this patch set, 10 days before the start of
> stage 3.

It's obviously not ready to include in its current form (using a name 
different from that actually accepted into C2Y).  Since it requires 
significant work to get it into a form corresponding to the actual C2Y 
feature and you've said you won't do that work, it's a very low priority 
for any kind of review at all compared to any submissions whose authors 
are willing to adapt them following review to be ready for inclusion.  
Name changes could be considered in a later development stage if there 
were a decision to change the name in Graz, but that requires a suitable 
submission while new features are under consideration for GCC 15.

-- 
Joseph S. Myers
josmyers@redhat.com


^ permalink raw reply	[flat|nested] 318+ messages in thread

* [PATCH v18 0/2] c: Add __countof__ operator
  2024-07-28 14:15 ` [RFC v1 0/2] c: Add _Lengthof operator Alejandro Colomar
                     ` (21 preceding siblings ...)
  2024-10-22 18:48   ` [PATCH v17 0/2] " Alejandro Colomar
@ 2024-11-10 10:32   ` Alejandro Colomar
  2024-11-10 10:32     ` [PATCH v18 1/2] contrib/: Add support for Cc: and Link: tags Alejandro Colomar
                       ` (3 more replies)
  2025-05-11 14:11   ` [PATCH v20 0/4] c: Add _Countof and <stdcountof.h> Alejandro Colomar
                     ` (5 subsequent siblings)
  28 siblings, 4 replies; 318+ messages in thread
From: Alejandro Colomar @ 2024-11-10 10:32 UTC (permalink / raw)
  To: gcc-patches; +Cc: Alejandro Colomar, Martin Uecker, JeanHeyd Meneide

[-- Attachment #1: Type: text/plain, Size: 5093 bytes --]

Hi!

Your favourite operator with the most controversial name comes back with
support for [0], thanks to Martin Uecker.  In movie theaters, and
probably in GCC 16.

For those who fight in a side in the name wars, here's a reminder of a
fair survey (by JeanHeyd) which might end the war with a peace treaty:
<https://thephd.dev/the-big-array-size-survey-for-c>.


Changes since v17:

-  Rebase after the recent patches added by Martin, which made [0][n]
   and [*][n] have distinct representation, and thus allowed making
   __countof__(int [0][n]) be a constant expression.

-  Make __countof__(int [0][n]) a constant expression.  Thanks, Martin!
   Update the testsuite to reflect this too, of course.

-  Rename small function in the testsuite (automatic => completed).

See the range-diff below for the exact differences since v17.


Martin, this worked out of the box.  I'll reply to this email with the
regression-test session results; they all passed.  [0] works like a
charm.


Have a lovely day!
Alex


Alejandro Colomar (2):
  contrib/: Add support for Cc: and Link: tags
  c: Add __countof__ operator

 contrib/gcc-changelog/git_commit.py    |   5 +-
 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                        |  22 +++-
 gcc/c/c-parser.cc                      |  62 +++++++---
 gcc/c/c-tree.h                         |   4 +
 gcc/c/c-typeck.cc                      | 115 ++++++++++++++++++-
 gcc/doc/extend.texi                    |  30 +++++
 gcc/testsuite/gcc.dg/countof-compile.c | 125 +++++++++++++++++++++
 gcc/testsuite/gcc.dg/countof-vla.c     |  45 ++++++++
 gcc/testsuite/gcc.dg/countof.c         | 150 +++++++++++++++++++++++++
 12 files changed, 564 insertions(+), 25 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/countof-compile.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-vla.c
 create mode 100644 gcc/testsuite/gcc.dg/countof.c

Range-diff against v17:
1:  d847dc4a795 = 1:  82100c813c3 contrib/: Add support for Cc: and Link: tags
2:  936f7945fae ! 2:  f8336e4646a c: Add __countof__ operator
    @@ Commit message
            and somehow magically return the number of elements of the array,
            regardless of it being really a pointer.
     
    -    -  Fix support for [0].
    -
         gcc/ChangeLog:
     
                 * doc/extend.texi: Document __countof__ operator.
    @@ gcc/c/c-decl.cc: finish_enum (tree enumtype, tree values, tree attributes)
     
      ## gcc/c/c-parser.cc ##
     @@ gcc/c/c-parser.cc: along with GCC; see the file COPYING3.  If not see
    - #include "bitmap.h"
    - #include "analyzer/analyzer-language.h"
      #include "toplev.h"
    + #include "asan.h"
    + #include "c-family/c-ubsan.h"
     +\f
     +#define c_parser_sizeof_expression(parser)                                    \
     +(                                                                             \
    @@ 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, star, var;
    ++  bool zero, 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);
    -+  star = (zero && C_TYPE_VARIABLE_SIZE (type));
    -+  if (star)
    -+    return true;
     +  if (zero)
     +    return false;
     +
    @@ gcc/testsuite/gcc.dg/countof-compile.c (new)
     +  _Static_assert (__countof__ (int [n][3]) == 7); /* { dg-error "not constant" } */
     +  _Static_assert (__countof__ (int [0][3]) == 0);
     +  _Static_assert (__countof__ (int [0]) == 0);
    -+
    -+  /* FIXME: countof(int [0][n]) should result in a constant expression.  */
    -+  _Static_assert (__countof__ (int [0][n]) == 0); /* { dg-error "not constant" } */
    ++  _Static_assert (__countof__ (int [0][n]) == 0);
     +}
     
      ## gcc/testsuite/gcc.dg/countof-vla.c (new) ##
    @@ gcc/testsuite/gcc.dg/countof-vla.c (new)
     +	      char (*a)[*][*],
     +	      int (*x)[__countof__ (*a)]);
     +
    -+// Can't test due to bug: <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=116284>
    -+//static int z2[0];
    -+//static int y2[__countof__(z2)];
    ++static int z2[0];
    ++static int y2[__countof__(z2)];
     
      ## gcc/testsuite/gcc.dg/countof.c (new) ##
     @@
    @@ gcc/testsuite/gcc.dg/countof.c (new)
     +}
     +
     +void
    -+automatic(void)
    ++completed (void)
     +{
     +  int a[] = {1, 2, 3};
     +  int z[] = {};
    @@ gcc/testsuite/gcc.dg/countof.c (new)
     +main (void)
     +{
     +  array ();
    -+  automatic ();
    ++  completed ();
     +  vla ();
     +  member ();
     +  vla_eval ();

base-commit: 9cbcf8d1de159e6113fafb5dc2feb4a7e467a302
-- 
2.45.2


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 318+ messages in thread

* [PATCH v18 1/2] contrib/: Add support for Cc: and Link: tags
  2024-11-10 10:32   ` [PATCH v18 " Alejandro Colomar
@ 2024-11-10 10:32     ` Alejandro Colomar
  2024-11-10 10:32     ` [PATCH v18 2/2] c: Add __countof__ operator Alejandro Colomar
                       ` (2 subsequent siblings)
  3 siblings, 0 replies; 318+ messages in thread
From: Alejandro Colomar @ 2024-11-10 10:32 UTC (permalink / raw)
  To: gcc-patches; +Cc: Alejandro Colomar, Martin Uecker, JeanHeyd Meneide

[-- Attachment #1: Type: text/plain, Size: 1258 bytes --]

contrib/ChangeLog:

	* gcc-changelog/git_commit.py (GitCommit):
	Add support for 'Cc: ' and 'Link: ' tags.

Cc: Jason Merrill <jason@redhat.com>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
---
 contrib/gcc-changelog/git_commit.py | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/contrib/gcc-changelog/git_commit.py b/contrib/gcc-changelog/git_commit.py
index 87ecb9e1a17..64fb986b74c 100755
--- a/contrib/gcc-changelog/git_commit.py
+++ b/contrib/gcc-changelog/git_commit.py
@@ -182,7 +182,8 @@ CO_AUTHORED_BY_PREFIX = 'co-authored-by: '
 
 REVIEW_PREFIXES = ('reviewed-by: ', 'reviewed-on: ', 'signed-off-by: ',
                    'acked-by: ', 'tested-by: ', 'reported-by: ',
-                   'suggested-by: ')
+                   'suggested-by: ', 'cc: ')
+LINK_PREFIXES = ('link: ')
 DATE_FORMAT = '%Y-%m-%d'
 
 
@@ -524,6 +525,8 @@ class GitCommit:
                     continue
                 elif lowered_line.startswith(REVIEW_PREFIXES):
                     continue
+                elif lowered_line.startswith(LINK_PREFIXES):
+                    continue
                 else:
                     m = cherry_pick_regex.search(line)
                     if m:
-- 
2.45.2


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 318+ messages in thread

* [PATCH v18 2/2] c: Add __countof__ operator
  2024-11-10 10:32   ` [PATCH v18 " Alejandro Colomar
  2024-11-10 10:32     ` [PATCH v18 1/2] contrib/: Add support for Cc: and Link: tags Alejandro Colomar
@ 2024-11-10 10:32     ` Alejandro Colomar
  2024-11-10 10:34     ` [PATCH v18 0/2] " Alejandro Colomar
  2024-11-10 13:47     ` Martin Uecker
  3 siblings, 0 replies; 318+ messages in thread
From: Alejandro Colomar @ 2024-11-10 10:32 UTC (permalink / raw)
  To: gcc-patches; +Cc: Alejandro Colomar, Martin Uecker, JeanHeyd Meneide

[-- Attachment #1: Type: text/plain, Size: 29801 bytes --]

This operator is similar to sizeof but can only be applied to an array,
and returns its number of elements.

FUTURE DIRECTIONS:

-  We should make it work with array parameters to functions,
   and somehow magically return the number of elements of the array,
   regardless of it being really a pointer.

gcc/ChangeLog:

	* doc/extend.texi: Document __countof__ operator.

gcc/c-family/ChangeLog:

	* c-common.h
	* c-common.def
	* c-common.cc (c_countof_type): Add __countof__ operator.

gcc/c/ChangeLog:

	* c-tree.h
	(c_expr_countof_expr, c_expr_countof_type)
	* c-decl.cc
	(start_struct, finish_struct)
	(start_enum, finish_enum)
	* c-parser.cc
	(c_parser_sizeof_expression)
	(c_parser_countof_expression)
	(c_parser_sizeof_or_countof_expression)
	(c_parser_unary_expression)
	* c-typeck.cc
	(build_external_ref)
	(record_maybe_used_decl)
	(pop_maybe_used)
	(is_top_array_vla)
	(c_expr_countof_expr, c_expr_countof_type):
	Add __countof__ operator.

gcc/testsuite/ChangeLog:

	* gcc.dg/countof-compile.c
	* gcc.dg/countof-vla.c
	* gcc.dg/countof.c: Add tests for __countof__ operator.

Link: <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117025>
Link: <https://inbox.sourceware.org/gcc/M8S4oQy--3-2@tutanota.com/T/>
Link: <https://inbox.sourceware.org/gcc-patches/20240728141547.302478-1-alx@kernel.org/T/#t>
Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3313.pdf>
Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3325.pdf>
Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3369.pdf>
Link: <https://github.com/llvm/llvm-project/issues/102836>
Link: <https://stackoverflow.com/questions/37538/#57537491>
Suggested-by: Xavier Del Campo Romero <xavi.dcr@tutanota.com>
Co-authored-by: Martin Uecker <uecker@tugraz.at>
Acked-by: "James K. Lowden" <jklowden@schemamania.org>
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>
Cc: Daniel Plakosh <dplakosh@cert.org>
Cc: "A. Jiang" <de34@live.cn>
Cc: Eugene Zelenko <eugene.zelenko@gmail.com>
Cc: Aaron Ballman <aaron.ballman@intel.com>
Cc: Paul Koning <paulkoning@comcast.net>
Cc: Daniel Lundin <daniel.lundin.mail@gmail.com>
Cc: Nikolaos Strimpas <Strnik86@protonmail.com>
Cc: JeanHeyd Meneide <phdofthehouse@gmail.com>
Cc: Fernando Borretti <fernando@borretti.me>
Cc: Jonathan Protzenko <jonathan.protzenko@ens-lyon.org>
Cc: Chris Bazley <Chris.Bazley@arm.com>
Cc: Ville Voutilainen <ville.voutilainen@gmail.com>
Cc: Alex Celeste <alexg.nvfp@gmail.com>
Cc: Jakub Łukasiewicz <jakublukasiewicz@outlook.com>
Cc: Douglas McIlroy <douglas.mcilroy@dartmouth.edu>
Cc: Jason Merrill <jason@redhat.com>
Cc: "Gustavo A. R. Silva" <gustavoars@kernel.org>
Cc: Patrizia Kaye <patrizia@ethernull.org>
Cc: Ori Bernstein <ori@eigenstate.org>
Cc: Robert Seacord <rcseacord@gmail.com>
Cc: Marek Polacek <mpolacek@gcc.gnu.org>
Cc: Sam James <sam@gentoo.org>
Cc: Richard Biener <richard.guenther@gmail.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                        |  22 +++-
 gcc/c/c-parser.cc                      |  62 +++++++---
 gcc/c/c-tree.h                         |   4 +
 gcc/c/c-typeck.cc                      | 115 ++++++++++++++++++-
 gcc/doc/extend.texi                    |  30 +++++
 gcc/testsuite/gcc.dg/countof-compile.c | 125 +++++++++++++++++++++
 gcc/testsuite/gcc.dg/countof-vla.c     |  45 ++++++++
 gcc/testsuite/gcc.dg/countof.c         | 150 +++++++++++++++++++++++++
 11 files changed, 560 insertions(+), 24 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/countof-compile.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-vla.c
 create mode 100644 gcc/testsuite/gcc.dg/countof.c

diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
index 06be2a37b4f..77bf8e84847 100644
--- a/gcc/c-family/c-common.cc
+++ b/gcc/c-family/c-common.cc
@@ -469,6 +469,7 @@ const struct c_common_resword c_common_reswords[] =
   { "__inline",		RID_INLINE,	0 },
   { "__inline__",	RID_INLINE,	0 },
   { "__label__",	RID_LABEL,	0 },
+  { "__countof__",	RID_COUNTOF,	0 },
   { "__null",		RID_NULL,	0 },
   { "__real",		RID_REALPART,	0 },
   { "__real__",		RID_REALPART,	0 },
@@ -4074,6 +4075,31 @@ c_alignof_expr (location_t loc, tree expr)
 
   return fold_convert_loc (loc, size_type_node, t);
 }
+
+/* Implement the countof keyword:
+   Return the number of elements of an array.  */
+
+tree
+c_countof_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 %<__countof__%> to type %qT", type);
+      return error_mark_node;
+    }
+  if (!COMPLETE_TYPE_P (type))
+    {
+      error_at (loc,
+		"invalid application of %<__countof__%> 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 dc49ad09e2f..f2ae784cefe 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 'countof' expression.  */
+DEFTREECODE (COUNTOF_EXPR, "countof_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 46099b63514..ba0d5a68f0f 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_COUNTOF,
   RID_VA_ARG,
   RID_EXTENSION, RID_IMAGPART, RID_REALPART, RID_LABEL,    RID_CHOOSE_EXPR,
   RID_TYPES_COMPATIBLE_P,      RID_BUILTIN_COMPLEX,	   RID_BUILTIN_SHUFFLE,
@@ -889,6 +890,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_countof_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 ac47ef24a3d..7ab69e6c158 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -8951,12 +8951,17 @@ 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_countof))
     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"
+		       : "__countof__"))));
 
   if (in_underspecified_init)
     error_at (loc, "%qT defined in underspecified object initializer", ref);
@@ -9928,7 +9933,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_countof)
 	struct_parse_info->struct_types.safe_push (t);
      }
 
@@ -10102,12 +10107,17 @@ 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_countof))
     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"
+		       : "__countof__"))));
 
   if (in_underspecified_init)
     error_at (loc, "%qT defined in underspecified object initializer",
@@ -10301,7 +10311,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_countof)
     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 3ab8a49bf35..a787152ab0a 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -76,7 +76,17 @@ along with GCC; see the file COPYING3.  If not see
 #include "toplev.h"
 #include "asan.h"
 #include "c-family/c-ubsan.h"
+\f
+#define c_parser_sizeof_expression(parser)                                    \
+(                                                                             \
+  c_parser_sizeof_or_countof_expression (parser, RID_SIZEOF)                  \
+)
 
+#define c_parser_countof_expression(parser)                                   \
+(                                                                             \
+  c_parser_sizeof_or_countof_expression (parser, RID_COUNTOF)                 \
+)
+\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
@@ -1697,7 +1707,8 @@ 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_countof_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 *,
@@ -10328,6 +10339,8 @@ c_parser_unary_expression (c_parser *parser)
     case CPP_KEYWORD:
       switch (c_parser_peek_token (parser)->keyword)
 	{
+	case RID_COUNTOF:
+	  return c_parser_countof_expression (parser);
 	case RID_SIZEOF:
 	  return c_parser_sizeof_expression (parser);
 	case RID_ALIGNOF:
@@ -10367,12 +10380,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_countof_expression (c_parser *parser, enum rid rid)
 {
+  const char *op_name = (rid == RID_COUNTOF) ? "__countof__" : "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;
@@ -10381,7 +10395,10 @@ c_parser_sizeof_expression (c_parser *parser)
 
   c_parser_consume_token (parser);
   c_inhibit_evaluation_warnings++;
-  in_sizeof++;
+  if (rid == RID_COUNTOF)
+    in_countof++;
+  else
+    in_sizeof++;
   if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)
       && c_token_starts_compound_literal (c_parser_peek_2nd_token (parser)))
     {
@@ -10400,7 +10417,10 @@ c_parser_sizeof_expression (c_parser *parser)
 	{
 	  struct c_expr ret;
 	  c_inhibit_evaluation_warnings--;
-	  in_sizeof--;
+	  if (rid == RID_COUNTOF)
+	    in_countof--;
+	  else
+	    in_sizeof--;
 	  ret.set_error ();
 	  ret.original_code = ERROR_MARK;
 	  ret.original_type = NULL;
@@ -10412,31 +10432,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_COUNTOF)
+	{
+	  in_countof--;
+	  result = c_expr_countof_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_COUNTOF)
+	in_countof--;
+      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_COUNTOF)
+	result = c_expr_countof_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 f6bcbabb9d5..f6030eb99b3 100644
--- a/gcc/c/c-tree.h
+++ b/gcc/c/c-tree.h
@@ -764,6 +764,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_countof;
 extern int in_typeof;
 extern bool c_in_omp_for;
 extern bool c_omp_array_section_p;
@@ -825,6 +826,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_countof_expr (location_t, struct c_expr);
+extern struct c_expr c_expr_countof_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 201d75d2e9c..188ac4f54db 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -72,6 +72,9 @@ int in_alignof;
 /* The level of nesting inside "sizeof".  */
 int in_sizeof;
 
+/* The level of nesting inside "countof".  */
+int in_countof;
+
 /* The level of nesting inside "typeof".  */
 int in_typeof;
 
@@ -3479,7 +3482,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_countof)
 	C_DECL_USED (ref) = 1;
       else if (DECL_INITIAL (ref) == NULL_TREE
 	       && DECL_EXTERNAL (ref)
@@ -3535,7 +3538,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_countof).  */
   int level;
   /* The next one at this level or above, or NULL.  */
   struct maybe_used_decl *next;
@@ -3553,7 +3556,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_countof;
   t->next = maybe_used_decls;
   maybe_used_decls = t;
 }
@@ -3567,7 +3570,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_countof;
   while (p && p->level > cur_level)
     {
       if (used)
@@ -3677,6 +3680,110 @@ 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);
+  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 countof applied to EXPR.  */
+
+struct c_expr
+c_expr_countof_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_countof_type (loc, TREE_TYPE (folded_expr));
+      c_last_sizeof_arg = expr.value;
+      c_last_sizeof_loc = loc;
+      ret.original_code = COUNTOF_EXPR;
+      ret.original_type = NULL;
+      ret.m_decimal = 0;
+      if (is_top_array_vla (TREE_TYPE (folded_expr)))
+	{
+	  /* countof 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 countof applied to T, a structure for the type
+   name passed to countof (rather than the type itself).  LOC is the
+   location of the original expression.  */
+
+struct c_expr
+c_expr_countof_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_countof_type (loc, type);
+  c_last_sizeof_arg = type;
+  c_last_sizeof_loc = loc;
+  ret.original_code = COUNTOF_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 countof does not get folded to a constant by
+	 c_fully_fold, because if the number of elements is evaluated
+	 the result is not constant and so
+	 constraints on zero or negative size arrays must not be applied
+	 when this countof 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/doc/extend.texi b/gcc/doc/extend.texi
index 5902e76f043..139e1198f55 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -10585,6 +10585,36 @@ 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 __countof__
+@section Determining the Number of Elements of Arrays
+@cindex __countof__
+@cindex number of elements
+
+The keyword @code{__countof__} determines
+the number of elements of an array operand.
+Its syntax is similar to @code{sizeof}.
+The operand must be
+a parenthesized complete array type name
+or an expression of such a type.
+For example:
+
+@smallexample
+int a[n];
+__countof__ (a);  // returns n
+__countof__ (int [7][3]);  // returns 7
+@end smallexample
+
+The result of this operator is an integer constant expression,
+unless the array has a variable number of elements.
+The operand is only evaluated
+if the array has a variable number of elements.
+For example:
+
+@smallexample
+__countof__ (int [7][n++]);  // integer constant expression
+__countof__ (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/testsuite/gcc.dg/countof-compile.c b/gcc/testsuite/gcc.dg/countof-compile.c
new file mode 100644
index 00000000000..0060064cb3a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/countof-compile.c
@@ -0,0 +1,125 @@
+/* { 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[__countof__(z)];
+
+void
+completed (void)
+{
+  int i = 42;
+  int a[] = {1, 2, i};
+
+  _Static_assert(__countof__ (w) == 3);
+  __countof__ (a);
+}
+
+void
+incomplete (int p[])
+{
+  __countof__ (x);  /* { dg-error "incomplete" } */
+
+  /* We want to support array parameters in the future,
+     which should change this from "invalid" to "incomplete".  */
+  __countof__ (p);  /* { dg-error "invalid" } */
+}
+
+void
+fam (void)
+{
+  struct {
+    int x;
+    int fam[];
+  } s;
+
+  __countof__ (s.fam); /* { dg-error "incomplete" } */
+}
+
+void
+param (int n, int p[n])
+{
+  /* We want to support array parameters in the future,
+     which would make this work.  */
+  __countof__ (p);  /* { dg-error "invalid" } */
+}
+
+void fix_fix (int i, char (*a)[3][5], int (*x)[__countof__ (*a)]);
+void fix_var (int i, char (*a)[3][i], int (*x)[__countof__ (*a)]);
+void fix_uns (int i, char (*a)[3][*], int (*x)[__countof__ (*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;
+
+  __countof__ (x); /* { dg-error "invalid" } */
+  __countof__ (int); /* { dg-error "invalid" } */
+  __countof__ (s); /* { dg-error "invalid" } */
+  __countof__ (struct s); /* { dg-error "invalid" } */
+  __countof__ (&x); /* { dg-error "invalid" } */
+  __countof__ (p); /* { dg-error "invalid" } */
+  __countof__ (int *); /* { dg-error "invalid" } */
+  __countof__ (&s.x); /* { dg-error "invalid" } */
+  __countof__ (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];
+
+  __countof__ (a[f1()]);
+  __countof__ (b[f2()]);
+}
+
+void
+no_parens(void)
+{
+  __countof__ a;
+  __countof__ *a;
+  __countof__ (int [3]) {};
+
+  __countof__ int [3]; /* { dg-error "expected expression before" } */
+}
+
+void
+const_expr(void)
+{
+  int n = 7;
+
+  _Static_assert (__countof__ (int [3][n]) == 3);
+  _Static_assert (__countof__ (int [n][3]) == 7); /* { dg-error "not constant" } */
+  _Static_assert (__countof__ (int [0][3]) == 0);
+  _Static_assert (__countof__ (int [0]) == 0);
+  _Static_assert (__countof__ (int [0][n]) == 0);
+}
diff --git a/gcc/testsuite/gcc.dg/countof-vla.c b/gcc/testsuite/gcc.dg/countof-vla.c
new file mode 100644
index 00000000000..01b04d5174a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/countof-vla.c
@@ -0,0 +1,45 @@
+/* { dg-do compile } */
+/* { dg-options "-Wno-pedantic -Wvla-parameter" } */
+
+void fix_fix (int i,
+	      char (*a)[3][5],
+	      int (*x)[__countof__ (*a)]);
+void fix_var (int i,
+	      char (*a)[3][i], /* dg-warn "variable" */
+	      int (*x)[__countof__ (*a)]);
+void fix_uns (int i,
+	      char (*a)[3][*],
+	      int (*x)[__countof__ (*a)]);
+
+void zro_fix (int i,
+	      char (*a)[0][5],
+	      int (*x)[__countof__ (*a)]);
+void zro_var (int i,
+	      char (*a)[0][i], /* dg-warn "variable" */
+	      int (*x)[__countof__ (*a)]);
+void zro_uns (int i,
+	      char (*a)[0][*],
+	      int (*x)[__countof__ (*a)]);
+
+void var_fix (int i,
+	      char (*a)[i][5], /* dg-warn "variable" */
+	      int (*x)[__countof__ (*a)]); /* dg-warn "variable" */
+void var_var (int i,
+	      char (*a)[i][i], /* dg-warn "variable" */
+	      int (*x)[__countof__ (*a)]); /* dg-warn "variable" */
+void var_uns (int i,
+	      char (*a)[i][*], /* dg-warn "variable" */
+	      int (*x)[__countof__ (*a)]); /* dg-warn "variable" */
+
+void uns_fix (int i,
+	      char (*a)[*][5],
+	      int (*x)[__countof__ (*a)]);
+void uns_var (int i,
+	      char (*a)[*][i], /* dg-warn "variable" */
+	      int (*x)[__countof__ (*a)]);
+void uns_uns (int i,
+	      char (*a)[*][*],
+	      int (*x)[__countof__ (*a)]);
+
+static int z2[0];
+static int y2[__countof__(z2)];
diff --git a/gcc/testsuite/gcc.dg/countof.c b/gcc/testsuite/gcc.dg/countof.c
new file mode 100644
index 00000000000..dfd117bc8e7
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/countof.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 (__countof__ (a) == 7);
+  static_assert (__countof__ (long [0]) == 0);
+  static_assert (__countof__ (unsigned [99]) == 99);
+}
+
+void
+completed (void)
+{
+  int a[] = {1, 2, 3};
+  int z[] = {};
+
+  static_assert (__countof__ (a) == 3);
+  static_assert (__countof__ (z) == 0);
+}
+
+void
+vla (void)
+{
+  unsigned n;
+
+  n = 99;
+  assert (__countof__ (short [n - 10]) == 99 - 10);
+
+  int v[n / 2];
+  assert (__countof__ (v) == 99 / 2);
+
+  n = 0;
+  int z[n];
+  assert (__countof__ (z) == 0);
+}
+
+void
+member (void)
+{
+  struct {
+    int a[8];
+  } s;
+
+  static_assert (__countof__ (s.a) == 8);
+}
+
+void
+vla_eval (void)
+{
+  int i;
+
+  i = 7;
+  assert (__countof__ (struct {int x;}[i++]) == 7);
+  assert (i == 7 + 1);
+
+  int v[i];
+  int (*p)[i];
+  p = &v;
+  assert (__countof__ (*p++) == i);
+  assert (p - 1 == &v);
+}
+
+void
+inner_vla_noeval (void)
+{
+  int i;
+
+  i = 3;
+  static_assert (__countof__ (struct {int x[i++];}[3]) == 3);
+  assert (i == 3);
+}
+
+void
+array_noeval (void)
+{
+  long a[5];
+  long (*p)[__countof__ (a)];
+
+  p = &a;
+  static_assert (__countof__ (*p++) == 5);
+  assert (p == &a);
+}
+
+void
+matrix_zero (void)
+{
+  int i;
+
+  static_assert (__countof__ (int [0][4]) == 0);
+  i = 3;
+  assert (__countof__ (int [0][i]) == 0);
+}
+
+void
+matrix_fixed (void)
+{
+  int i;
+
+  static_assert (__countof__ (int [7][4]) == 7);
+  i = 3;
+  static_assert (__countof__ (int [7][i]) == 7);
+}
+
+void
+matrix_vla (void)
+{
+  int i, j;
+
+  i = 7;
+  assert (__countof__ (int [i++][4]) == 7);
+  assert (i == 7 + 1);
+
+  i = 9;
+  j = 3;
+  assert (__countof__ (int [i++][j]) == 9);
+  assert (i == 9 + 1);
+}
+
+void
+no_parens(void)
+{
+  int n = 3;
+  int a[7];
+  int v[n];
+
+  static_assert (__countof__ a == 7); 
+  assert (__countof__ v == 3); 
+}
+
+int
+main (void)
+{
+  array ();
+  completed ();
+  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] 318+ messages in thread

* Re: [PATCH v18 0/2] c: Add __countof__ operator
  2024-11-10 10:32   ` [PATCH v18 " Alejandro Colomar
  2024-11-10 10:32     ` [PATCH v18 1/2] contrib/: Add support for Cc: and Link: tags Alejandro Colomar
  2024-11-10 10:32     ` [PATCH v18 2/2] c: Add __countof__ operator Alejandro Colomar
@ 2024-11-10 10:34     ` Alejandro Colomar
  2024-11-10 13:47     ` Martin Uecker
  3 siblings, 0 replies; 318+ messages in thread
From: Alejandro Colomar @ 2024-11-10 10:34 UTC (permalink / raw)
  To: gcc-patches; +Cc: Martin Uecker, JeanHeyd Meneide

[-- Attachment #1: Type: text/plain, Size: 9969 bytes --]

On Sun, Nov 10, 2024 at 11:32:54AM GMT, Alejandro Colomar wrote:
> Hi!
> 
> Your favourite operator with the most controversial name comes back with
> support for [0], thanks to Martin Uecker.  In movie theaters, and
> probably in GCC 16.
> 
> For those who fight in a side in the name wars, here's a reminder of a
> fair survey (by JeanHeyd) which might end the war with a peace treaty:
> <https://thephd.dev/the-big-array-size-survey-for-c>.
> 
> 
> Changes since v17:
> 
> -  Rebase after the recent patches added by Martin, which made [0][n]
>    and [*][n] have distinct representation, and thus allowed making
>    __countof__(int [0][n]) be a constant expression.
> 
> -  Make __countof__(int [0][n]) a constant expression.  Thanks, Martin!
>    Update the testsuite to reflect this too, of course.
> 
> -  Rename small function in the testsuite (automatic => completed).
> 
> See the range-diff below for the exact differences since v17.
> 
> 
> Martin, this worked out of the box.  I'll reply to this email with the
> regression-test session results; they all passed.  [0] works like a
> charm.

Regression tests say ok:

alx@debian:~/src/gnu/gcc/len$ git tag len18
alx@debian:~/src/gnu/gcc/len$ git log --oneline gnu/master^..len18
f8336e4646a (HEAD -> len, tag: len18) c: Add __countof__ operator
82100c813c3 contrib/: Add support for Cc: and Link: tags
114abf075c1 (gnu/trunk, gnu/master) c: minor fixes related to arrays of unspecified size
alx@debian:~/src/gnu/gcc/len$ git reset gnu/master --h
HEAD is now at 114abf075c1 c: minor fixes related to arrays of unspecified size
alx@debian:~/src/gnu/gcc/len$ mkdir ../len18
alx@debian:~/src/gnu/gcc/len$ cd ../len18
alx@debian:~/src/gnu/gcc/len18$ /bin/time ../len/configure --disable-multilib --prefix=/opt/local/gnu/gcc/countof18 |& ts -s | ovr -n 3; echo $?
00:00:04 config.status: creating Makefile
00:00:04 2.74user 1.51system 0:03.82elapsed 111%CPU (0avgtext+0avgdata 26588maxresident)k
00:00:04 91760inputs+8000outputs (275major+276906minor)pagefaults 0swaps
0
alx@debian:~/src/gnu/gcc/len18$ /bin/time make -j24 bootstrap |& ts -s | ovr -n 3; echo $?
00:20:34 make[1]: Leaving directory '/home/alx/src/gnu/gcc/len18'
00:20:34 14990.13user 437.20system 20:34.11elapsed 1250%CPU (0avgtext+0avgdata 1558756maxresident)k
00:20:34 1555888inputs+30810152outputs (19314major+119705948minor)pagefaults 0swaps
0
alx@debian:~/src/gnu/gcc/len18$ /bin/time make check |& ts -s | ovr -n 3; echo $?
06:54:58 make[1]: Leaving directory '/home/alx/src/gnu/gcc/len18'
06:54:58 21595.28user 3410.52system 6:54:57elapsed 100%CPU (0avgtext+0avgdata 2327800maxresident)k
06:54:58 728800inputs+21757040outputs (2918major+1010304995minor)pagefaults 0swaps
0
alx@debian:~/src/gnu/gcc/len18$ cd ../len
alx@debian:~/src/gnu/gcc/len$ git merge --ff-only len18
Updating 114abf075c1..f8336e4646a
Fast-forward
 contrib/gcc-changelog/git_commit.py    |   5 +-
 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                        |  22 +++-
 gcc/c/c-parser.cc                      |  62 +++++++---
 gcc/c/c-tree.h                         |   4 +
 gcc/c/c-typeck.cc                      | 115 ++++++++++++++++++-
 gcc/doc/extend.texi                    |  30 +++++
 gcc/testsuite/gcc.dg/countof-compile.c | 125 +++++++++++++++++++++
 gcc/testsuite/gcc.dg/countof-vla.c     |  45 ++++++++
 gcc/testsuite/gcc.dg/countof.c         | 150 +++++++++++++++++++++++++
 12 files changed, 564 insertions(+), 25 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/countof-compile.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-vla.c
 create mode 100644 gcc/testsuite/gcc.dg/countof.c
alx@debian:~/src/gnu/gcc/len$ cd ..
alx@debian:~/src/gnu/gcc$ mv len18 len18_b4
alx@debian:~/src/gnu/gcc$ mkdir len18
alx@debian:~/src/gnu/gcc$ cd len18
alx@debian:~/src/gnu/gcc/len18$ /bin/time ../len/configure --disable-multilib --prefix=/opt/local/gnu/gcc/countof18 |& ts -s | ovr -n 3; echo $?
00:00:03 config.status: creating Makefile
00:00:04 2.91user 1.55system 0:03.89elapsed 114%CPU (0avgtext+0avgdata 26556maxresident)k
00:00:04 0inputs+8000outputs (0major+280759minor)pagefaults 0swaps
0
alx@debian:~/src/gnu/gcc/len18$ /bin/time make -j24 bootstrap |& ts -s | ovr -n 3; echo $?
00:20:36 make[1]: Leaving directory '/home/alx/src/gnu/gcc/len18'
00:20:36 15194.00user 433.58system 20:35.69elapsed 1264%CPU (0avgtext+0avgdata 1565564maxresident)k
00:20:36 3688inputs+30817928outputs (168major+119818585minor)pagefaults 0swaps
0
alx@debian:~/src/gnu/gcc/len18$ /bin/time make check |& ts -s | ovr -n 3; echo $?
06:55:35 make[1]: Leaving directory '/home/alx/src/gnu/gcc/len18'
06:55:35 21613.87user 3477.00system 6:55:35elapsed 100%CPU (0avgtext+0avgdata 2327144maxresident)k
06:55:35 304inputs+21758376outputs (2758major+1012005133minor)pagefaults 0swaps
0
alx@debian:~/src/gnu/gcc/len18$ find -type f | grep '\.sum$' | while read f; do diff -u ../len18_b4/$f $f; done
--- ../len18_b4/./gcc/testsuite/gcc/gcc.sum	2024-11-09 14:30:51.671373959 +0100
+++ ./gcc/testsuite/gcc/gcc.sum	2024-11-09 22:23:17.996906200 +0100
@@ -1,4 +1,4 @@
-Test run by alx on Sat Nov  9 12:44:52 2024
+Test run by alx on Sat Nov  9 20:35:13 2024
 Native configuration is x86_64-pc-linux-gnu
 
 		=== gcc tests ===
@@ -78457,6 +78457,29 @@
 PASS: gcc.dg/conv-2.c (test for excess errors)
 PASS: gcc.dg/conv-3.c (test for excess errors)
 PASS: gcc.dg/conv-3.c execution test
+PASS: gcc.dg/countof-compile.c  (test for errors, line 24)
+PASS: gcc.dg/countof-compile.c  (test for errors, line 28)
+PASS: gcc.dg/countof-compile.c  (test for errors, line 39)
+PASS: gcc.dg/countof-compile.c  (test for errors, line 47)
+PASS: gcc.dg/countof-compile.c  (test for errors, line 62)
+PASS: gcc.dg/countof-compile.c  (test for errors, line 65)
+PASS: gcc.dg/countof-compile.c  (test for errors, line 68)
+PASS: gcc.dg/countof-compile.c  (test for errors, line 80)
+PASS: gcc.dg/countof-compile.c  (test for errors, line 81)
+PASS: gcc.dg/countof-compile.c  (test for errors, line 82)
+PASS: gcc.dg/countof-compile.c  (test for errors, line 83)
+PASS: gcc.dg/countof-compile.c  (test for errors, line 84)
+PASS: gcc.dg/countof-compile.c  (test for errors, line 85)
+PASS: gcc.dg/countof-compile.c  (test for errors, line 86)
+PASS: gcc.dg/countof-compile.c  (test for errors, line 87)
+PASS: gcc.dg/countof-compile.c  (test for errors, line 88)
+PASS: gcc.dg/countof-compile.c  (test for warnings, line 92)
+PASS: gcc.dg/countof-compile.c  (test for errors, line 112)
+PASS: gcc.dg/countof-compile.c  (test for errors, line 121)
+PASS: gcc.dg/countof-compile.c (test for excess errors)
+PASS: gcc.dg/countof-vla.c (test for excess errors)
+PASS: gcc.dg/countof.c (test for excess errors)
+PASS: gcc.dg/countof.c execution test
 PASS: gcc.dg/cr-decimal-dig-1.c (test for excess errors)
 PASS: gcc.dg/cr-decimal-dig-2.c (test for excess errors)
 PASS: gcc.dg/cr-decimal-dig-3.c (test for excess errors)
@@ -209690,7 +209713,7 @@
 
 		=== gcc Summary ===
 
-# of expected passes		204581
+# of expected passes		204604
 # of unexpected failures	35
 # of unexpected successes	2
 # of expected failures		1462
--- ../len18_b4/./gcc/testsuite/gfortran/gfortran.sum	2024-11-09 16:10:40.810086221 +0100
+++ ./gcc/testsuite/gfortran/gfortran.sum	2024-11-10 00:02:42.892974019 +0100
@@ -1,4 +1,4 @@
-Test run by alx on Sat Nov  9 15:35:18 2024
+Test run by alx on Sat Nov  9 23:27:28 2024
 Native configuration is x86_64-pc-linux-gnu
 
 		=== gfortran tests ===
--- ../len18_b4/./gcc/testsuite/objc/objc.sum	2024-11-09 16:11:47.262652513 +0100
+++ ./gcc/testsuite/objc/objc.sum	2024-11-10 00:03:49.645533215 +0100
@@ -1,4 +1,4 @@
-Test run by alx on Sat Nov  9 16:10:41 2024
+Test run by alx on Sun Nov 10 00:02:43 2024
 Native configuration is x86_64-pc-linux-gnu
 
 		=== objc tests ===
--- ../len18_b4/./gcc/testsuite/g++/g++.sum	2024-11-09 15:35:17.635848988 +0100
+++ ./gcc/testsuite/g++/g++.sum	2024-11-09 23:27:28.295344138 +0100
@@ -1,4 +1,4 @@
-Test run by alx on Sat Nov  9 14:30:52 2024
+Test run by alx on Sat Nov  9 22:23:18 2024
 Native configuration is x86_64-pc-linux-gnu
 
 		=== g++ tests ===
--- ../len18_b4/./x86_64-pc-linux-gnu/libitm/testsuite/libitm.sum	2024-11-09 19:39:41.748431581 +0100
+++ ./x86_64-pc-linux-gnu/libitm/testsuite/libitm.sum	2024-11-10 03:30:41.385976347 +0100
@@ -1,4 +1,4 @@
-Test run by alx on Sat Nov  9 19:39:39 2024
+Test run by alx on Sun Nov 10 03:30:39 2024
 Native configuration is x86_64-pc-linux-gnu
 
 		=== libitm tests ===
--- ../len18_b4/./x86_64-pc-linux-gnu/libgomp/testsuite/libgomp.sum	2024-11-09 19:39:39.228410199 +0100
+++ ./x86_64-pc-linux-gnu/libgomp/testsuite/libgomp.sum	2024-11-10 03:30:38.841955150 +0100
@@ -1,4 +1,4 @@
-Test run by alx on Sat Nov  9 19:25:22 2024
+Test run by alx on Sun Nov 10 03:16:28 2024
 Native configuration is x86_64-pc-linux-gnu
 
 		=== libgomp tests ===
--- ../len18_b4/./x86_64-pc-linux-gnu/libatomic/testsuite/libatomic.sum	2024-11-09 19:39:44.084451402 +0100
+++ ./x86_64-pc-linux-gnu/libatomic/testsuite/libatomic.sum	2024-11-10 03:30:43.569994545 +0100
@@ -1,4 +1,4 @@
-Test run by alx on Sat Nov  9 19:39:42 2024
+Test run by alx on Sun Nov 10 03:30:41 2024
 Native configuration is x86_64-pc-linux-gnu
 
 		=== libatomic tests ===
--- ../len18_b4/./x86_64-pc-linux-gnu/libstdc++-v3/testsuite/libstdc++.sum	2024-11-09 19:24:59.576997714 +0100
+++ ./x86_64-pc-linux-gnu/libstdc++-v3/testsuite/libstdc++.sum	2024-11-10 03:16:05.646750347 +0100
@@ -1,4 +1,4 @@
-Test run by alx on Sat Nov  9 16:12:16 2024
+Test run by alx on Sun Nov 10 00:04:18 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] 318+ messages in thread

* Re: [PATCH v18 0/2] c: Add __countof__ operator
  2024-11-10 10:32   ` [PATCH v18 " Alejandro Colomar
                       ` (2 preceding siblings ...)
  2024-11-10 10:34     ` [PATCH v18 0/2] " Alejandro Colomar
@ 2024-11-10 13:47     ` Martin Uecker
  3 siblings, 0 replies; 318+ messages in thread
From: Martin Uecker @ 2024-11-10 13:47 UTC (permalink / raw)
  To: Alejandro Colomar, gcc-patches; +Cc: JeanHeyd Meneide

Am Sonntag, dem 10.11.2024 um 11:32 +0100 schrieb Alejandro Colomar:
> Hi!
> 
> Your favourite operator with the most controversial name comes back with
> support for [0], thanks to Martin Uecker.  In movie theaters, and
> probably in GCC 16.
> 
> For those who fight in a side in the name wars, here's a reminder of a
> fair survey (by JeanHeyd) which might end the war with a peace treaty:
> <https://thephd.dev/the-big-array-size-survey-for-c>.
> 
> 
> Changes since v17:
> 
> -  Rebase after the recent patches added by Martin, which made [0][n]
>    and [*][n] have distinct representation, and thus allowed making
>    __countof__(int [0][n]) be a constant expression.
> 
> -  Make __countof__(int [0][n]) a constant expression.  Thanks, Martin!
>    Update the testsuite to reflect this too, of course.
> 
> -  Rename small function in the testsuite (automatic => completed).
> 
> See the range-diff below for the exact differences since v17.
> 
> 
> Martin, this worked out of the box.  I'll reply to this email with the
> regression-test session results; they all passed.  [0] works like a
> charm.

Yes, it is nice how everything starts to fall into place
once you remove enough complexity and special cases ...

Martin

> 
> 
> Have a lovely day!
> Alex
> 
> 
> Alejandro Colomar (2):
>   contrib/: Add support for Cc: and Link: tags
>   c: Add __countof__ operator
> 
>  contrib/gcc-changelog/git_commit.py    |   5 +-
>  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                        |  22 +++-
>  gcc/c/c-parser.cc                      |  62 +++++++---
>  gcc/c/c-tree.h                         |   4 +
>  gcc/c/c-typeck.cc                      | 115 ++++++++++++++++++-
>  gcc/doc/extend.texi                    |  30 +++++
>  gcc/testsuite/gcc.dg/countof-compile.c | 125 +++++++++++++++++++++
>  gcc/testsuite/gcc.dg/countof-vla.c     |  45 ++++++++
>  gcc/testsuite/gcc.dg/countof.c         | 150 +++++++++++++++++++++++++
>  12 files changed, 564 insertions(+), 25 deletions(-)
>  create mode 100644 gcc/testsuite/gcc.dg/countof-compile.c
>  create mode 100644 gcc/testsuite/gcc.dg/countof-vla.c
>  create mode 100644 gcc/testsuite/gcc.dg/countof.c
> 
> Range-diff against v17:
> 1:  d847dc4a795 = 1:  82100c813c3 contrib/: Add support for Cc: and Link: tags
> 2:  936f7945fae ! 2:  f8336e4646a c: Add __countof__ operator
>     @@ Commit message
>             and somehow magically return the number of elements of the array,
>             regardless of it being really a pointer.
>      
>     -    -  Fix support for [0].
>     -
>          gcc/ChangeLog:
>      
>                  * doc/extend.texi: Document __countof__ operator.
>     @@ gcc/c/c-decl.cc: finish_enum (tree enumtype, tree values, tree attributes)
>      
>       ## gcc/c/c-parser.cc ##
>      @@ gcc/c/c-parser.cc: along with GCC; see the file COPYING3.  If not see
>     - #include "bitmap.h"
>     - #include "analyzer/analyzer-language.h"
>       #include "toplev.h"
>     + #include "asan.h"
>     + #include "c-family/c-ubsan.h"
>      +\f
>      +#define c_parser_sizeof_expression(parser)                                    \
>      +(                                                                             \
>     @@ 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, star, var;
>     ++  bool zero, 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);
>     -+  star = (zero && C_TYPE_VARIABLE_SIZE (type));
>     -+  if (star)
>     -+    return true;
>      +  if (zero)
>      +    return false;
>      +
>     @@ gcc/testsuite/gcc.dg/countof-compile.c (new)
>      +  _Static_assert (__countof__ (int [n][3]) == 7); /* { dg-error "not constant" } */
>      +  _Static_assert (__countof__ (int [0][3]) == 0);
>      +  _Static_assert (__countof__ (int [0]) == 0);
>     -+
>     -+  /* FIXME: countof(int [0][n]) should result in a constant expression.  */
>     -+  _Static_assert (__countof__ (int [0][n]) == 0); /* { dg-error "not constant" } */
>     ++  _Static_assert (__countof__ (int [0][n]) == 0);
>      +}
>      
>       ## gcc/testsuite/gcc.dg/countof-vla.c (new) ##
>     @@ gcc/testsuite/gcc.dg/countof-vla.c (new)
>      +	      char (*a)[*][*],
>      +	      int (*x)[__countof__ (*a)]);
>      +
>     -+// Can't test due to bug: <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=116284>
>     -+//static int z2[0];
>     -+//static int y2[__countof__(z2)];
>     ++static int z2[0];
>     ++static int y2[__countof__(z2)];
>      
>       ## gcc/testsuite/gcc.dg/countof.c (new) ##
>      @@
>     @@ gcc/testsuite/gcc.dg/countof.c (new)
>      +}
>      +
>      +void
>     -+automatic(void)
>     ++completed (void)
>      +{
>      +  int a[] = {1, 2, 3};
>      +  int z[] = {};
>     @@ gcc/testsuite/gcc.dg/countof.c (new)
>      +main (void)
>      +{
>      +  array ();
>     -+  automatic ();
>     ++  completed ();
>      +  vla ();
>      +  member ();
>      +  vla_eval ();
> 
> base-commit: 9cbcf8d1de159e6113fafb5dc2feb4a7e467a302


^ permalink raw reply	[flat|nested] 318+ messages in thread

* [PATCH v20 0/4] c: Add _Countof and <stdcountof.h>
  2024-07-28 14:15 ` [RFC v1 0/2] c: Add _Lengthof operator Alejandro Colomar
                     ` (22 preceding siblings ...)
  2024-11-10 10:32   ` [PATCH v18 " Alejandro Colomar
@ 2025-05-11 14:11   ` Alejandro Colomar
  2025-05-11 14:11     ` [PATCH v20 1/4] contrib/: Add support for Link: tags Alejandro Colomar
                       ` (4 more replies)
  2025-05-12 15:53   ` [PATCH v21 0/3] " Alejandro Colomar
                     ` (4 subsequent siblings)
  28 siblings, 5 replies; 318+ messages in thread
From: Alejandro Colomar @ 2025-05-11 14:11 UTC (permalink / raw)
  To: gcc-patches
  Cc: Alejandro Colomar, Martin Uecker, JeanHeyd Meneide, Joseph Myers,
	Jakub Jelinek

Hi,

Here's the list of changes in v20:

-  Drop changes to support Cc tags in commit messages (but keep the
   patch to add support for Link tags).
-  Drop the Cc tags from commit 2 (but keep Link tags).
-  Remove one _Static_assert() from tests.  I think the test is more
   readable without it.
-  Add space in macro definition.
-  Fix changelog for the makefile changes.
-  Add patch 4, which adds the pedantic warning for <= C23.

I think this is feature-complete.  I have run `make bootstrap`.  I
haven't run `make check` yet this time; I'll do that in the following
days.


Have a lovely day!
Alex


Alejandro Colomar (4):
  contrib/: Add support for Link: tags
  c: Add _Countof operator
  c: Add <stdcountof.h>
  c: Add -Wpedantic diagnostic for _Countof

 contrib/gcc-changelog/git_commit.py    |   3 +
 gcc/Makefile.in                        |   1 +
 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                        |  22 +++-
 gcc/c/c-parser.cc                      |  63 +++++++---
 gcc/c/c-tree.h                         |   4 +
 gcc/c/c-typeck.cc                      | 115 +++++++++++++++++-
 gcc/doc/extend.texi                    |  30 +++++
 gcc/ginclude/stdcountof.h              |  31 +++++
 gcc/testsuite/gcc.dg/countof-compile.c | 130 +++++++++++++++++++++
 gcc/testsuite/gcc.dg/countof-vla.c     |  51 ++++++++
 gcc/testsuite/gcc.dg/countof.c         | 154 +++++++++++++++++++++++++
 14 files changed, 611 insertions(+), 24 deletions(-)
 create mode 100644 gcc/ginclude/stdcountof.h
 create mode 100644 gcc/testsuite/gcc.dg/countof-compile.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-vla.c
 create mode 100644 gcc/testsuite/gcc.dg/countof.c

Range-diff against v19:
1:  796c82b0cba ! 1:  0a752a02dd0 contrib/: Add support for Cc: and Link: tags
    @@ Metadata
     Author: Alejandro Colomar <alx@kernel.org>
     
      ## Commit message ##
    -    contrib/: Add support for Cc: and Link: tags
    +    contrib/: Add support for Link: tags
     
         contrib/ChangeLog:
     
                 * gcc-changelog/git_commit.py (GitCommit):
    -            Add support for 'Cc: ' and 'Link: ' tags.
    +            Add support for 'Link:' tags.
     
         Cc: Jason Merrill <jason@redhat.com>
         Signed-off-by: Alejandro Colomar <alx@kernel.org>
     
      ## contrib/gcc-changelog/git_commit.py ##
     @@ contrib/gcc-changelog/git_commit.py: CO_AUTHORED_BY_PREFIX = 'co-authored-by: '
    - 
      REVIEW_PREFIXES = ('reviewed-by: ', 'reviewed-on: ', 'signed-off-by: ',
                         'acked-by: ', 'tested-by: ', 'reported-by: ',
    --                   'suggested-by: ')
    -+                   'suggested-by: ', 'cc: ')
    +                    'suggested-by: ')
     +LINK_PREFIXES = ('link: ')
      DATE_FORMAT = '%Y-%m-%d'
      
2:  ae4691c8b45 ! 2:  c28c880f609 c: Add _Countof operator
    @@ Commit message
         Suggested-by: Xavier Del Campo Romero <xavi.dcr@tutanota.com>
         Co-authored-by: Martin Uecker <uecker@tugraz.at>
         Acked-by: "James K. Lowden" <jklowden@schemamania.org>
    -    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>
    -    Cc: Daniel Plakosh <dplakosh@cert.org>
    -    Cc: "A. Jiang" <de34@live.cn>
    -    Cc: Eugene Zelenko <eugene.zelenko@gmail.com>
    -    Cc: Aaron Ballman <aaron.ballman@intel.com>
    -    Cc: Paul Koning <paulkoning@comcast.net>
    -    Cc: Daniel Lundin <daniel.lundin.mail@gmail.com>
    -    Cc: Nikolaos Strimpas <Strnik86@protonmail.com>
    -    Cc: JeanHeyd Meneide <phdofthehouse@gmail.com>
    -    Cc: Fernando Borretti <fernando@borretti.me>
    -    Cc: Jonathan Protzenko <jonathan.protzenko@ens-lyon.org>
    -    Cc: Chris Bazley <Chris.Bazley@arm.com>
    -    Cc: Ville Voutilainen <ville.voutilainen@gmail.com>
    -    Cc: Alex Celeste <alexg.nvfp@gmail.com>
    -    Cc: Jakub Łukasiewicz <jakublukasiewicz@outlook.com>
    -    Cc: Douglas McIlroy <douglas.mcilroy@dartmouth.edu>
    -    Cc: Jason Merrill <jason@redhat.com>
    -    Cc: "Gustavo A. R. Silva" <gustavoars@kernel.org>
    -    Cc: Patrizia Kaye <patrizia@ethernull.org>
    -    Cc: Ori Bernstein <ori@eigenstate.org>
    -    Cc: Robert Seacord <rcseacord@gmail.com>
    -    Cc: Marek Polacek <mpolacek@gcc.gnu.org>
    -    Cc: Sam James <sam@gentoo.org>
    -    Cc: Richard Biener <richard.guenther@gmail.com>
         Signed-off-by: Alejandro Colomar <alx@kernel.org>
     
      ## gcc/c-family/c-common.cc ##
    @@ gcc/testsuite/gcc.dg/countof-compile.c (new)
     +{
     +  int b[n][n];
     +
    -+  _Static_assert (_Countof (a[f1()]) == 9);
    ++  _Countof (a[f1()]);
     +  _Countof (b[f2()]);
     +}
     +
3:  f4700c6d7dc ! 3:  f6ff1f130de c: Add <stdcountof.h>
    @@ Commit message
     
         gcc/ChangeLog:
     
    -            * Makefile.in
    +            * Makefile.in (USER_H): Add <stdcountof.h>.
                 * ginclude/stdcountof.h: Add countof macro.
     
         Signed-off-by: Alejandro Colomar <alx@kernel.org>
    @@ gcc/ginclude/stdcountof.h (new)
     +#ifndef _STDCOUNTOF_H
     +#define _STDCOUNTOF_H
     +
    -+#define countof _Countof
    ++#define countof  _Countof
     +
     +#endif	/* stdcountof.h */
-:  ----------- > 4:  94bc203a406 c: Add -Wpedantic diagnostic for _Countof
-- 
2.49.0


^ permalink raw reply	[flat|nested] 318+ messages in thread

* [PATCH v20 1/4] contrib/: Add support for Link: tags
  2025-05-11 14:11   ` [PATCH v20 0/4] c: Add _Countof and <stdcountof.h> Alejandro Colomar
@ 2025-05-11 14:11     ` Alejandro Colomar
  2025-05-11 14:12     ` [PATCH v20 2/4] c: Add _Countof operator Alejandro Colomar
                       ` (3 subsequent siblings)
  4 siblings, 0 replies; 318+ messages in thread
From: Alejandro Colomar @ 2025-05-11 14:11 UTC (permalink / raw)
  To: gcc-patches
  Cc: Alejandro Colomar, Martin Uecker, JeanHeyd Meneide, Joseph Myers,
	Jakub Jelinek, Jason Merrill

contrib/ChangeLog:

	* gcc-changelog/git_commit.py (GitCommit):
	Add support for 'Link:' tags.

Cc: Jason Merrill <jason@redhat.com>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
---
 contrib/gcc-changelog/git_commit.py | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/contrib/gcc-changelog/git_commit.py b/contrib/gcc-changelog/git_commit.py
index 5645f80ebb9..5f5f3b9110a 100755
--- a/contrib/gcc-changelog/git_commit.py
+++ b/contrib/gcc-changelog/git_commit.py
@@ -188,6 +188,7 @@ CO_AUTHORED_BY_PREFIX = 'co-authored-by: '
 REVIEW_PREFIXES = ('reviewed-by: ', 'reviewed-on: ', 'signed-off-by: ',
                    'acked-by: ', 'tested-by: ', 'reported-by: ',
                    'suggested-by: ')
+LINK_PREFIXES = ('link: ')
 DATE_FORMAT = '%Y-%m-%d'
 
 
@@ -529,6 +530,8 @@ class GitCommit:
                     continue
                 elif lowered_line.startswith(REVIEW_PREFIXES):
                     continue
+                elif lowered_line.startswith(LINK_PREFIXES):
+                    continue
                 else:
                     m = cherry_pick_regex.search(line)
                     if m:
-- 
2.49.0


^ permalink raw reply	[flat|nested] 318+ messages in thread

* [PATCH v20 2/4] c: Add _Countof operator
  2025-05-11 14:11   ` [PATCH v20 0/4] c: Add _Countof and <stdcountof.h> Alejandro Colomar
  2025-05-11 14:11     ` [PATCH v20 1/4] contrib/: Add support for Link: tags Alejandro Colomar
@ 2025-05-11 14:12     ` Alejandro Colomar
  2025-05-12 10:54       ` Joseph Myers
  2025-05-11 14:12     ` [PATCH v20 3/4] c: Add <stdcountof.h> Alejandro Colomar
                       ` (2 subsequent siblings)
  4 siblings, 1 reply; 318+ messages in thread
From: Alejandro Colomar @ 2025-05-11 14:12 UTC (permalink / raw)
  To: gcc-patches
  Cc: Alejandro Colomar, Martin Uecker, JeanHeyd Meneide, Joseph Myers,
	Jakub Jelinek, Xavier Del Campo Romero, James K. Lowden

This operator is similar to sizeof but can only be applied to an array,
and returns its number of elements.

FUTURE DIRECTIONS:

-  We should make it work with array parameters to functions,
   and somehow magically return the number of elements of the array,
   regardless of it being really a pointer.

gcc/ChangeLog:

	* doc/extend.texi: Document _Countof operator.

gcc/c-family/ChangeLog:

	* c-common.h
	* c-common.def
	* c-common.cc (c_countof_type): Add _Countof operator.

gcc/c/ChangeLog:

	* c-tree.h
	(c_expr_countof_expr, c_expr_countof_type)
	* c-decl.cc
	(start_struct, finish_struct)
	(start_enum, finish_enum)
	* c-parser.cc
	(c_parser_sizeof_expression)
	(c_parser_countof_expression)
	(c_parser_sizeof_or_countof_expression)
	(c_parser_unary_expression)
	* c-typeck.cc
	(build_external_ref)
	(record_maybe_used_decl)
	(pop_maybe_used)
	(is_top_array_vla)
	(c_expr_countof_expr, c_expr_countof_type):
	Add _Countof operator.

gcc/testsuite/ChangeLog:

	* gcc.dg/countof-compile.c
	* gcc.dg/countof-vla.c
	* gcc.dg/countof.c: Add tests for _Countof operator.

Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3550.pdf>
Link: <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117025>
Link: <https://inbox.sourceware.org/gcc/M8S4oQy--3-2@tutanota.com/T/>
Link: <https://inbox.sourceware.org/gcc-patches/20240728141547.302478-1-alx@kernel.org/T/#t>
Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3313.pdf>
Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3325.pdf>
Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3369.pdf>
Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3469.htm>
Link: <https://github.com/llvm/llvm-project/issues/102836>
Link: <https://thephd.dev/the-big-array-size-survey-for-c>
Link: <https://thephd.dev/the-big-array-size-survey-for-c-results>
Link: <https://stackoverflow.com/questions/37538/#57537491>
Suggested-by: Xavier Del Campo Romero <xavi.dcr@tutanota.com>
Co-authored-by: Martin Uecker <uecker@tugraz.at>
Acked-by: "James K. Lowden" <jklowden@schemamania.org>
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                        |  22 +++-
 gcc/c/c-parser.cc                      |  59 +++++++---
 gcc/c/c-tree.h                         |   4 +
 gcc/c/c-typeck.cc                      | 115 +++++++++++++++++-
 gcc/doc/extend.texi                    |  30 +++++
 gcc/testsuite/gcc.dg/countof-compile.c | 130 +++++++++++++++++++++
 gcc/testsuite/gcc.dg/countof-vla.c     |  51 ++++++++
 gcc/testsuite/gcc.dg/countof.c         | 154 +++++++++++++++++++++++++
 11 files changed, 572 insertions(+), 24 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/countof-compile.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-vla.c
 create mode 100644 gcc/testsuite/gcc.dg/countof.c

diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
index 587d76461e9..f71cb2652d5 100644
--- a/gcc/c-family/c-common.cc
+++ b/gcc/c-family/c-common.cc
@@ -394,6 +394,7 @@ const struct c_common_resword c_common_reswords[] =
 {
   { "_Alignas",		RID_ALIGNAS,   D_CONLY },
   { "_Alignof",		RID_ALIGNOF,   D_CONLY },
+  { "_Countof",		RID_COUNTOF,   D_CONLY },
   { "_Atomic",		RID_ATOMIC,    D_CONLY },
   { "_BitInt",		RID_BITINT,    D_CONLY },
   { "_Bool",		RID_BOOL,      D_CONLY },
@@ -4080,6 +4081,31 @@ c_alignof_expr (location_t loc, tree expr)
 
   return fold_convert_loc (loc, size_type_node, t);
 }
+
+/* Implement the _Countof keyword:
+   Return the number of elements of an array.  */
+
+tree
+c_countof_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 %<_Countof%> to type %qT", type);
+      return error_mark_node;
+    }
+  if (!COMPLETE_TYPE_P (type))
+    {
+      error_at (loc,
+		"invalid application of %<_Countof%> 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 cf2228201fa..0bcc4998afe 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 'countof' expression.  */
+DEFTREECODE (COUNTOF_EXPR, "countof_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 ea6c2975056..91fd120e77e 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_COUNTOF,
   RID_C23_VA_START, RID_VA_ARG,
   RID_EXTENSION, RID_IMAGPART, RID_REALPART, RID_LABEL,    RID_CHOOSE_EXPR,
   RID_TYPES_COMPATIBLE_P,      RID_BUILTIN_COMPLEX,	   RID_BUILTIN_SHUFFLE,
@@ -890,6 +891,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_countof_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 ad66d7d258b..5bf638bfbd8 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -8943,12 +8943,17 @@ 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_countof))
     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"
+		       : "_Countof"))));
 
   if (in_underspecified_init)
     error_at (loc, "%qT defined in underspecified object initializer", ref);
@@ -9923,7 +9928,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_countof)
 	struct_parse_info->struct_types.safe_push (t);
      }
 
@@ -10097,12 +10102,17 @@ 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_countof))
     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"
+		       : "_Countof"))));
 
   if (in_underspecified_init)
     error_at (loc, "%qT defined in underspecified object initializer",
@@ -10296,7 +10306,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_countof)
     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 8a63dc54c79..87700339394 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -77,7 +77,17 @@ along with GCC; see the file COPYING3.  If not see
 #include "asan.h"
 #include "c-family/c-ubsan.h"
 #include "gcc-urlifier.h"
+\f
+#define c_parser_sizeof_expression(parser)                                    \
+(                                                                             \
+  c_parser_sizeof_or_countof_expression (parser, RID_SIZEOF)                  \
+)
 
+#define c_parser_countof_expression(parser)                                   \
+(                                                                             \
+  c_parser_sizeof_or_countof_expression (parser, RID_COUNTOF)                 \
+)
+\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
@@ -1737,7 +1747,8 @@ 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_countof_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 *,
@@ -10572,6 +10583,8 @@ c_parser_unary_expression (c_parser *parser)
     case CPP_KEYWORD:
       switch (c_parser_peek_token (parser)->keyword)
 	{
+	case RID_COUNTOF:
+	  return c_parser_countof_expression (parser);
 	case RID_SIZEOF:
 	  return c_parser_sizeof_expression (parser);
 	case RID_ALIGNOF:
@@ -10611,12 +10624,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_countof_expression (c_parser *parser, enum rid rid)
 {
+  const char *op_name = (rid == RID_COUNTOF) ? "_Countof" : "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;
@@ -10625,7 +10639,10 @@ c_parser_sizeof_expression (c_parser *parser)
 
   c_parser_consume_token (parser);
   c_inhibit_evaluation_warnings++;
-  in_sizeof++;
+  if (rid == RID_COUNTOF)
+    in_countof++;
+  else
+    in_sizeof++;
   if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)
       && c_token_starts_compound_literal (c_parser_peek_2nd_token (parser)))
     {
@@ -10646,7 +10663,7 @@ c_parser_sizeof_expression (c_parser *parser)
 	     for parsing error; the parsing of the expression could have
 	     called record_maybe_used_decl.  */
 	  expr.set_error ();
-	  goto sizeof_expr;
+	  goto Xof_expr;
 	}
       if (c_parser_next_token_is (parser, CPP_OPEN_BRACE))
 	{
@@ -10654,31 +10671,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_COUNTOF)
+	{
+	  in_countof--;
+	  result = c_expr_countof_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_COUNTOF)
+	in_countof--;
+      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_COUNTOF)
+	result = c_expr_countof_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 2098120de29..723a28b3906 100644
--- a/gcc/c/c-tree.h
+++ b/gcc/c/c-tree.h
@@ -765,6 +765,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_countof;
 extern int in_typeof;
 extern bool c_in_omp_for;
 extern bool c_omp_array_section_p;
@@ -827,6 +828,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_countof_expr (location_t, struct c_expr);
+extern struct c_expr c_expr_countof_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 0e1f842e22d..360216b9662 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -72,6 +72,9 @@ int in_alignof;
 /* The level of nesting inside "sizeof".  */
 int in_sizeof;
 
+/* The level of nesting inside "countof".  */
+int in_countof;
+
 /* The level of nesting inside "typeof".  */
 int in_typeof;
 
@@ -3540,7 +3543,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_countof)
 	C_DECL_USED (ref) = 1;
       else if (DECL_INITIAL (ref) == NULL_TREE
 	       && DECL_EXTERNAL (ref)
@@ -3596,7 +3599,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_countof).  */
   int level;
   /* The next one at this level or above, or NULL.  */
   struct maybe_used_decl *next;
@@ -3614,7 +3617,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_countof;
   t->next = maybe_used_decls;
   maybe_used_decls = t;
 }
@@ -3628,7 +3631,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_countof;
   while (p && p->level > cur_level)
     {
       if (used)
@@ -3738,6 +3741,110 @@ 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);
+  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 countof applied to EXPR.  */
+
+struct c_expr
+c_expr_countof_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_countof_type (loc, TREE_TYPE (folded_expr));
+      c_last_sizeof_arg = expr.value;
+      c_last_sizeof_loc = loc;
+      ret.original_code = COUNTOF_EXPR;
+      ret.original_type = NULL;
+      ret.m_decimal = 0;
+      if (is_top_array_vla (TREE_TYPE (folded_expr)))
+	{
+	  /* countof 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 countof applied to T, a structure for the type
+   name passed to countof (rather than the type itself).  LOC is the
+   location of the original expression.  */
+
+struct c_expr
+c_expr_countof_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_countof_type (loc, type);
+  c_last_sizeof_arg = type;
+  c_last_sizeof_loc = loc;
+  ret.original_code = COUNTOF_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 countof does not get folded to a constant by
+	 c_fully_fold, because if the number of elements is evaluated
+	 the result is not constant and so
+	 constraints on zero or negative size arrays must not be applied
+	 when this countof 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/doc/extend.texi b/gcc/doc/extend.texi
index 212d2487558..8b33df20fbc 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -10706,6 +10706,36 @@ library.
 @xref{OpenMP and OpenACC Options}, for additional options useful with
 @option{-fopenacc}.
 
+@node _Countof
+@section Determining the Number of Elements of Arrays
+@cindex _Countof
+@cindex number of elements
+
+The keyword @code{_Countof} determines
+the number of elements of an array operand.
+Its syntax is similar to @code{sizeof}.
+The operand must be
+a parenthesized complete array type name
+or an expression of such a type.
+For example:
+
+@smallexample
+int a[n];
+_Countof (a);  // returns n
+_Countof (int [7][3]);  // returns 7
+@end smallexample
+
+The result of this operator is an integer constant expression,
+unless the array has a variable number of elements.
+The operand is only evaluated
+if the array has a variable number of elements.
+For example:
+
+@smallexample
+_Countof (int [7][n++]);  // integer constant expression
+_Countof (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/testsuite/gcc.dg/countof-compile.c b/gcc/testsuite/gcc.dg/countof-compile.c
new file mode 100644
index 00000000000..9b4743789f9
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/countof-compile.c
@@ -0,0 +1,130 @@
+/* { dg-do compile } */
+/* { dg-options "-Wno-declaration-after-statement -Wno-pedantic -Wno-vla" } */
+
+#define NULL  ((void *) 0)
+
+extern int x[];
+
+static int w[] = {1, 2, 3};
+
+static int z[0];
+static int y[_Countof(z)];
+
+void
+completed (void)
+{
+  int i = 42;
+  int a[] = {1, 2, i};
+
+  _Static_assert(_Countof (w) == 3);
+  _Static_assert(_Countof (a) == 3);
+}
+
+void
+incomplete (int p[])
+{
+  _Countof (x);  /* { dg-error "incomplete" } */
+
+  /* We want to support array parameters in the future,
+     which should change this from "invalid" to "incomplete".  */
+  _Countof (p);  /* { dg-error "invalid" } */
+}
+
+void
+fam (void)
+{
+  struct {
+    int x;
+    int fam[];
+  } s;
+
+  _Countof (s.fam); /* { dg-error "incomplete" } */
+}
+
+void
+param (int n, int p[n])
+{
+  /* We want to support array parameters in the future,
+     which would make this work.  */
+  _Countof (p);  /* { dg-error "invalid" } */
+}
+
+void fix_fix (int i, char (*a)[3][5], int (*x)[_Countof (*a)],
+	      short (*)[_Generic(x, int (*)[3]: 1)]);
+void fix_var (int i, char (*a)[3][i], int (*x)[_Countof (*a)],
+	      short (*)[_Generic(x, int (*)[3]: 1)]);
+void fix_uns (int i, char (*a)[3][*], int (*x)[_Countof (*a)],
+	      short (*)[_Generic(x, int (*)[3]: 1)]);
+
+void
+func (void)
+{
+  int  i3[3];
+  int  i5[5];
+  char c35[3][5];
+
+  fix_fix (5, &c35, &i3, NULL);
+  fix_fix (5, &c35, &i5, NULL); /* { dg-error "incompatible-pointer-types" } */
+
+  fix_var (5, &c35, &i3, NULL);
+  fix_var (5, &c35, &i5, NULL); /* { dg-error "incompatible-pointer-types" } */
+
+  fix_uns (5, &c35, &i3, NULL);
+  fix_uns (5, &c35, &i5, NULL); /* { dg-error "incompatible-pointer-types" } */
+}
+
+void
+non_arr(void)
+{
+  int x;
+  int *p;
+  struct s {
+    int x[3];
+  } s;
+
+  _Countof (x); /* { dg-error "invalid" } */
+  _Countof (int); /* { dg-error "invalid" } */
+  _Countof (s); /* { dg-error "invalid" } */
+  _Countof (struct s); /* { dg-error "invalid" } */
+  _Countof (&x); /* { dg-error "invalid" } */
+  _Countof (p); /* { dg-error "invalid" } */
+  _Countof (int *); /* { dg-error "invalid" } */
+  _Countof (&s.x); /* { dg-error "invalid" } */
+  _Countof (int (*)[3]); /* { dg-error "invalid" } */
+}
+
+static int f1();
+static int f2(); /* { dg-warning "never defined" } */
+int a[10][9];
+int n;
+
+void
+syms(void)
+{
+  int b[n][n];
+
+  _Countof (a[f1()]);
+  _Countof (b[f2()]);
+}
+
+void
+no_parens(void)
+{
+  _Static_assert(_Countof a == 10);
+  _Static_assert(_Countof *a == 9);
+  _Static_assert(_Countof (int [3]) {} == 3);
+
+  _Countof int [3]; /* { dg-error "expected expression before" } */
+}
+
+void
+const_expr(void)
+{
+  int n = 7;
+
+  _Static_assert (_Countof (int [3][n]) == 3);
+  _Static_assert (_Countof (int [n][3]) == 7); /* { dg-error "not constant" } */
+  _Static_assert (_Countof (int [0][3]) == 0);
+  _Static_assert (_Countof (int [0]) == 0);
+  _Static_assert (_Countof (int [0][n]) == 0);
+}
diff --git a/gcc/testsuite/gcc.dg/countof-vla.c b/gcc/testsuite/gcc.dg/countof-vla.c
new file mode 100644
index 00000000000..ec882d257b8
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/countof-vla.c
@@ -0,0 +1,51 @@
+/* { dg-do compile } */
+/* { dg-options "-Wno-pedantic -Wvla-parameter" } */
+
+void fix_fix (int i,
+	      char (*a)[3][5],
+	      int (*x)[_Countof (*a)],
+	      short (*)[_Generic(x, int (*)[3]: 1)]);
+void fix_var (int i,
+	      char (*a)[3][i], /* dg-warn "variable" */
+	      int (*x)[_Countof (*a)],
+	      short (*)[_Generic(x, int (*)[3]: 1)]);
+void fix_uns (int i,
+	      char (*a)[3][*],
+	      int (*x)[_Countof (*a)],
+	      short (*)[_Generic(x, int (*)[3]: 1)]);
+
+void zro_fix (int i,
+	      char (*a)[0][5],
+	      int (*x)[_Countof (*a)],
+	      short (*)[_Generic(x, int (*)[3]: 1)]);
+void zro_var (int i,
+	      char (*a)[0][i], /* dg-warn "variable" */
+	      int (*x)[_Countof (*a)],
+	      short (*)[_Generic(x, int (*)[3]: 1)]);
+void zro_uns (int i,
+	      char (*a)[0][*],
+	      int (*x)[_Countof (*a)],
+	      short (*)[_Generic(x, int (*)[3]: 1)]);
+
+void var_fix (int i,
+	      char (*a)[i][5], /* dg-warn "variable" */
+	      int (*x)[_Countof (*a)]); /* dg-warn "variable" */
+void var_var (int i,
+	      char (*a)[i][i], /* dg-warn "variable" */
+	      int (*x)[_Countof (*a)]); /* dg-warn "variable" */
+void var_uns (int i,
+	      char (*a)[i][*], /* dg-warn "variable" */
+	      int (*x)[_Countof (*a)]); /* dg-warn "variable" */
+
+void uns_fix (int i,
+	      char (*a)[*][5],
+	      int (*x)[_Countof (*a)]);
+void uns_var (int i,
+	      char (*a)[*][i], /* dg-warn "variable" */
+	      int (*x)[_Countof (*a)]);
+void uns_uns (int i,
+	      char (*a)[*][*],
+	      int (*x)[_Countof (*a)]);
+
+static int z2[0];
+static int y2[_Countof (z2)];
diff --git a/gcc/testsuite/gcc.dg/countof.c b/gcc/testsuite/gcc.dg/countof.c
new file mode 100644
index 00000000000..fc8f4a9405c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/countof.c
@@ -0,0 +1,154 @@
+/* { 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 (_Countof (a) == 7);
+  static_assert (_Countof (long [0]) == 0);
+  static_assert (_Countof (unsigned [99]) == 99);
+}
+
+void
+completed (void)
+{
+  int a[] = {1, 2, 3};
+  int z[] = {};
+
+  static_assert (_Countof (a) == 3);
+  static_assert (_Countof (z) == 0);
+}
+
+void
+vla (void)
+{
+  unsigned n;
+
+  n = 99;
+  assert (_Countof (short [n - 10]) == 99 - 10);
+
+  int v[n / 2];
+  assert (_Countof (v) == 99 / 2);
+
+  n = 0;
+  int z[n];
+  assert (_Countof (z) == 0);
+}
+
+void
+member (void)
+{
+  struct {
+    int a[8];
+  } s;
+
+  static_assert (_Countof (s.a) == 8);
+}
+
+void
+vla_eval (void)
+{
+  int i;
+
+  i = 7;
+  assert (_Countof (struct {int x;}[i++]) == 7);
+  assert (i == 7 + 1);
+
+  int v[i];
+  int (*p)[i];
+  p = &v;
+  assert (_Countof (*p++) == i);
+  assert (p - 1 == &v);
+}
+
+void
+inner_vla_noeval (void)
+{
+  int i;
+
+  i = 3;
+  static_assert (_Countof (struct {int x[i++];}[3]) == 3);
+  assert (i == 3);
+}
+
+void
+array_noeval (void)
+{
+  long a[5];
+  long (*p)[_Countof (a)];
+
+  p = &a;
+  static_assert (_Countof (*p++) == 5);
+  assert (p == &a);
+}
+
+void
+matrix_zero (void)
+{
+  int i;
+
+  static_assert (_Countof (int [0][4]) == 0);
+  i = 3;
+  static_assert (_Countof (int [0][i]) == 0);
+}
+
+void
+matrix_fixed (void)
+{
+  int i;
+
+  static_assert (_Countof (int [7][4]) == 7);
+  i = 3;
+  static_assert (_Countof (int [7][i]) == 7);
+}
+
+void
+matrix_vla (void)
+{
+  int i, j;
+
+  i = 7;
+  assert (_Countof (int [i++][4]) == 7);
+  assert (i == 7 + 1);
+
+  i = 0;
+  assert (_Countof (int [i++][4]) == 0);
+  assert (i == 0 + 1);
+
+  i = 9;
+  j = 3;
+  assert (_Countof (int [i++][j]) == 9);
+  assert (i == 9 + 1);
+}
+
+void
+no_parens(void)
+{
+  int n = 3;
+  int a[7];
+  int v[n];
+
+  static_assert (_Countof a == 7); 
+  assert (_Countof v == 3); 
+}
+
+int
+main (void)
+{
+  array ();
+  completed ();
+  vla ();
+  member ();
+  vla_eval ();
+  inner_vla_noeval ();
+  array_noeval ();
+  matrix_zero ();
+  matrix_fixed ();
+  matrix_vla ();
+  no_parens ();
+}
-- 
2.49.0


^ permalink raw reply	[flat|nested] 318+ messages in thread

* [PATCH v20 3/4] c: Add <stdcountof.h>
  2025-05-11 14:11   ` [PATCH v20 0/4] c: Add _Countof and <stdcountof.h> Alejandro Colomar
  2025-05-11 14:11     ` [PATCH v20 1/4] contrib/: Add support for Link: tags Alejandro Colomar
  2025-05-11 14:12     ` [PATCH v20 2/4] c: Add _Countof operator Alejandro Colomar
@ 2025-05-11 14:12     ` Alejandro Colomar
  2025-05-12 10:54       ` Joseph Myers
  2025-05-11 14:12     ` [PATCH v20 4/4] c: Add -Wpedantic diagnostic for _Countof Alejandro Colomar
  2025-05-12 10:49     ` [PATCH v20 0/4] c: Add _Countof and <stdcountof.h> Joseph Myers
  4 siblings, 1 reply; 318+ messages in thread
From: Alejandro Colomar @ 2025-05-11 14:12 UTC (permalink / raw)
  To: gcc-patches
  Cc: Alejandro Colomar, Martin Uecker, JeanHeyd Meneide, Joseph Myers,
	Jakub Jelinek

gcc/ChangeLog:

	* Makefile.in (USER_H): Add <stdcountof.h>.
	* ginclude/stdcountof.h: Add countof macro.

Signed-off-by: Alejandro Colomar <alx@kernel.org>
---
 gcc/Makefile.in           |  1 +
 gcc/ginclude/stdcountof.h | 31 +++++++++++++++++++++++++++++++
 2 files changed, 32 insertions(+)
 create mode 100644 gcc/ginclude/stdcountof.h

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index e3af923e0e0..8d5d357632e 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -481,6 +481,7 @@ USER_H = $(srcdir)/ginclude/float.h \
 	 $(srcdir)/ginclude/stdalign.h \
 	 $(srcdir)/ginclude/stdatomic.h \
 	 $(srcdir)/ginclude/stdckdint.h \
+	 $(srcdir)/ginclude/stdcountof.h \
 	 $(EXTRA_HEADERS)
 
 USER_H_INC_NEXT_PRE = @user_headers_inc_next_pre@
diff --git a/gcc/ginclude/stdcountof.h b/gcc/ginclude/stdcountof.h
new file mode 100644
index 00000000000..1d914f40e5d
--- /dev/null
+++ b/gcc/ginclude/stdcountof.h
@@ -0,0 +1,31 @@
+/* Copyright (C) 2025 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/>.  */
+
+/* ISO C2Y: 7.21 Array count <stdcountof.h>.  */
+
+#ifndef _STDCOUNTOF_H
+#define _STDCOUNTOF_H
+
+#define countof  _Countof
+
+#endif	/* stdcountof.h */
-- 
2.49.0


^ permalink raw reply	[flat|nested] 318+ messages in thread

* [PATCH v20 4/4] c: Add -Wpedantic diagnostic for _Countof
  2025-05-11 14:11   ` [PATCH v20 0/4] c: Add _Countof and <stdcountof.h> Alejandro Colomar
                       ` (2 preceding siblings ...)
  2025-05-11 14:12     ` [PATCH v20 3/4] c: Add <stdcountof.h> Alejandro Colomar
@ 2025-05-11 14:12     ` Alejandro Colomar
  2025-05-12 10:49     ` [PATCH v20 0/4] c: Add _Countof and <stdcountof.h> Joseph Myers
  4 siblings, 0 replies; 318+ messages in thread
From: Alejandro Colomar @ 2025-05-11 14:12 UTC (permalink / raw)
  To: gcc-patches
  Cc: Alejandro Colomar, Martin Uecker, JeanHeyd Meneide, Joseph Myers,
	Jakub Jelinek

It is not supported in <= C23 mode.

gcc/c/ChangeLog:

	* c-parser.cc (c_parser_sizeof_or_countof_expression):
	Add -Wpedantic diagnostic for _Countof in <= C23 mode.

Signed-off-by: Alejandro Colomar <alx@kernel.org>
---
 gcc/c/c-parser.cc | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
index 87700339394..d2193ad2f34 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -10637,6 +10637,10 @@ c_parser_sizeof_or_countof_expression (c_parser *parser, enum rid rid)
 
   start = c_parser_peek_token (parser)->location;
 
+  if (rid == RID_COUNTOF)
+    pedwarn_c23 (start, OPT_Wpedantic,
+		 "ISO C does not support %qs before C23", op_name);
+
   c_parser_consume_token (parser);
   c_inhibit_evaluation_warnings++;
   if (rid == RID_COUNTOF)
-- 
2.49.0


^ permalink raw reply	[flat|nested] 318+ messages in thread

* Re: [PATCH v20 0/4] c: Add _Countof and <stdcountof.h>
  2025-05-11 14:11   ` [PATCH v20 0/4] c: Add _Countof and <stdcountof.h> Alejandro Colomar
                       ` (3 preceding siblings ...)
  2025-05-11 14:12     ` [PATCH v20 4/4] c: Add -Wpedantic diagnostic for _Countof Alejandro Colomar
@ 2025-05-12 10:49     ` Joseph Myers
  4 siblings, 0 replies; 318+ messages in thread
From: Joseph Myers @ 2025-05-12 10:49 UTC (permalink / raw)
  To: Alejandro Colomar
  Cc: gcc-patches, Martin Uecker, JeanHeyd Meneide, Jakub Jelinek

On Sun, 11 May 2025, Alejandro Colomar wrote:

> Hi,
> 
> Here's the list of changes in v20:
> 
> -  Drop changes to support Cc tags in commit messages (but keep the
>    patch to add support for Link tags).

That patch *does not belong in this series*.  Keep the series to only 
those patches concerned with the C standard feature, and eliminate the 
contrib/ change from the series.  You can submit it separately if you 
want.  If a change with Link: gets approved before the contrib/ change, 
just change Link: into free-form text in the commit message referencing 
the relevant URLs.

-- 
Joseph S. Myers
josmyers@redhat.com


^ permalink raw reply	[flat|nested] 318+ messages in thread

* Re: [PATCH v20 2/4] c: Add _Countof operator
  2025-05-11 14:12     ` [PATCH v20 2/4] c: Add _Countof operator Alejandro Colomar
@ 2025-05-12 10:54       ` Joseph Myers
  2025-05-12 15:14         ` Alejandro Colomar
  0 siblings, 1 reply; 318+ messages in thread
From: Joseph Myers @ 2025-05-12 10:54 UTC (permalink / raw)
  To: Alejandro Colomar
  Cc: gcc-patches, Martin Uecker, JeanHeyd Meneide, Jakub Jelinek,
	Xavier Del Campo Romero, James K. Lowden

On Sun, 11 May 2025, Alejandro Colomar wrote:

> +/* { dg-options "-Wno-declaration-after-statement -Wno-pedantic -Wno-vla" } */

> +/* { dg-options "-Wno-pedantic -Wvla-parameter" } */

> +/* { dg-options "-Wno-declaration-after-statement -Wno-pedantic -Wno-vla" } */

Most of these options are suspect, considering they are the default.

The main tests should use -std=c2y -pedantic-errors, except for any tests 
that specifically involve GNU extensions.  Then there should be separate 
tests for the -pedantic handling for older C standard versions (-std=c23 
-pedantic, -std=c23 -pedantic-errors, -std=c23 -pedantic-errors 
-Wno-c23-c2y-compat, -std=c2y -pedantic-errors -Wc23-c2y-compat).

-- 
Joseph S. Myers
josmyers@redhat.com


^ permalink raw reply	[flat|nested] 318+ messages in thread

* Re: [PATCH v20 3/4] c: Add <stdcountof.h>
  2025-05-11 14:12     ` [PATCH v20 3/4] c: Add <stdcountof.h> Alejandro Colomar
@ 2025-05-12 10:54       ` Joseph Myers
  2025-05-12 14:50         ` Alejandro Colomar
  0 siblings, 1 reply; 318+ messages in thread
From: Joseph Myers @ 2025-05-12 10:54 UTC (permalink / raw)
  To: Alejandro Colomar
  Cc: gcc-patches, Martin Uecker, JeanHeyd Meneide, Jakub Jelinek

On Sun, 11 May 2025, Alejandro Colomar wrote:

> gcc/ChangeLog:
> 
> 	* Makefile.in (USER_H): Add <stdcountof.h>.
> 	* ginclude/stdcountof.h: Add countof macro.

This is missing tests for the header.

-- 
Joseph S. Myers
josmyers@redhat.com


^ permalink raw reply	[flat|nested] 318+ messages in thread

* Re: [PATCH v20 3/4] c: Add <stdcountof.h>
  2025-05-12 10:54       ` Joseph Myers
@ 2025-05-12 14:50         ` Alejandro Colomar
  0 siblings, 0 replies; 318+ messages in thread
From: Alejandro Colomar @ 2025-05-12 14:50 UTC (permalink / raw)
  To: Joseph Myers; +Cc: gcc-patches, Martin Uecker, JeanHeyd Meneide, Jakub Jelinek

[-- Attachment #1: Type: text/plain, Size: 656 bytes --]

On Mon, May 12, 2025 at 10:54:52AM +0000, Joseph Myers wrote:
> On Sun, 11 May 2025, Alejandro Colomar wrote:
> 
> > gcc/ChangeLog:
> > 
> > 	* Makefile.in (USER_H): Add <stdcountof.h>.
> > 	* ginclude/stdcountof.h: Add countof macro.
> 
> This is missing tests for the header.

Hi Joseph,

Yep, I hadn't found any existing tests to base mine on.  It seems I
didn't search well, because now I've found gcc.dg/c11-align-2.c, which
is precisely what I needed.  I've included tests for v21.  They're
quite simple, since the operator is already tested in its own tests.


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] 318+ messages in thread

* Re: [PATCH v20 2/4] c: Add _Countof operator
  2025-05-12 10:54       ` Joseph Myers
@ 2025-05-12 15:14         ` Alejandro Colomar
  0 siblings, 0 replies; 318+ messages in thread
From: Alejandro Colomar @ 2025-05-12 15:14 UTC (permalink / raw)
  To: Joseph Myers
  Cc: gcc-patches, Martin Uecker, JeanHeyd Meneide, Jakub Jelinek,
	Xavier Del Campo Romero, James K. Lowden

[-- Attachment #1: Type: text/plain, Size: 1120 bytes --]

On Mon, May 12, 2025 at 10:54:34AM +0000, Joseph Myers wrote:
> On Sun, 11 May 2025, Alejandro Colomar wrote:
> 
> > +/* { dg-options "-Wno-declaration-after-statement -Wno-pedantic -Wno-vla" } */
> 
> > +/* { dg-options "-Wno-pedantic -Wvla-parameter" } */
> 
> > +/* { dg-options "-Wno-declaration-after-statement -Wno-pedantic -Wno-vla" } */
> 
> Most of these options are suspect, considering they are the default.

Hi Joseph,

Thanks!  I don't remember where I got those from.  It was probably
pasted from whichever file I took to base my tests on, a year ago.  :)

> 
> The main tests should use -std=c2y -pedantic-errors, except for any tests 
> that specifically involve GNU extensions.  Then there should be separate 
> tests for the -pedantic handling for older C standard versions (-std=c23 
> -pedantic, -std=c23 -pedantic-errors, -std=c23 -pedantic-errors 
> -Wno-c23-c2y-compat, -std=c2y -pedantic-errors -Wc23-c2y-compat).

Thanks!  I've prepared that for v21.

Cheers,
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] 318+ messages in thread

* [PATCH v21 0/3] c: Add _Countof and <stdcountof.h>
  2024-07-28 14:15 ` [RFC v1 0/2] c: Add _Lengthof operator Alejandro Colomar
                     ` (23 preceding siblings ...)
  2025-05-11 14:11   ` [PATCH v20 0/4] c: Add _Countof and <stdcountof.h> Alejandro Colomar
@ 2025-05-12 15:53   ` Alejandro Colomar
  2025-05-12 15:53     ` [PATCH v21 1/3] c: Add _Countof operator Alejandro Colomar
                       ` (2 more replies)
  2025-05-15 22:37   ` [PATCH v22 0/3] c: Add _Countof and <stdcountof.h> Alejandro Colomar
                     ` (3 subsequent siblings)
  28 siblings, 3 replies; 318+ messages in thread
From: Alejandro Colomar @ 2025-05-12 15:53 UTC (permalink / raw)
  To: gcc-patches
  Cc: Alejandro Colomar, Martin Uecker, JeanHeyd Meneide, Joseph Myers,
	Jakub Jelinek

Hi!

Here's the list of changes in v21:

-  Drop patch 1 (I've sent it separately, as Joseph requested).
-  Keep Link tags.  This means the other patch is an implicit dependency
   of this patch set.
-  Fix test compiler flags.  [Joseph]
-  Add tests for <stdcountof.h>.  [Joseph]
-  Add tests for pedantic diagnostics.  [Joseph]

I haven't compiled this, but since only tests changed since v20, it
shouldn't fail.  I haven't run `make check` for this revision (nor in
v20).  I will do both things in the following days.  I've run the tests
manually with a build of v20 I had, and they look good.


Have a lovely day!
Alex


Alejandro Colomar (3):
  c: Add _Countof operator
  c: Add <stdcountof.h>
  c: Add -Wpedantic diagnostic for _Countof

 gcc/Makefile.in                               |   1 +
 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                               |  22 ++-
 gcc/c/c-parser.cc                             |  63 +++++--
 gcc/c/c-tree.h                                |   4 +
 gcc/c/c-typeck.cc                             | 115 ++++++++++++-
 gcc/doc/extend.texi                           |  30 ++++
 gcc/ginclude/stdcountof.h                     |  31 ++++
 gcc/testsuite/gcc.dg/countof-compat.c         |   8 +
 gcc/testsuite/gcc.dg/countof-compile.c        | 130 +++++++++++++++
 gcc/testsuite/gcc.dg/countof-no-compat.c      |   5 +
 .../gcc.dg/countof-pedantic-errors.c          |   8 +
 gcc/testsuite/gcc.dg/countof-pedantic.c       |   8 +
 gcc/testsuite/gcc.dg/countof-stdcountof.c     |  21 +++
 gcc/testsuite/gcc.dg/countof-vla.c            |  51 ++++++
 gcc/testsuite/gcc.dg/countof.c                | 154 ++++++++++++++++++
 18 files changed, 658 insertions(+), 24 deletions(-)
 create mode 100644 gcc/ginclude/stdcountof.h
 create mode 100644 gcc/testsuite/gcc.dg/countof-compat.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-compile.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-no-compat.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-pedantic-errors.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-pedantic.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-stdcountof.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-vla.c
 create mode 100644 gcc/testsuite/gcc.dg/countof.c

Range-diff against v20:
1:  0a752a02dd0 < -:  ----------- contrib/: Add support for Link: tags
2:  c28c880f609 ! 1:  432081a4747 c: Add _Countof operator
    @@ gcc/doc/extend.texi: library.
      ## gcc/testsuite/gcc.dg/countof-compile.c (new) ##
     @@
     +/* { dg-do compile } */
    -+/* { dg-options "-Wno-declaration-after-statement -Wno-pedantic -Wno-vla" } */
    ++/* { dg-options "-std=c2y -pedantic-errors" } */
     +
     +#define NULL  ((void *) 0)
     +
    @@ gcc/testsuite/gcc.dg/countof-compile.c (new)
      ## gcc/testsuite/gcc.dg/countof-vla.c (new) ##
     @@
     +/* { dg-do compile } */
    -+/* { dg-options "-Wno-pedantic -Wvla-parameter" } */
    ++/* { dg-options "-std=c2y -pedantic-errors -Wvla-parameter" } */
     +
     +void fix_fix (int i,
     +	      char (*a)[3][5],
    @@ gcc/testsuite/gcc.dg/countof-vla.c (new)
      ## gcc/testsuite/gcc.dg/countof.c (new) ##
     @@
     +/* { dg-do run } */
    -+/* { dg-options "-Wno-declaration-after-statement -Wno-pedantic -Wno-vla" } */
    ++/* { dg-options "-std=c2y -pedantic-errors" } */
     +
     +#undef NDEBUG
     +#include <assert.h>
3:  f6ff1f130de ! 2:  46294255dd8 c: Add <stdcountof.h>
    @@ Commit message
                 * Makefile.in (USER_H): Add <stdcountof.h>.
                 * ginclude/stdcountof.h: Add countof macro.
     
    +    gcc/testsuite/ChangeLog:
    +
    +            * gcc.dg/countof-stdcountof.c: Add tests for <stdcountof.h>.
    +
         Signed-off-by: Alejandro Colomar <alx@kernel.org>
     
      ## gcc/Makefile.in ##
    @@ gcc/ginclude/stdcountof.h (new)
     +#define countof  _Countof
     +
     +#endif	/* stdcountof.h */
    +
    + ## gcc/testsuite/gcc.dg/countof-stdcountof.c (new) ##
    +@@
    ++/* { dg-do run } */
    ++/* { dg-options "-std=c2y -pedantic-errors" } */
    ++
    ++#include <stdcountof.h>
    ++
    ++#ifndef countof
    ++#error "countof not defined"
    ++#endif
    ++
    ++int a[3];
    ++int b[countof a];
    ++
    ++#define str(x) #x
    ++#define xstr(x) str(x)
    ++
    ++int
    ++main (void)
    ++{
    ++  if (strcmp (xstr(countof), "_Alignas") != 0)
    ++    abort ();
    ++}
4:  94bc203a406 ! 3:  20cf2d14d3e c: Add -Wpedantic diagnostic for _Countof
    @@ Metadata
      ## Commit message ##
         c: Add -Wpedantic diagnostic for _Countof
     
    -    It is not supported in <= C23 mode.
    +    It has been standardized in C2y.
     
         gcc/c/ChangeLog:
     
                 * c-parser.cc (c_parser_sizeof_or_countof_expression):
                 Add -Wpedantic diagnostic for _Countof in <= C23 mode.
     
    +    gcc/testsuite/ChangeLog:
    +
    +            * gcc.dg/countof-compat.c
    +            * gcc.dg/countof-no-compat.c
    +            * gcc.dg/countof-pedantic.c
    +            * gcc.dg/countof-pedantic-errors.c:
    +            Test pedantic diagnostics for _Countof.
    +
         Signed-off-by: Alejandro Colomar <alx@kernel.org>
     
      ## gcc/c/c-parser.cc ##
    @@ gcc/c/c-parser.cc: c_parser_sizeof_or_countof_expression (c_parser *parser, enum
        c_parser_consume_token (parser);
        c_inhibit_evaluation_warnings++;
        if (rid == RID_COUNTOF)
    +
    + ## gcc/testsuite/gcc.dg/countof-compat.c (new) ##
    +@@
    ++/* { dg-do compile } */
    ++/* { dg-options "-std=c2y -pedantic-errors -Wc23-c2y-compat" } */
    ++
    ++#include <stdcountof.h>
    ++
    ++int a[1];
    ++int b[countof(a)];
    ++int c[_Countof(a)];  /* { dg-warning "ISO C does not support" */
    +
    + ## gcc/testsuite/gcc.dg/countof-no-compat.c (new) ##
    +@@
    ++/* { dg-do compile } */
    ++/* { dg-options "-std=c23 -pedantic-errors -Wno-c23-c2y-compat" } */
    ++
    ++int a[1];
    ++int b[_Countof(a)];
    +
    + ## gcc/testsuite/gcc.dg/countof-pedantic-errors.c (new) ##
    +@@
    ++/* { dg-do compile } */
    ++/* { dg-options "-std=c23 -pedantic-errors" } */
    ++
    ++#include <stdcountof.h>
    ++
    ++int a[1];
    ++int b[countof(a)];
    ++int c[_Countof(a)];  /* { dg-error "ISO C does not support" */
    +
    + ## gcc/testsuite/gcc.dg/countof-pedantic.c (new) ##
    +@@
    ++/* { dg-do compile } */
    ++/* { dg-options "-std=c23 -pedantic" } */
    ++
    ++#include <stdcountof.h>
    ++
    ++int a[1];
    ++int b[countof(a)];
    ++int c[_Countof(a)];  /* { dg-warning "ISO C does not support" */
-- 
2.49.0


^ permalink raw reply	[flat|nested] 318+ messages in thread

* [PATCH v21 1/3] c: Add _Countof operator
  2025-05-12 15:53   ` [PATCH v21 0/3] " Alejandro Colomar
@ 2025-05-12 15:53     ` Alejandro Colomar
  2025-05-12 17:11       ` Jonathan Wakely
  2025-05-12 15:55     ` [PATCH v21 2/3] c: Add <stdcountof.h> Alejandro Colomar
  2025-05-12 15:55     ` [PATCH v21 3/3] c: Add -Wpedantic diagnostic for _Countof Alejandro Colomar
  2 siblings, 1 reply; 318+ messages in thread
From: Alejandro Colomar @ 2025-05-12 15:53 UTC (permalink / raw)
  To: gcc-patches
  Cc: Alejandro Colomar, Martin Uecker, JeanHeyd Meneide, Joseph Myers,
	Jakub Jelinek, Xavier Del Campo Romero, James K. Lowden

This operator is similar to sizeof but can only be applied to an array,
and returns its number of elements.

FUTURE DIRECTIONS:

-  We should make it work with array parameters to functions,
   and somehow magically return the number of elements of the array,
   regardless of it being really a pointer.

gcc/ChangeLog:

	* doc/extend.texi: Document _Countof operator.

gcc/c-family/ChangeLog:

	* c-common.h
	* c-common.def
	* c-common.cc (c_countof_type): Add _Countof operator.

gcc/c/ChangeLog:

	* c-tree.h
	(c_expr_countof_expr, c_expr_countof_type)
	* c-decl.cc
	(start_struct, finish_struct)
	(start_enum, finish_enum)
	* c-parser.cc
	(c_parser_sizeof_expression)
	(c_parser_countof_expression)
	(c_parser_sizeof_or_countof_expression)
	(c_parser_unary_expression)
	* c-typeck.cc
	(build_external_ref)
	(record_maybe_used_decl)
	(pop_maybe_used)
	(is_top_array_vla)
	(c_expr_countof_expr, c_expr_countof_type):
	Add _Countof operator.

gcc/testsuite/ChangeLog:

	* gcc.dg/countof-compile.c
	* gcc.dg/countof-vla.c
	* gcc.dg/countof.c: Add tests for _Countof operator.

Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3550.pdf>
Link: <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117025>
Link: <https://inbox.sourceware.org/gcc/M8S4oQy--3-2@tutanota.com/T/>
Link: <https://inbox.sourceware.org/gcc-patches/20240728141547.302478-1-alx@kernel.org/T/#t>
Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3313.pdf>
Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3325.pdf>
Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3369.pdf>
Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3469.htm>
Link: <https://github.com/llvm/llvm-project/issues/102836>
Link: <https://thephd.dev/the-big-array-size-survey-for-c>
Link: <https://thephd.dev/the-big-array-size-survey-for-c-results>
Link: <https://stackoverflow.com/questions/37538/#57537491>
Suggested-by: Xavier Del Campo Romero <xavi.dcr@tutanota.com>
Co-authored-by: Martin Uecker <uecker@tugraz.at>
Acked-by: "James K. Lowden" <jklowden@schemamania.org>
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                        |  22 +++-
 gcc/c/c-parser.cc                      |  59 +++++++---
 gcc/c/c-tree.h                         |   4 +
 gcc/c/c-typeck.cc                      | 115 +++++++++++++++++-
 gcc/doc/extend.texi                    |  30 +++++
 gcc/testsuite/gcc.dg/countof-compile.c | 130 +++++++++++++++++++++
 gcc/testsuite/gcc.dg/countof-vla.c     |  51 ++++++++
 gcc/testsuite/gcc.dg/countof.c         | 154 +++++++++++++++++++++++++
 11 files changed, 572 insertions(+), 24 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/countof-compile.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-vla.c
 create mode 100644 gcc/testsuite/gcc.dg/countof.c

diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
index 587d76461e9..f71cb2652d5 100644
--- a/gcc/c-family/c-common.cc
+++ b/gcc/c-family/c-common.cc
@@ -394,6 +394,7 @@ const struct c_common_resword c_common_reswords[] =
 {
   { "_Alignas",		RID_ALIGNAS,   D_CONLY },
   { "_Alignof",		RID_ALIGNOF,   D_CONLY },
+  { "_Countof",		RID_COUNTOF,   D_CONLY },
   { "_Atomic",		RID_ATOMIC,    D_CONLY },
   { "_BitInt",		RID_BITINT,    D_CONLY },
   { "_Bool",		RID_BOOL,      D_CONLY },
@@ -4080,6 +4081,31 @@ c_alignof_expr (location_t loc, tree expr)
 
   return fold_convert_loc (loc, size_type_node, t);
 }
+
+/* Implement the _Countof keyword:
+   Return the number of elements of an array.  */
+
+tree
+c_countof_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 %<_Countof%> to type %qT", type);
+      return error_mark_node;
+    }
+  if (!COMPLETE_TYPE_P (type))
+    {
+      error_at (loc,
+		"invalid application of %<_Countof%> 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 cf2228201fa..0bcc4998afe 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 'countof' expression.  */
+DEFTREECODE (COUNTOF_EXPR, "countof_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 ea6c2975056..91fd120e77e 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_COUNTOF,
   RID_C23_VA_START, RID_VA_ARG,
   RID_EXTENSION, RID_IMAGPART, RID_REALPART, RID_LABEL,    RID_CHOOSE_EXPR,
   RID_TYPES_COMPATIBLE_P,      RID_BUILTIN_COMPLEX,	   RID_BUILTIN_SHUFFLE,
@@ -890,6 +891,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_countof_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 ad66d7d258b..5bf638bfbd8 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -8943,12 +8943,17 @@ 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_countof))
     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"
+		       : "_Countof"))));
 
   if (in_underspecified_init)
     error_at (loc, "%qT defined in underspecified object initializer", ref);
@@ -9923,7 +9928,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_countof)
 	struct_parse_info->struct_types.safe_push (t);
      }
 
@@ -10097,12 +10102,17 @@ 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_countof))
     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"
+		       : "_Countof"))));
 
   if (in_underspecified_init)
     error_at (loc, "%qT defined in underspecified object initializer",
@@ -10296,7 +10306,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_countof)
     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 8a63dc54c79..87700339394 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -77,7 +77,17 @@ along with GCC; see the file COPYING3.  If not see
 #include "asan.h"
 #include "c-family/c-ubsan.h"
 #include "gcc-urlifier.h"
+\f
+#define c_parser_sizeof_expression(parser)                                    \
+(                                                                             \
+  c_parser_sizeof_or_countof_expression (parser, RID_SIZEOF)                  \
+)
 
+#define c_parser_countof_expression(parser)                                   \
+(                                                                             \
+  c_parser_sizeof_or_countof_expression (parser, RID_COUNTOF)                 \
+)
+\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
@@ -1737,7 +1747,8 @@ 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_countof_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 *,
@@ -10572,6 +10583,8 @@ c_parser_unary_expression (c_parser *parser)
     case CPP_KEYWORD:
       switch (c_parser_peek_token (parser)->keyword)
 	{
+	case RID_COUNTOF:
+	  return c_parser_countof_expression (parser);
 	case RID_SIZEOF:
 	  return c_parser_sizeof_expression (parser);
 	case RID_ALIGNOF:
@@ -10611,12 +10624,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_countof_expression (c_parser *parser, enum rid rid)
 {
+  const char *op_name = (rid == RID_COUNTOF) ? "_Countof" : "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;
@@ -10625,7 +10639,10 @@ c_parser_sizeof_expression (c_parser *parser)
 
   c_parser_consume_token (parser);
   c_inhibit_evaluation_warnings++;
-  in_sizeof++;
+  if (rid == RID_COUNTOF)
+    in_countof++;
+  else
+    in_sizeof++;
   if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)
       && c_token_starts_compound_literal (c_parser_peek_2nd_token (parser)))
     {
@@ -10646,7 +10663,7 @@ c_parser_sizeof_expression (c_parser *parser)
 	     for parsing error; the parsing of the expression could have
 	     called record_maybe_used_decl.  */
 	  expr.set_error ();
-	  goto sizeof_expr;
+	  goto Xof_expr;
 	}
       if (c_parser_next_token_is (parser, CPP_OPEN_BRACE))
 	{
@@ -10654,31 +10671,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_COUNTOF)
+	{
+	  in_countof--;
+	  result = c_expr_countof_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_COUNTOF)
+	in_countof--;
+      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_COUNTOF)
+	result = c_expr_countof_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 2098120de29..723a28b3906 100644
--- a/gcc/c/c-tree.h
+++ b/gcc/c/c-tree.h
@@ -765,6 +765,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_countof;
 extern int in_typeof;
 extern bool c_in_omp_for;
 extern bool c_omp_array_section_p;
@@ -827,6 +828,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_countof_expr (location_t, struct c_expr);
+extern struct c_expr c_expr_countof_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 0e1f842e22d..360216b9662 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -72,6 +72,9 @@ int in_alignof;
 /* The level of nesting inside "sizeof".  */
 int in_sizeof;
 
+/* The level of nesting inside "countof".  */
+int in_countof;
+
 /* The level of nesting inside "typeof".  */
 int in_typeof;
 
@@ -3540,7 +3543,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_countof)
 	C_DECL_USED (ref) = 1;
       else if (DECL_INITIAL (ref) == NULL_TREE
 	       && DECL_EXTERNAL (ref)
@@ -3596,7 +3599,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_countof).  */
   int level;
   /* The next one at this level or above, or NULL.  */
   struct maybe_used_decl *next;
@@ -3614,7 +3617,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_countof;
   t->next = maybe_used_decls;
   maybe_used_decls = t;
 }
@@ -3628,7 +3631,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_countof;
   while (p && p->level > cur_level)
     {
       if (used)
@@ -3738,6 +3741,110 @@ 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);
+  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 countof applied to EXPR.  */
+
+struct c_expr
+c_expr_countof_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_countof_type (loc, TREE_TYPE (folded_expr));
+      c_last_sizeof_arg = expr.value;
+      c_last_sizeof_loc = loc;
+      ret.original_code = COUNTOF_EXPR;
+      ret.original_type = NULL;
+      ret.m_decimal = 0;
+      if (is_top_array_vla (TREE_TYPE (folded_expr)))
+	{
+	  /* countof 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 countof applied to T, a structure for the type
+   name passed to countof (rather than the type itself).  LOC is the
+   location of the original expression.  */
+
+struct c_expr
+c_expr_countof_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_countof_type (loc, type);
+  c_last_sizeof_arg = type;
+  c_last_sizeof_loc = loc;
+  ret.original_code = COUNTOF_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 countof does not get folded to a constant by
+	 c_fully_fold, because if the number of elements is evaluated
+	 the result is not constant and so
+	 constraints on zero or negative size arrays must not be applied
+	 when this countof 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/doc/extend.texi b/gcc/doc/extend.texi
index 212d2487558..8b33df20fbc 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -10706,6 +10706,36 @@ library.
 @xref{OpenMP and OpenACC Options}, for additional options useful with
 @option{-fopenacc}.
 
+@node _Countof
+@section Determining the Number of Elements of Arrays
+@cindex _Countof
+@cindex number of elements
+
+The keyword @code{_Countof} determines
+the number of elements of an array operand.
+Its syntax is similar to @code{sizeof}.
+The operand must be
+a parenthesized complete array type name
+or an expression of such a type.
+For example:
+
+@smallexample
+int a[n];
+_Countof (a);  // returns n
+_Countof (int [7][3]);  // returns 7
+@end smallexample
+
+The result of this operator is an integer constant expression,
+unless the array has a variable number of elements.
+The operand is only evaluated
+if the array has a variable number of elements.
+For example:
+
+@smallexample
+_Countof (int [7][n++]);  // integer constant expression
+_Countof (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/testsuite/gcc.dg/countof-compile.c b/gcc/testsuite/gcc.dg/countof-compile.c
new file mode 100644
index 00000000000..777bd6de66a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/countof-compile.c
@@ -0,0 +1,130 @@
+/* { dg-do compile } */
+/* { dg-options "-std=c2y -pedantic-errors" } */
+
+#define NULL  ((void *) 0)
+
+extern int x[];
+
+static int w[] = {1, 2, 3};
+
+static int z[0];
+static int y[_Countof(z)];
+
+void
+completed (void)
+{
+  int i = 42;
+  int a[] = {1, 2, i};
+
+  _Static_assert(_Countof (w) == 3);
+  _Static_assert(_Countof (a) == 3);
+}
+
+void
+incomplete (int p[])
+{
+  _Countof (x);  /* { dg-error "incomplete" } */
+
+  /* We want to support array parameters in the future,
+     which should change this from "invalid" to "incomplete".  */
+  _Countof (p);  /* { dg-error "invalid" } */
+}
+
+void
+fam (void)
+{
+  struct {
+    int x;
+    int fam[];
+  } s;
+
+  _Countof (s.fam); /* { dg-error "incomplete" } */
+}
+
+void
+param (int n, int p[n])
+{
+  /* We want to support array parameters in the future,
+     which would make this work.  */
+  _Countof (p);  /* { dg-error "invalid" } */
+}
+
+void fix_fix (int i, char (*a)[3][5], int (*x)[_Countof (*a)],
+	      short (*)[_Generic(x, int (*)[3]: 1)]);
+void fix_var (int i, char (*a)[3][i], int (*x)[_Countof (*a)],
+	      short (*)[_Generic(x, int (*)[3]: 1)]);
+void fix_uns (int i, char (*a)[3][*], int (*x)[_Countof (*a)],
+	      short (*)[_Generic(x, int (*)[3]: 1)]);
+
+void
+func (void)
+{
+  int  i3[3];
+  int  i5[5];
+  char c35[3][5];
+
+  fix_fix (5, &c35, &i3, NULL);
+  fix_fix (5, &c35, &i5, NULL); /* { dg-error "incompatible-pointer-types" } */
+
+  fix_var (5, &c35, &i3, NULL);
+  fix_var (5, &c35, &i5, NULL); /* { dg-error "incompatible-pointer-types" } */
+
+  fix_uns (5, &c35, &i3, NULL);
+  fix_uns (5, &c35, &i5, NULL); /* { dg-error "incompatible-pointer-types" } */
+}
+
+void
+non_arr(void)
+{
+  int x;
+  int *p;
+  struct s {
+    int x[3];
+  } s;
+
+  _Countof (x); /* { dg-error "invalid" } */
+  _Countof (int); /* { dg-error "invalid" } */
+  _Countof (s); /* { dg-error "invalid" } */
+  _Countof (struct s); /* { dg-error "invalid" } */
+  _Countof (&x); /* { dg-error "invalid" } */
+  _Countof (p); /* { dg-error "invalid" } */
+  _Countof (int *); /* { dg-error "invalid" } */
+  _Countof (&s.x); /* { dg-error "invalid" } */
+  _Countof (int (*)[3]); /* { dg-error "invalid" } */
+}
+
+static int f1();
+static int f2(); /* { dg-warning "never defined" } */
+int a[10][9];
+int n;
+
+void
+syms(void)
+{
+  int b[n][n];
+
+  _Countof (a[f1()]);
+  _Countof (b[f2()]);
+}
+
+void
+no_parens(void)
+{
+  _Static_assert(_Countof a == 10);
+  _Static_assert(_Countof *a == 9);
+  _Static_assert(_Countof (int [3]) {} == 3);
+
+  _Countof int [3]; /* { dg-error "expected expression before" } */
+}
+
+void
+const_expr(void)
+{
+  int n = 7;
+
+  _Static_assert (_Countof (int [3][n]) == 3);
+  _Static_assert (_Countof (int [n][3]) == 7); /* { dg-error "not constant" } */
+  _Static_assert (_Countof (int [0][3]) == 0);
+  _Static_assert (_Countof (int [0]) == 0);
+  _Static_assert (_Countof (int [0][n]) == 0);
+}
diff --git a/gcc/testsuite/gcc.dg/countof-vla.c b/gcc/testsuite/gcc.dg/countof-vla.c
new file mode 100644
index 00000000000..e3d98bc785b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/countof-vla.c
@@ -0,0 +1,51 @@
+/* { dg-do compile } */
+/* { dg-options "-std=c2y -pedantic-errors -Wvla-parameter" } */
+
+void fix_fix (int i,
+	      char (*a)[3][5],
+	      int (*x)[_Countof (*a)],
+	      short (*)[_Generic(x, int (*)[3]: 1)]);
+void fix_var (int i,
+	      char (*a)[3][i], /* dg-warn "variable" */
+	      int (*x)[_Countof (*a)],
+	      short (*)[_Generic(x, int (*)[3]: 1)]);
+void fix_uns (int i,
+	      char (*a)[3][*],
+	      int (*x)[_Countof (*a)],
+	      short (*)[_Generic(x, int (*)[3]: 1)]);
+
+void zro_fix (int i,
+	      char (*a)[0][5],
+	      int (*x)[_Countof (*a)],
+	      short (*)[_Generic(x, int (*)[3]: 1)]);
+void zro_var (int i,
+	      char (*a)[0][i], /* dg-warn "variable" */
+	      int (*x)[_Countof (*a)],
+	      short (*)[_Generic(x, int (*)[3]: 1)]);
+void zro_uns (int i,
+	      char (*a)[0][*],
+	      int (*x)[_Countof (*a)],
+	      short (*)[_Generic(x, int (*)[3]: 1)]);
+
+void var_fix (int i,
+	      char (*a)[i][5], /* dg-warn "variable" */
+	      int (*x)[_Countof (*a)]); /* dg-warn "variable" */
+void var_var (int i,
+	      char (*a)[i][i], /* dg-warn "variable" */
+	      int (*x)[_Countof (*a)]); /* dg-warn "variable" */
+void var_uns (int i,
+	      char (*a)[i][*], /* dg-warn "variable" */
+	      int (*x)[_Countof (*a)]); /* dg-warn "variable" */
+
+void uns_fix (int i,
+	      char (*a)[*][5],
+	      int (*x)[_Countof (*a)]);
+void uns_var (int i,
+	      char (*a)[*][i], /* dg-warn "variable" */
+	      int (*x)[_Countof (*a)]);
+void uns_uns (int i,
+	      char (*a)[*][*],
+	      int (*x)[_Countof (*a)]);
+
+static int z2[0];
+static int y2[_Countof (z2)];
diff --git a/gcc/testsuite/gcc.dg/countof.c b/gcc/testsuite/gcc.dg/countof.c
new file mode 100644
index 00000000000..9ee3e64a73e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/countof.c
@@ -0,0 +1,154 @@
+/* { dg-do run } */
+/* { dg-options "-std=c2y -pedantic-errors" } */
+
+#undef NDEBUG
+#include <assert.h>
+
+void
+array (void)
+{
+  short a[7];
+
+  static_assert (_Countof (a) == 7);
+  static_assert (_Countof (long [0]) == 0);
+  static_assert (_Countof (unsigned [99]) == 99);
+}
+
+void
+completed (void)
+{
+  int a[] = {1, 2, 3};
+  int z[] = {};
+
+  static_assert (_Countof (a) == 3);
+  static_assert (_Countof (z) == 0);
+}
+
+void
+vla (void)
+{
+  unsigned n;
+
+  n = 99;
+  assert (_Countof (short [n - 10]) == 99 - 10);
+
+  int v[n / 2];
+  assert (_Countof (v) == 99 / 2);
+
+  n = 0;
+  int z[n];
+  assert (_Countof (z) == 0);
+}
+
+void
+member (void)
+{
+  struct {
+    int a[8];
+  } s;
+
+  static_assert (_Countof (s.a) == 8);
+}
+
+void
+vla_eval (void)
+{
+  int i;
+
+  i = 7;
+  assert (_Countof (struct {int x;}[i++]) == 7);
+  assert (i == 7 + 1);
+
+  int v[i];
+  int (*p)[i];
+  p = &v;
+  assert (_Countof (*p++) == i);
+  assert (p - 1 == &v);
+}
+
+void
+inner_vla_noeval (void)
+{
+  int i;
+
+  i = 3;
+  static_assert (_Countof (struct {int x[i++];}[3]) == 3);
+  assert (i == 3);
+}
+
+void
+array_noeval (void)
+{
+  long a[5];
+  long (*p)[_Countof (a)];
+
+  p = &a;
+  static_assert (_Countof (*p++) == 5);
+  assert (p == &a);
+}
+
+void
+matrix_zero (void)
+{
+  int i;
+
+  static_assert (_Countof (int [0][4]) == 0);
+  i = 3;
+  static_assert (_Countof (int [0][i]) == 0);
+}
+
+void
+matrix_fixed (void)
+{
+  int i;
+
+  static_assert (_Countof (int [7][4]) == 7);
+  i = 3;
+  static_assert (_Countof (int [7][i]) == 7);
+}
+
+void
+matrix_vla (void)
+{
+  int i, j;
+
+  i = 7;
+  assert (_Countof (int [i++][4]) == 7);
+  assert (i == 7 + 1);
+
+  i = 0;
+  assert (_Countof (int [i++][4]) == 0);
+  assert (i == 0 + 1);
+
+  i = 9;
+  j = 3;
+  assert (_Countof (int [i++][j]) == 9);
+  assert (i == 9 + 1);
+}
+
+void
+no_parens(void)
+{
+  int n = 3;
+  int a[7];
+  int v[n];
+
+  static_assert (_Countof a == 7); 
+  assert (_Countof v == 3); 
+}
+
+int
+main (void)
+{
+  array ();
+  completed ();
+  vla ();
+  member ();
+  vla_eval ();
+  inner_vla_noeval ();
+  array_noeval ();
+  matrix_zero ();
+  matrix_fixed ();
+  matrix_vla ();
+  no_parens ();
+}
-- 
2.49.0


^ permalink raw reply	[flat|nested] 318+ messages in thread

* [PATCH v21 2/3] c: Add <stdcountof.h>
  2025-05-12 15:53   ` [PATCH v21 0/3] " Alejandro Colomar
  2025-05-12 15:53     ` [PATCH v21 1/3] c: Add _Countof operator Alejandro Colomar
@ 2025-05-12 15:55     ` Alejandro Colomar
  2025-05-12 16:43       ` Joseph Myers
  2025-05-12 15:55     ` [PATCH v21 3/3] c: Add -Wpedantic diagnostic for _Countof Alejandro Colomar
  2 siblings, 1 reply; 318+ messages in thread
From: Alejandro Colomar @ 2025-05-12 15:55 UTC (permalink / raw)
  To: gcc-patches
  Cc: Alejandro Colomar, Martin Uecker, JeanHeyd Meneide, Joseph Myers,
	Jakub Jelinek

gcc/ChangeLog:

	* Makefile.in (USER_H): Add <stdcountof.h>.
	* ginclude/stdcountof.h: Add countof macro.

gcc/testsuite/ChangeLog:

	* gcc.dg/countof-stdcountof.c: Add tests for <stdcountof.h>.

Signed-off-by: Alejandro Colomar <alx@kernel.org>
---
 gcc/Makefile.in                           |  1 +
 gcc/ginclude/stdcountof.h                 | 31 +++++++++++++++++++++++
 gcc/testsuite/gcc.dg/countof-stdcountof.c | 21 +++++++++++++++
 3 files changed, 53 insertions(+)
 create mode 100644 gcc/ginclude/stdcountof.h
 create mode 100644 gcc/testsuite/gcc.dg/countof-stdcountof.c

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index e3af923e0e0..8d5d357632e 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -481,6 +481,7 @@ USER_H = $(srcdir)/ginclude/float.h \
 	 $(srcdir)/ginclude/stdalign.h \
 	 $(srcdir)/ginclude/stdatomic.h \
 	 $(srcdir)/ginclude/stdckdint.h \
+	 $(srcdir)/ginclude/stdcountof.h \
 	 $(EXTRA_HEADERS)
 
 USER_H_INC_NEXT_PRE = @user_headers_inc_next_pre@
diff --git a/gcc/ginclude/stdcountof.h b/gcc/ginclude/stdcountof.h
new file mode 100644
index 00000000000..1d914f40e5d
--- /dev/null
+++ b/gcc/ginclude/stdcountof.h
@@ -0,0 +1,31 @@
+/* Copyright (C) 2025 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/>.  */
+
+/* ISO C2Y: 7.21 Array count <stdcountof.h>.  */
+
+#ifndef _STDCOUNTOF_H
+#define _STDCOUNTOF_H
+
+#define countof  _Countof
+
+#endif	/* stdcountof.h */
diff --git a/gcc/testsuite/gcc.dg/countof-stdcountof.c b/gcc/testsuite/gcc.dg/countof-stdcountof.c
new file mode 100644
index 00000000000..6a85386f046
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/countof-stdcountof.c
@@ -0,0 +1,21 @@
+/* { dg-do run } */
+/* { dg-options "-std=c2y -pedantic-errors" } */
+
+#include <stdcountof.h>
+
+#ifndef countof
+#error "countof not defined"
+#endif
+
+int a[3];
+int b[countof a];
+
+#define str(x) #x
+#define xstr(x) str(x)
+
+int
+main (void)
+{
+  if (strcmp (xstr(countof), "_Alignas") != 0)
+    abort ();
+}
-- 
2.49.0


^ permalink raw reply	[flat|nested] 318+ messages in thread

* [PATCH v21 3/3] c: Add -Wpedantic diagnostic for _Countof
  2025-05-12 15:53   ` [PATCH v21 0/3] " Alejandro Colomar
  2025-05-12 15:53     ` [PATCH v21 1/3] c: Add _Countof operator Alejandro Colomar
  2025-05-12 15:55     ` [PATCH v21 2/3] c: Add <stdcountof.h> Alejandro Colomar
@ 2025-05-12 15:55     ` Alejandro Colomar
  2 siblings, 0 replies; 318+ messages in thread
From: Alejandro Colomar @ 2025-05-12 15:55 UTC (permalink / raw)
  To: gcc-patches
  Cc: Alejandro Colomar, Martin Uecker, JeanHeyd Meneide, Joseph Myers,
	Jakub Jelinek

It has been standardized in C2y.

gcc/c/ChangeLog:

	* c-parser.cc (c_parser_sizeof_or_countof_expression):
	Add -Wpedantic diagnostic for _Countof in <= C23 mode.

gcc/testsuite/ChangeLog:

	* gcc.dg/countof-compat.c
	* gcc.dg/countof-no-compat.c
	* gcc.dg/countof-pedantic.c
	* gcc.dg/countof-pedantic-errors.c:
	Test pedantic diagnostics for _Countof.

Signed-off-by: Alejandro Colomar <alx@kernel.org>
---
 gcc/c/c-parser.cc                              | 4 ++++
 gcc/testsuite/gcc.dg/countof-compat.c          | 8 ++++++++
 gcc/testsuite/gcc.dg/countof-no-compat.c       | 5 +++++
 gcc/testsuite/gcc.dg/countof-pedantic-errors.c | 8 ++++++++
 gcc/testsuite/gcc.dg/countof-pedantic.c        | 8 ++++++++
 5 files changed, 33 insertions(+)
 create mode 100644 gcc/testsuite/gcc.dg/countof-compat.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-no-compat.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-pedantic-errors.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-pedantic.c

diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
index 87700339394..d2193ad2f34 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -10637,6 +10637,10 @@ c_parser_sizeof_or_countof_expression (c_parser *parser, enum rid rid)
 
   start = c_parser_peek_token (parser)->location;
 
+  if (rid == RID_COUNTOF)
+    pedwarn_c23 (start, OPT_Wpedantic,
+		 "ISO C does not support %qs before C23", op_name);
+
   c_parser_consume_token (parser);
   c_inhibit_evaluation_warnings++;
   if (rid == RID_COUNTOF)
diff --git a/gcc/testsuite/gcc.dg/countof-compat.c b/gcc/testsuite/gcc.dg/countof-compat.c
new file mode 100644
index 00000000000..e1278d28c5e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/countof-compat.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-std=c2y -pedantic-errors -Wc23-c2y-compat" } */
+
+#include <stdcountof.h>
+
+int a[1];
+int b[countof(a)];
+int c[_Countof(a)];  /* { dg-warning "ISO C does not support" */
diff --git a/gcc/testsuite/gcc.dg/countof-no-compat.c b/gcc/testsuite/gcc.dg/countof-no-compat.c
new file mode 100644
index 00000000000..4a244cf222f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/countof-no-compat.c
@@ -0,0 +1,5 @@
+/* { dg-do compile } */
+/* { dg-options "-std=c23 -pedantic-errors -Wno-c23-c2y-compat" } */
+
+int a[1];
+int b[_Countof(a)];
diff --git a/gcc/testsuite/gcc.dg/countof-pedantic-errors.c b/gcc/testsuite/gcc.dg/countof-pedantic-errors.c
new file mode 100644
index 00000000000..d7992c75865
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/countof-pedantic-errors.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-std=c23 -pedantic-errors" } */
+
+#include <stdcountof.h>
+
+int a[1];
+int b[countof(a)];
+int c[_Countof(a)];  /* { dg-error "ISO C does not support" */
diff --git a/gcc/testsuite/gcc.dg/countof-pedantic.c b/gcc/testsuite/gcc.dg/countof-pedantic.c
new file mode 100644
index 00000000000..76ff1c72807
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/countof-pedantic.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-std=c23 -pedantic" } */
+
+#include <stdcountof.h>
+
+int a[1];
+int b[countof(a)];
+int c[_Countof(a)];  /* { dg-warning "ISO C does not support" */
-- 
2.49.0


^ permalink raw reply	[flat|nested] 318+ messages in thread

* Re: [PATCH v21 2/3] c: Add <stdcountof.h>
  2025-05-12 15:55     ` [PATCH v21 2/3] c: Add <stdcountof.h> Alejandro Colomar
@ 2025-05-12 16:43       ` Joseph Myers
  2025-05-12 22:04         ` Alejandro Colomar
  0 siblings, 1 reply; 318+ messages in thread
From: Joseph Myers @ 2025-05-12 16:43 UTC (permalink / raw)
  To: Alejandro Colomar
  Cc: gcc-patches, Martin Uecker, JeanHeyd Meneide, Jakub Jelinek

On Mon, 12 May 2025, Alejandro Colomar wrote:

> +  if (strcmp (xstr(countof), "_Alignas") != 0)

countof should definitely not expand to _Alignas!  I don't recommend 
posting untested patches.

-- 
Joseph S. Myers
josmyers@redhat.com


^ permalink raw reply	[flat|nested] 318+ messages in thread

* Re: [PATCH v21 1/3] c: Add _Countof operator
  2025-05-12 15:53     ` [PATCH v21 1/3] c: Add _Countof operator Alejandro Colomar
@ 2025-05-12 17:11       ` Jonathan Wakely
  2025-05-12 22:15         ` Alejandro Colomar
  0 siblings, 1 reply; 318+ messages in thread
From: Jonathan Wakely @ 2025-05-12 17:11 UTC (permalink / raw)
  To: Alejandro Colomar
  Cc: gcc-patches, Martin Uecker, JeanHeyd Meneide, Joseph Myers,
	Jakub Jelinek, Xavier Del Campo Romero, James K. Lowden

On 12/05/25 17:53 +0200, Alejandro Colomar wrote:
>This operator is similar to sizeof but can only be applied to an array,
>and returns its number of elements.
>
>FUTURE DIRECTIONS:
>
>-  We should make it work with array parameters to functions,
>   and somehow magically return the number of elements of the array,
>   regardless of it being really a pointer.
>
>gcc/ChangeLog:
>
>	* doc/extend.texi: Document _Countof operator.
>
>gcc/c-family/ChangeLog:
>
>	* c-common.h
>	* c-common.def
>	* c-common.cc (c_countof_type): Add _Countof operator.
>
>gcc/c/ChangeLog:
>
>	* c-tree.h
>	(c_expr_countof_expr, c_expr_countof_type)
>	* c-decl.cc
>	(start_struct, finish_struct)
>	(start_enum, finish_enum)
>	* c-parser.cc
>	(c_parser_sizeof_expression)
>	(c_parser_countof_expression)
>	(c_parser_sizeof_or_countof_expression)
>	(c_parser_unary_expression)
>	* c-typeck.cc
>	(build_external_ref)
>	(record_maybe_used_decl)
>	(pop_maybe_used)
>	(is_top_array_vla)
>	(c_expr_countof_expr, c_expr_countof_type):
>	Add _Countof operator.
>
>gcc/testsuite/ChangeLog:
>
>	* gcc.dg/countof-compile.c
>	* gcc.dg/countof-vla.c
>	* gcc.dg/countof.c: Add tests for _Countof operator.
>
>Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3550.pdf>
>Link: <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117025>
>Link: <https://inbox.sourceware.org/gcc/M8S4oQy--3-2@tutanota.com/T/>
>Link: <https://inbox.sourceware.org/gcc-patches/20240728141547.302478-1-alx@kernel.org/T/#t>
>Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3313.pdf>
>Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3325.pdf>
>Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3369.pdf>
>Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3469.htm>
>Link: <https://github.com/llvm/llvm-project/issues/102836>
>Link: <https://thephd.dev/the-big-array-size-survey-for-c>
>Link: <https://thephd.dev/the-big-array-size-survey-for-c-results>
>Link: <https://stackoverflow.com/questions/37538/#57537491>
>Suggested-by: Xavier Del Campo Romero <xavi.dcr@tutanota.com>
>Co-authored-by: Martin Uecker <uecker@tugraz.at>
>Acked-by: "James K. Lowden" <jklowden@schemamania.org>

What does this Acked-by: indicate?

My guess would be that it indicates approval for the patch, but Jim is
not an approver for the C front end, so he can't approve this patch.
Does Acked-by: indicate something other than approval?  When it's
somebody who can't approve the patch, how is it different to
Reviewed-by:?

I'm not overjoyed by the idea of trailers that mean something in some
other project (e.g. the kernel) but are just co-opted to mean
something slightly (or completely) different in the GCC repo without
some kind of agreement from the community about what they mean *here*.

>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                        |  22 +++-
> gcc/c/c-parser.cc                      |  59 +++++++---
> gcc/c/c-tree.h                         |   4 +
> gcc/c/c-typeck.cc                      | 115 +++++++++++++++++-
> gcc/doc/extend.texi                    |  30 +++++
> gcc/testsuite/gcc.dg/countof-compile.c | 130 +++++++++++++++++++++
> gcc/testsuite/gcc.dg/countof-vla.c     |  51 ++++++++
> gcc/testsuite/gcc.dg/countof.c         | 154 +++++++++++++++++++++++++
> 11 files changed, 572 insertions(+), 24 deletions(-)
> create mode 100644 gcc/testsuite/gcc.dg/countof-compile.c
> create mode 100644 gcc/testsuite/gcc.dg/countof-vla.c
> create mode 100644 gcc/testsuite/gcc.dg/countof.c
>


^ permalink raw reply	[flat|nested] 318+ messages in thread

* Re: [PATCH v21 2/3] c: Add <stdcountof.h>
  2025-05-12 16:43       ` Joseph Myers
@ 2025-05-12 22:04         ` Alejandro Colomar
  0 siblings, 0 replies; 318+ messages in thread
From: Alejandro Colomar @ 2025-05-12 22:04 UTC (permalink / raw)
  To: Joseph Myers; +Cc: gcc-patches, Martin Uecker, JeanHeyd Meneide, Jakub Jelinek

[-- Attachment #1: Type: text/plain, Size: 501 bytes --]

Hi Joseph,

On Mon, May 12, 2025 at 04:43:45PM +0000, Joseph Myers wrote:
> On Mon, 12 May 2025, Alejandro Colomar wrote:
> 
> > +  if (strcmp (xstr(countof), "_Alignas") != 0)
> 
> countof should definitely not expand to _Alignas!

D'oh!  :-)

>  I don't recommend 
> posting untested patches.

I should have run them.  I did build them, though.  At least I wrote a
notice saying I didn't run the tests.  :)


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] 318+ messages in thread

* Re: [PATCH v21 1/3] c: Add _Countof operator
  2025-05-12 17:11       ` Jonathan Wakely
@ 2025-05-12 22:15         ` Alejandro Colomar
  2025-05-13  9:39           ` Jonathan Wakely
  0 siblings, 1 reply; 318+ messages in thread
From: Alejandro Colomar @ 2025-05-12 22:15 UTC (permalink / raw)
  To: Jonathan Wakely
  Cc: gcc-patches, Martin Uecker, JeanHeyd Meneide, Joseph Myers,
	Jakub Jelinek, Xavier Del Campo Romero, James K. Lowden

[-- Attachment #1: Type: text/plain, Size: 3738 bytes --]

Hi Jonathan,

On Mon, May 12, 2025 at 06:11:18PM +0100, Jonathan Wakely wrote:
> On 12/05/25 17:53 +0200, Alejandro Colomar wrote:
> > Suggested-by: Xavier Del Campo Romero <xavi.dcr@tutanota.com>
> > Co-authored-by: Martin Uecker <uecker@tugraz.at>
> > Acked-by: "James K. Lowden" <jklowden@schemamania.org>
> 
> What does this Acked-by: indicate?

<https://www.kernel.org/doc/html/latest/process/submitting-patches.html#when-to-use-acked-by-cc-and-co-developed-by>

	Acked-by: may also be used by other stakeholders, such as people
	with domain knowledge (e.g. the original author of the code
	being modified), userspace-side reviewers for a kernel uAPI
	patch or key users of a feature.

	[...]

	Acked-by: is also less formal than Reviewed-by:.  For instance,
	maintainers may use it to signify that they are OK with a patch
	landing, but they may not have reviewed it as thoroughly as if a
	Reviewed-by: was provided.  Similarly, a key user may not have
	carried out a technical review of the patch, yet they may be
	satisfied with the general approach, the feature or the
	user-facing interface.

> My guess would be that it indicates approval for the patch, but Jim is
> not an approver for the C front end, so he can't approve this patch.

That would be a Reviewed-by:.  Acked-by: can be used by a reviewer when
they like the patch but haven't reviewed as seriously as a Reviewed-by:
tag would imply.  It can also be used --like in this case-- for when
someone who can't approve it, still wants to express approval.

> Does Acked-by: indicate something other than approval?

There are degrees of approval.  The formal one would be Reviewed-by:.
The informal one would be Acked-by:.

>  When it's
> somebody who can't approve the patch, how is it different to
> Reviewed-by:?

Someone who can't aapprove the patch wouldn't usually emit a
Reviewed-by:.  Unless they feel so strongly qualified as an exception to
review the patch (e.g., if you review a patch for the man pages about
_Atomic, you could say you've Reviewed-by, because even when you don't
have commit rights, I'm going to trust your review more than my own).

> I'm not overjoyed by the idea of trailers that mean something in some
> other project (e.g. the kernel) but are just co-opted to mean
> something slightly (or completely) different in the GCC repo without
> some kind of agreement from the community about what they mean *here*.

I use them with the exact meaning of
<https://www.kernel.org/doc/html/latest/process/submitting-patches.html#when-to-use-acked-by-cc-and-co-developed-by>.
I would encourage using them.  They convey useful information.


Have a lovely night!
Alex

> 
> > 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                        |  22 +++-
> > gcc/c/c-parser.cc                      |  59 +++++++---
> > gcc/c/c-tree.h                         |   4 +
> > gcc/c/c-typeck.cc                      | 115 +++++++++++++++++-
> > gcc/doc/extend.texi                    |  30 +++++
> > gcc/testsuite/gcc.dg/countof-compile.c | 130 +++++++++++++++++++++
> > gcc/testsuite/gcc.dg/countof-vla.c     |  51 ++++++++
> > gcc/testsuite/gcc.dg/countof.c         | 154 +++++++++++++++++++++++++
> > 11 files changed, 572 insertions(+), 24 deletions(-)
> > create mode 100644 gcc/testsuite/gcc.dg/countof-compile.c
> > create mode 100644 gcc/testsuite/gcc.dg/countof-vla.c
> > create mode 100644 gcc/testsuite/gcc.dg/countof.c
> > 
> 

-- 
<https://www.alejandro-colomar.es/>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 318+ messages in thread

* Re: [PATCH v21 1/3] c: Add _Countof operator
  2025-05-12 22:15         ` Alejandro Colomar
@ 2025-05-13  9:39           ` Jonathan Wakely
  2025-05-13 10:13             ` Alejandro Colomar
  0 siblings, 1 reply; 318+ messages in thread
From: Jonathan Wakely @ 2025-05-13  9:39 UTC (permalink / raw)
  To: Alejandro Colomar
  Cc: gcc-patches, Martin Uecker, JeanHeyd Meneide, Joseph Myers,
	Jakub Jelinek, Xavier Del Campo Romero, James K. Lowden

On Mon, 12 May 2025 at 23:15, Alejandro Colomar <alx@kernel.org> wrote:
>
> Hi Jonathan,
>
> On Mon, May 12, 2025 at 06:11:18PM +0100, Jonathan Wakely wrote:
> > On 12/05/25 17:53 +0200, Alejandro Colomar wrote:
> > > Suggested-by: Xavier Del Campo Romero <xavi.dcr@tutanota.com>
> > > Co-authored-by: Martin Uecker <uecker@tugraz.at>
> > > Acked-by: "James K. Lowden" <jklowden@schemamania.org>
> >
> > What does this Acked-by: indicate?
>
> <https://www.kernel.org/doc/html/latest/process/submitting-patches.html#when-to-use-acked-by-cc-and-co-developed-by>
>
>         Acked-by: may also be used by other stakeholders, such as people
>         with domain knowledge (e.g. the original author of the code
>         being modified), userspace-side reviewers for a kernel uAPI
>         patch or key users of a feature.
>
>         [...]
>
>         Acked-by: is also less formal than Reviewed-by:.  For instance,
>         maintainers may use it to signify that they are OK with a patch
>         landing, but they may not have reviewed it as thoroughly as if a
>         Reviewed-by: was provided.  Similarly, a key user may not have
>         carried out a technical review of the patch, yet they may be
>         satisfied with the general approach, the feature or the
>         user-facing interface.
>
> > My guess would be that it indicates approval for the patch, but Jim is
> > not an approver for the C front end, so he can't approve this patch.
>
> That would be a Reviewed-by:.

In GCC I've been using Reviewed-by: for anybody who reviews a patch,
not necessarily approval from a maintainer.
There are only seven occurrences of Acked-by on the gcc master branch.
Four of them are duplicating a Reviewed-by: trailer in the same commit
which seems unnecessary.


>  Acked-by: can be used by a reviewer when
> they like the patch but haven't reviewed as seriously as a Reviewed-by:
> tag would imply.  It can also be used --like in this case-- for when
> someone who can't approve it, still wants to express approval.
>
> > Does Acked-by: indicate something other than approval?
>
> There are degrees of approval.  The formal one would be Reviewed-by:.
> The informal one would be Acked-by:.

Should we agree on

> >  When it's
> > somebody who can't approve the patch, how is it different to
> > Reviewed-by:?
>
> Someone who can't aapprove the patch wouldn't usually emit a
> Reviewed-by:.  Unless they feel so strongly qualified as an exception to
> review the patch (e.g., if you review a patch for the man pages about
> _Atomic, you could say you've Reviewed-by, because even when you don't
> have commit rights, I'm going to trust your review more than my own).
>
> > I'm not overjoyed by the idea of trailers that mean something in some
> > other project (e.g. the kernel) but are just co-opted to mean
> > something slightly (or completely) different in the GCC repo without
> > some kind of agreement from the community about what they mean *here*.
>
> I use them with the exact meaning of
> <https://www.kernel.org/doc/html/latest/process/submitting-patches.html#when-to-use-acked-by-cc-and-co-developed-by>.

Yes, I read that, and "maintainer" seems to have a different meaning
to how we use it in GCC.

"Acked-by: is meant to be used by those responsible for or involved
with the affected code in one way or another. Most commonly, the
maintainer when that maintainer neither contributed to nor forwarded
the patch."
That sounds like approval from a maintainer (in GCC we don't "forward"
patches because we only have one tree, there are no subsystem trees
where work is collected then forwarded to Linus).

And the description of Reviewed-by: doesn't imply approval from a
maintainer, it implies a thorough review by somebody knowledgeable
about the area:
https://www.kernel.org/doc/html/latest/process/submitting-patches.html#reviewer-s-statement-of-oversight

I think the kernel's uses of Reviewed-by: and Acked-by: don't really
map to GCC's development/review/approval model.

For GCC, I think it would make more sense to use Reviewed-by: to mean
somebody competent reviewed the patch, and (if we feel it's needed)
something like Approved-by: to mean formal approval by a maintainer
who is able to approve patches in that area.

If we do want to use Acked-by: for review (possibly informal, or not a
thorough review) and Reviewed-by: for formal approval by a maintainer,
I'd be OK with that but I'd like to see it documented for GCC. The
kernel docs don't really answer my questions about what it means for
GCC, and it seems you and I are already using the trailers
differently.


> I would encourage using them.  They convey useful information.
>
>
> Have a lovely night!
> Alex
>
> >
> > > 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                        |  22 +++-
> > > gcc/c/c-parser.cc                      |  59 +++++++---
> > > gcc/c/c-tree.h                         |   4 +
> > > gcc/c/c-typeck.cc                      | 115 +++++++++++++++++-
> > > gcc/doc/extend.texi                    |  30 +++++
> > > gcc/testsuite/gcc.dg/countof-compile.c | 130 +++++++++++++++++++++
> > > gcc/testsuite/gcc.dg/countof-vla.c     |  51 ++++++++
> > > gcc/testsuite/gcc.dg/countof.c         | 154 +++++++++++++++++++++++++
> > > 11 files changed, 572 insertions(+), 24 deletions(-)
> > > create mode 100644 gcc/testsuite/gcc.dg/countof-compile.c
> > > create mode 100644 gcc/testsuite/gcc.dg/countof-vla.c
> > > create mode 100644 gcc/testsuite/gcc.dg/countof.c
> > >
> >
>
> --
> <https://www.alejandro-colomar.es/>


^ permalink raw reply	[flat|nested] 318+ messages in thread

* Re: [PATCH v21 1/3] c: Add _Countof operator
  2025-05-13  9:39           ` Jonathan Wakely
@ 2025-05-13 10:13             ` Alejandro Colomar
  2025-05-13 10:56               ` Jonathan Wakely
  0 siblings, 1 reply; 318+ messages in thread
From: Alejandro Colomar @ 2025-05-13 10:13 UTC (permalink / raw)
  To: Jonathan Wakely
  Cc: gcc-patches, Martin Uecker, JeanHeyd Meneide, Joseph Myers,
	Jakub Jelinek, Xavier Del Campo Romero, James K. Lowden

[-- Attachment #1: Type: text/plain, Size: 6309 bytes --]

Hi Jonathan,

On Tue, May 13, 2025 at 10:39:21AM +0100, Jonathan Wakely wrote:
> On Mon, 12 May 2025 at 23:15, Alejandro Colomar <alx@kernel.org> wrote:
> > <https://www.kernel.org/doc/html/latest/process/submitting-patches.html#when-to-use-acked-by-cc-and-co-developed-by>
> >
> >         Acked-by: may also be used by other stakeholders, such as people
> >         with domain knowledge (e.g. the original author of the code
> >         being modified), userspace-side reviewers for a kernel uAPI
> >         patch or key users of a feature.
> >
> >         [...]
> >
> >         Acked-by: is also less formal than Reviewed-by:.  For instance,
> >         maintainers may use it to signify that they are OK with a patch
> >         landing, but they may not have reviewed it as thoroughly as if a
> >         Reviewed-by: was provided.  Similarly, a key user may not have
> >         carried out a technical review of the patch, yet they may be
> >         satisfied with the general approach, the feature or the
> >         user-facing interface.
> >
> > > My guess would be that it indicates approval for the patch, but Jim is
> > > not an approver for the C front end, so he can't approve this patch.
> >
> > That would be a Reviewed-by:.
> 
> In GCC I've been using Reviewed-by: for anybody who reviews a patch,
> not necessarily approval from a maintainer.
> There are only seven occurrences of Acked-by on the gcc master branch.
> Four of them are duplicating a Reviewed-by: trailer in the same commit
> which seems unnecessary.
> 
> 
> >  Acked-by: can be used by a reviewer when
> > they like the patch but haven't reviewed as seriously as a Reviewed-by:
> > tag would imply.  It can also be used --like in this case-- for when
> > someone who can't approve it, still wants to express approval.
> >
> > > Does Acked-by: indicate something other than approval?
> >
> > There are degrees of approval.  The formal one would be Reviewed-by:.
> > The informal one would be Acked-by:.
> 
> Should we agree on
> 
> > >  When it's
> > > somebody who can't approve the patch, how is it different to
> > > Reviewed-by:?
> >
> > Someone who can't aapprove the patch wouldn't usually emit a
> > Reviewed-by:.  Unless they feel so strongly qualified as an exception to
> > review the patch (e.g., if you review a patch for the man pages about
> > _Atomic, you could say you've Reviewed-by, because even when you don't
> > have commit rights, I'm going to trust your review more than my own).
> >
> > > I'm not overjoyed by the idea of trailers that mean something in some
> > > other project (e.g. the kernel) but are just co-opted to mean
> > > something slightly (or completely) different in the GCC repo without
> > > some kind of agreement from the community about what they mean *here*.
> >
> > I use them with the exact meaning of
> > <https://www.kernel.org/doc/html/latest/process/submitting-patches.html#when-to-use-acked-by-cc-and-co-developed-by>.
> 
> Yes, I read that, and "maintainer" seems to have a different meaning
> to how we use it in GCC.
> 
> "Acked-by: is meant to be used by those responsible for or involved
> with the affected code in one way or another. Most commonly, the
> maintainer when that maintainer neither contributed to nor forwarded
> the patch."
> That sounds like approval from a maintainer (in GCC we don't "forward"
> patches because we only have one tree, there are no subsystem trees
> where work is collected then forwarded to Linus).
> 
> And the description of Reviewed-by: doesn't imply approval from a
> maintainer, it implies a thorough review by somebody knowledgeable
> about the area:
> https://www.kernel.org/doc/html/latest/process/submitting-patches.html#reviewer-s-statement-of-oversight

Yes.  That means for example it would be appropriate for you to emit
Reviewed-by: in the Linux man-pages project for a patch that changes
_Atomic stuff (as we have something about that pending).  Or glibc
maintainers can emit them for manual pages about APIs that they work
with.

Maintainer isn't a black-or-white thing, at least in some projects, like
the kernel or the man-pages.  It's up to judgement of someone reading a
trailer to know what relation it has with the project or the specific
subsystem.

The actual maintainer that does this, usually is the one that takes the
patch and commits it (adding its Signed-off-by).  The one that signs
is supposed to know the reviewers, and what value brings each review.
So for example, if Joseph will be taking these patches from me, then
it's up to him to evaluate what an Acked-by: from James means.

> I think the kernel's uses of Reviewed-by: and Acked-by: don't really
> map to GCC's development/review/approval model.
> 
> For GCC, I think it would make more sense to use Reviewed-by: to mean
> somebody competent reviewed the patch,

That's already acceptable by the kernel.  It depends on what you
interpret by *competent* and by *reviewed*, but it can be acceptable.

> and (if we feel it's needed)
> something like Approved-by: to mean formal approval by a maintainer
> who is able to approve patches in that area.

I don't think this is necessary, because committers already know which
review means approval (by who emmitted it) and which don't.  So you can
use Reviewed-by: for both formal approval for commit, and for strong
reviews.

> If we do want to use Acked-by: for review (possibly informal, or not a
> thorough review) and Reviewed-by: for formal approval by a maintainer,

I think Acked-by: is still useful for documenting other people doing
light reviews, or simply saying they like the idea of a patch, even if
they didn't thoroughly review it.

> I'd be OK with that but I'd like to see it documented for GCC. The
> kernel docs don't really answer my questions about what it means for
> GCC, and it seems you and I are already using the trailers
> differently.

Okay, that's up to you GCC maintainers to decide and document.  Let me
know if I should change anything in my patches, and feel free to remove
tags when committing my patches if my tags don't match your expectations
of a commit trailer.


Cheers,
Alex

-- 
<https://www.alejandro-colomar.es/>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 318+ messages in thread

* Re: [PATCH v21 1/3] c: Add _Countof operator
  2025-05-13 10:13             ` Alejandro Colomar
@ 2025-05-13 10:56               ` Jonathan Wakely
  0 siblings, 0 replies; 318+ messages in thread
From: Jonathan Wakely @ 2025-05-13 10:56 UTC (permalink / raw)
  To: Alejandro Colomar
  Cc: gcc-patches, Martin Uecker, JeanHeyd Meneide, Joseph Myers,
	Jakub Jelinek, Xavier Del Campo Romero, James K. Lowden

On Tue, 13 May 2025 at 11:13, Alejandro Colomar <alx@kernel.org> wrote:
>
> Hi Jonathan,
>
> On Tue, May 13, 2025 at 10:39:21AM +0100, Jonathan Wakely wrote:
> > On Mon, 12 May 2025 at 23:15, Alejandro Colomar <alx@kernel.org> wrote:
> > > <https://www.kernel.org/doc/html/latest/process/submitting-patches.html#when-to-use-acked-by-cc-and-co-developed-by>
> > >
> > >         Acked-by: may also be used by other stakeholders, such as people
> > >         with domain knowledge (e.g. the original author of the code
> > >         being modified), userspace-side reviewers for a kernel uAPI
> > >         patch or key users of a feature.
> > >
> > >         [...]
> > >
> > >         Acked-by: is also less formal than Reviewed-by:.  For instance,
> > >         maintainers may use it to signify that they are OK with a patch
> > >         landing, but they may not have reviewed it as thoroughly as if a
> > >         Reviewed-by: was provided.  Similarly, a key user may not have
> > >         carried out a technical review of the patch, yet they may be
> > >         satisfied with the general approach, the feature or the
> > >         user-facing interface.
> > >
> > > > My guess would be that it indicates approval for the patch, but Jim is
> > > > not an approver for the C front end, so he can't approve this patch.
> > >
> > > That would be a Reviewed-by:.
> >
> > In GCC I've been using Reviewed-by: for anybody who reviews a patch,
> > not necessarily approval from a maintainer.
> > There are only seven occurrences of Acked-by on the gcc master branch.
> > Four of them are duplicating a Reviewed-by: trailer in the same commit
> > which seems unnecessary.
> >
> >
> > >  Acked-by: can be used by a reviewer when
> > > they like the patch but haven't reviewed as seriously as a Reviewed-by:
> > > tag would imply.  It can also be used --like in this case-- for when
> > > someone who can't approve it, still wants to express approval.
> > >
> > > > Does Acked-by: indicate something other than approval?
> > >
> > > There are degrees of approval.  The formal one would be Reviewed-by:.
> > > The informal one would be Acked-by:.
> >
> > Should we agree on
> >
> > > >  When it's
> > > > somebody who can't approve the patch, how is it different to
> > > > Reviewed-by:?
> > >
> > > Someone who can't aapprove the patch wouldn't usually emit a
> > > Reviewed-by:.  Unless they feel so strongly qualified as an exception to
> > > review the patch (e.g., if you review a patch for the man pages about
> > > _Atomic, you could say you've Reviewed-by, because even when you don't
> > > have commit rights, I'm going to trust your review more than my own).
> > >
> > > > I'm not overjoyed by the idea of trailers that mean something in some
> > > > other project (e.g. the kernel) but are just co-opted to mean
> > > > something slightly (or completely) different in the GCC repo without
> > > > some kind of agreement from the community about what they mean *here*.
> > >
> > > I use them with the exact meaning of
> > > <https://www.kernel.org/doc/html/latest/process/submitting-patches.html#when-to-use-acked-by-cc-and-co-developed-by>.
> >
> > Yes, I read that, and "maintainer" seems to have a different meaning
> > to how we use it in GCC.
> >
> > "Acked-by: is meant to be used by those responsible for or involved
> > with the affected code in one way or another. Most commonly, the
> > maintainer when that maintainer neither contributed to nor forwarded
> > the patch."
> > That sounds like approval from a maintainer (in GCC we don't "forward"
> > patches because we only have one tree, there are no subsystem trees
> > where work is collected then forwarded to Linus).
> >
> > And the description of Reviewed-by: doesn't imply approval from a
> > maintainer, it implies a thorough review by somebody knowledgeable
> > about the area:
> > https://www.kernel.org/doc/html/latest/process/submitting-patches.html#reviewer-s-statement-of-oversight
>
> Yes.  That means for example it would be appropriate for you to emit
> Reviewed-by: in the Linux man-pages project for a patch that changes
> _Atomic stuff (as we have something about that pending).  Or glibc
> maintainers can emit them for manual pages about APIs that they work
> with.
>
> Maintainer isn't a black-or-white thing, at least in some projects, like
> the kernel or the man-pages.  It's up to judgement of someone reading a
> trailer to know what relation it has with the project or the specific
> subsystem.

It is black-or-white for GCC, which is why I think deferring to the
kernel docs is misleading for GCC.


> The actual maintainer that does this, usually is the one that takes the
> patch and commits it (adding its Signed-off-by).  The one that signs
> is supposed to know the reviewers, and what value brings each review.
> So for example, if Joseph will be taking these patches from me, then
> it's up to him to evaluate what an Acked-by: from James means.
>
> > I think the kernel's uses of Reviewed-by: and Acked-by: don't really
> > map to GCC's development/review/approval model.
> >
> > For GCC, I think it would make more sense to use Reviewed-by: to mean
> > somebody competent reviewed the patch,
>
> That's already acceptable by the kernel.  It depends on what you
> interpret by *competent* and by *reviewed*, but it can be acceptable.
>
> > and (if we feel it's needed)
> > something like Approved-by: to mean formal approval by a maintainer
> > who is able to approve patches in that area.
>
> I don't think this is necessary, because committers already know which
> review means approval (by who emmitted it) and which don't.  So you can
> use Reviewed-by: for both formal approval for commit, and for strong
> reviews.
>
> > If we do want to use Acked-by: for review (possibly informal, or not a
> > thorough review) and Reviewed-by: for formal approval by a maintainer,
>
> I think Acked-by: is still useful for documenting other people doing
> light reviews, or simply saying they like the idea of a patch, even if
> they didn't thoroughly review it.
>
> > I'd be OK with that but I'd like to see it documented for GCC. The
> > kernel docs don't really answer my questions about what it means for
> > GCC, and it seems you and I are already using the trailers
> > differently.
>
> Okay, that's up to you GCC maintainers to decide and document.  Let me
> know if I should change anything in my patches, and feel free to remove
> tags when committing my patches if my tags don't match your expectations
> of a commit trailer.
>
>
> Cheers,
> Alex
>
> --
> <https://www.alejandro-colomar.es/>


^ permalink raw reply	[flat|nested] 318+ messages in thread

* [PATCH v22 0/3] c: Add _Countof and <stdcountof.h>
  2024-07-28 14:15 ` [RFC v1 0/2] c: Add _Lengthof operator Alejandro Colomar
                     ` (24 preceding siblings ...)
  2025-05-12 15:53   ` [PATCH v21 0/3] " Alejandro Colomar
@ 2025-05-15 22:37   ` Alejandro Colomar
  2025-05-15 22:37     ` [PATCH v22 1/3] c: Add _Countof operator Alejandro Colomar
                       ` (4 more replies)
  2025-05-21  0:17   ` [PATCH v23 " Alejandro Colomar
                     ` (2 subsequent siblings)
  28 siblings, 5 replies; 318+ messages in thread
From: Alejandro Colomar @ 2025-05-15 22:37 UTC (permalink / raw)
  To: gcc-patches
  Cc: Alejandro Colomar, Martin Uecker, JeanHeyd Meneide, Joseph Myers,
	Jakub Jelinek

Hi,

Here's the patch set.  This time, feature complete, and fully tested
with no regressions.  I'll send a reply with the test results in a
moment.

v22 changes:

-  Move Link: tags to above the changelog, as Jason requested.
-  Update the tests for -pedantic-errors.  Some tests are now errors
   instead of warnings.  I've had to move some tests about GNU
   extensions to new test files, so now it's more granular.  Some tests
   were removed, since I realized they were redundant while moving to
   smaller files.
-  Add <assert.h> (and NDEBUG) to some test files that were missing it,
   and also the forward declaration of strcmp(3).
-  Fix typos in dejagnu diagnostic comments.

Is this ready to merge now, hopefully?  :-)


Have a lovely night!
Alex

Alejandro Colomar (3):
  c: Add _Countof operator
  c: Add <stdcountof.h>
  c: Add -Wpedantic diagnostic for _Countof

 gcc/Makefile.in                               |   1 +
 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                               |  22 +++-
 gcc/c/c-parser.cc                             |  63 +++++++--
 gcc/c/c-tree.h                                |   4 +
 gcc/c/c-typeck.cc                             | 115 +++++++++++++++-
 gcc/doc/extend.texi                           |  30 +++++
 gcc/ginclude/stdcountof.h                     |  31 +++++
 gcc/testsuite/gcc.dg/countof-compat.c         |   8 ++
 gcc/testsuite/gcc.dg/countof-compile.c        | 124 ++++++++++++++++++
 gcc/testsuite/gcc.dg/countof-no-compat.c      |   5 +
 .../gcc.dg/countof-pedantic-errors.c          |   8 ++
 gcc/testsuite/gcc.dg/countof-pedantic.c       |   8 ++
 gcc/testsuite/gcc.dg/countof-stdcountof.c     |  25 ++++
 gcc/testsuite/gcc.dg/countof-vla.c            |  35 +++++
 gcc/testsuite/gcc.dg/countof-vmt.c            |  21 +++
 gcc/testsuite/gcc.dg/countof-zero-compile.c   |  38 ++++++
 gcc/testsuite/gcc.dg/countof-zero.c           |  32 +++++
 gcc/testsuite/gcc.dg/countof.c                | 121 +++++++++++++++++
 21 files changed, 698 insertions(+), 24 deletions(-)
 create mode 100644 gcc/ginclude/stdcountof.h
 create mode 100644 gcc/testsuite/gcc.dg/countof-compat.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-compile.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-no-compat.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-pedantic-errors.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-pedantic.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-stdcountof.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-vla.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-vmt.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-zero-compile.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-zero.c
 create mode 100644 gcc/testsuite/gcc.dg/countof.c

Range-diff against v21:
1:  432081a4747 ! 1:  1c983c3baa7 c: Add _Countof operator
    @@ Commit message
            and somehow magically return the number of elements of the array,
            regardless of it being really a pointer.
     
    +    Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3550.pdf>
    +    Link: <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117025>
    +    Link: <https://inbox.sourceware.org/gcc/M8S4oQy--3-2@tutanota.com/T/>
    +    Link: <https://inbox.sourceware.org/gcc-patches/20240728141547.302478-1-alx@kernel.org/T/#t>
    +    Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3313.pdf>
    +    Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3325.pdf>
    +    Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3369.pdf>
    +    Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3469.htm>
    +    Link: <https://github.com/llvm/llvm-project/issues/102836>
    +    Link: <https://thephd.dev/the-big-array-size-survey-for-c>
    +    Link: <https://thephd.dev/the-big-array-size-survey-for-c-results>
    +    Link: <https://stackoverflow.com/questions/37538/#57537491>
    +
         gcc/ChangeLog:
     
                 * doc/extend.texi: Document _Countof operator.
    @@ Commit message
     
                 * gcc.dg/countof-compile.c
                 * gcc.dg/countof-vla.c
    +            * gcc.dg/countof-vmt.c
    +            * gcc.dg/countof-zero-compile.c
    +            * gcc.dg/countof-zero.c
                 * gcc.dg/countof.c: Add tests for _Countof operator.
     
    -    Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3550.pdf>
    -    Link: <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117025>
    -    Link: <https://inbox.sourceware.org/gcc/M8S4oQy--3-2@tutanota.com/T/>
    -    Link: <https://inbox.sourceware.org/gcc-patches/20240728141547.302478-1-alx@kernel.org/T/#t>
    -    Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3313.pdf>
    -    Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3325.pdf>
    -    Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3369.pdf>
    -    Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3469.htm>
    -    Link: <https://github.com/llvm/llvm-project/issues/102836>
    -    Link: <https://thephd.dev/the-big-array-size-survey-for-c>
    -    Link: <https://thephd.dev/the-big-array-size-survey-for-c-results>
    -    Link: <https://stackoverflow.com/questions/37538/#57537491>
         Suggested-by: Xavier Del Campo Romero <xavi.dcr@tutanota.com>
         Co-authored-by: Martin Uecker <uecker@tugraz.at>
         Acked-by: "James K. Lowden" <jklowden@schemamania.org>
    @@ gcc/testsuite/gcc.dg/countof-compile.c (new)
     +
     +static int w[] = {1, 2, 3};
     +
    -+static int z[0];
    -+static int y[_Countof(z)];
    -+
     +void
     +completed (void)
     +{
    @@ gcc/testsuite/gcc.dg/countof-compile.c (new)
     +}
     +
     +static int f1();
    -+static int f2(); /* { dg-warning "never defined" } */
    ++static int f2(); /* { dg-error "never defined" } */
     +int a[10][9];
     +int n;
     +
    @@ gcc/testsuite/gcc.dg/countof-compile.c (new)
     +
     +  _Static_assert (_Countof (int [3][n]) == 3);
     +  _Static_assert (_Countof (int [n][3]) == 7); /* { dg-error "not constant" } */
    -+  _Static_assert (_Countof (int [0][3]) == 0);
    -+  _Static_assert (_Countof (int [0]) == 0);
    -+  _Static_assert (_Countof (int [0][n]) == 0);
     +}
     
      ## gcc/testsuite/gcc.dg/countof-vla.c (new) ##
    @@ gcc/testsuite/gcc.dg/countof-vla.c (new)
     +	      int (*x)[_Countof (*a)],
     +	      short (*)[_Generic(x, int (*)[3]: 1)]);
     +
    -+void zro_fix (int i,
    -+	      char (*a)[0][5],
    -+	      int (*x)[_Countof (*a)],
    -+	      short (*)[_Generic(x, int (*)[3]: 1)]);
    -+void zro_var (int i,
    -+	      char (*a)[0][i], /* dg-warn "variable" */
    -+	      int (*x)[_Countof (*a)],
    -+	      short (*)[_Generic(x, int (*)[3]: 1)]);
    -+void zro_uns (int i,
    -+	      char (*a)[0][*],
    -+	      int (*x)[_Countof (*a)],
    -+	      short (*)[_Generic(x, int (*)[3]: 1)]);
    -+
     +void var_fix (int i,
     +	      char (*a)[i][5], /* dg-warn "variable" */
     +	      int (*x)[_Countof (*a)]); /* dg-warn "variable" */
    @@ gcc/testsuite/gcc.dg/countof-vla.c (new)
     +void uns_uns (int i,
     +	      char (*a)[*][*],
     +	      int (*x)[_Countof (*a)]);
    +
    + ## gcc/testsuite/gcc.dg/countof-vmt.c (new) ##
    +@@
    ++/* { dg-do run } */
    ++/* { dg-options "-std=c2y" } */
     +
    -+static int z2[0];
    -+static int y2[_Countof (z2)];
    ++#undef NDEBUG
    ++#include <assert.h>
    ++
    ++void
    ++inner_vla_noeval (void)
    ++{
    ++  int i;
    ++
    ++  i = 3;
    ++  static_assert (_Countof (struct {int x[i++];}[3]) == 3);
    ++  assert (i == 3);
    ++}
    ++
    ++int
    ++main (void)
    ++{
    ++  inner_vla_noeval ();
    ++}
    +
    + ## gcc/testsuite/gcc.dg/countof-zero-compile.c (new) ##
    +@@
    ++/* { dg-do compile } */
    ++/* { dg-options "-std=c2y" } */
    ++
    ++static int z[0];
    ++static int y[_Countof (z)];
    ++
    ++_Static_assert(_Countof (y) == 0);
    ++
    ++void
    ++completed (void)
    ++{
    ++  int z[] = {};
    ++
    ++  static_assert (_Countof (z) == 0);
    ++}
    ++
    ++void zro_fix (int i,
    ++	      char (*a)[0][5],
    ++	      int (*x)[_Countof (*a)],
    ++	      short (*)[_Generic(x, int (*)[0]: 1)]);
    ++void zro_var (int i,
    ++	      char (*a)[0][i], /* dg-warn "variable" */
    ++	      int (*x)[_Countof (*a)],
    ++	      short (*)[_Generic(x, int (*)[0]: 1)]);
    ++void zro_uns (int i,
    ++	      char (*a)[0][*],
    ++	      int (*x)[_Countof (*a)],
    ++	      short (*)[_Generic(x, int (*)[0]: 1)]);
    ++
    ++void
    ++const_expr(void)
    ++{
    ++  int n = 7;
    ++
    ++  _Static_assert (_Countof (int [0][3]) == 0);
    ++  _Static_assert (_Countof (int [0]) == 0);
    ++  _Static_assert (_Countof (int [0][n]) == 0);
    ++}
    +
    + ## gcc/testsuite/gcc.dg/countof-zero.c (new) ##
    +@@
    ++/* { dg-do run } */
    ++/* { dg-options "-std=c2y" } */
    ++
    ++#undef NDEBUG
    ++#include <assert.h>
    ++
    ++void
    ++vla (void)
    ++{
    ++  unsigned n;
    ++
    ++  n = 0;
    ++  int z[n];
    ++  assert (_Countof (z) == 0);
    ++}
    ++
    ++void
    ++matrix_vla (void)
    ++{
    ++  int i;
    ++
    ++  i = 0;
    ++  assert (_Countof (int [i++][4]) == 0);
    ++  assert (i == 0 + 1);
    ++}
    ++
    ++int
    ++main (void)
    ++{
    ++  vla ();
    ++  matrix_vla ();
    ++}
     
      ## gcc/testsuite/gcc.dg/countof.c (new) ##
     @@
    @@ gcc/testsuite/gcc.dg/countof.c (new)
     +  short a[7];
     +
     +  static_assert (_Countof (a) == 7);
    -+  static_assert (_Countof (long [0]) == 0);
     +  static_assert (_Countof (unsigned [99]) == 99);
     +}
     +
    @@ gcc/testsuite/gcc.dg/countof.c (new)
     +completed (void)
     +{
     +  int a[] = {1, 2, 3};
    -+  int z[] = {};
     +
     +  static_assert (_Countof (a) == 3);
    -+  static_assert (_Countof (z) == 0);
     +}
     +
     +void
    @@ gcc/testsuite/gcc.dg/countof.c (new)
     +
     +  int v[n / 2];
     +  assert (_Countof (v) == 99 / 2);
    -+
    -+  n = 0;
    -+  int z[n];
    -+  assert (_Countof (z) == 0);
     +}
     +
     +void
    @@ gcc/testsuite/gcc.dg/countof.c (new)
     +}
     +
     +void
    -+inner_vla_noeval (void)
    -+{
    -+  int i;
    -+
    -+  i = 3;
    -+  static_assert (_Countof (struct {int x[i++];}[3]) == 3);
    -+  assert (i == 3);
    -+}
    -+
    -+void
     +array_noeval (void)
     +{
     +  long a[5];
    @@ gcc/testsuite/gcc.dg/countof.c (new)
     +}
     +
     +void
    -+matrix_zero (void)
    -+{
    -+  int i;
    -+
    -+  static_assert (_Countof (int [0][4]) == 0);
    -+  i = 3;
    -+  static_assert (_Countof (int [0][i]) == 0);
    -+}
    -+
    -+void
     +matrix_fixed (void)
     +{
     +  int i;
    @@ gcc/testsuite/gcc.dg/countof.c (new)
     +  assert (_Countof (int [i++][4]) == 7);
     +  assert (i == 7 + 1);
     +
    -+  i = 0;
    -+  assert (_Countof (int [i++][4]) == 0);
    -+  assert (i == 0 + 1);
    -+
     +  i = 9;
     +  j = 3;
     +  assert (_Countof (int [i++][j]) == 9);
    @@ gcc/testsuite/gcc.dg/countof.c (new)
     +  vla ();
     +  member ();
     +  vla_eval ();
    -+  inner_vla_noeval ();
     +  array_noeval ();
    -+  matrix_zero ();
     +  matrix_fixed ();
     +  matrix_vla ();
     +  no_parens ();
2:  46294255dd8 ! 2:  418f81175e7 c: Add <stdcountof.h>
    @@ gcc/testsuite/gcc.dg/countof-stdcountof.c (new)
     +
     +#include <stdcountof.h>
     +
    ++#undef NDEBUG
    ++#include <assert.h>
    ++
    ++extern int strcmp (const char *, const char *);
    ++
     +#ifndef countof
     +#error "countof not defined"
     +#endif
    @@ gcc/testsuite/gcc.dg/countof-stdcountof.c (new)
     +int
     +main (void)
     +{
    -+  if (strcmp (xstr(countof), "_Alignas") != 0)
    -+    abort ();
    ++  assert (strcmp (xstr(countof), "_Countof") == 0);
     +}
3:  20cf2d14d3e ! 3:  c44ef4a2c75 c: Add -Wpedantic diagnostic for _Countof
    @@ gcc/testsuite/gcc.dg/countof-compat.c (new)
     +
     +int a[1];
     +int b[countof(a)];
    -+int c[_Countof(a)];  /* { dg-warning "ISO C does not support" */
    ++int c[_Countof(a)];  /* { dg-warning "ISO C does not support" } */
     
      ## gcc/testsuite/gcc.dg/countof-no-compat.c (new) ##
     @@
    @@ gcc/testsuite/gcc.dg/countof-pedantic-errors.c (new)
     +
     +int a[1];
     +int b[countof(a)];
    -+int c[_Countof(a)];  /* { dg-error "ISO C does not support" */
    ++int c[_Countof(a)];  /* { dg-error "ISO C does not support" } */
     
      ## gcc/testsuite/gcc.dg/countof-pedantic.c (new) ##
     @@
    @@ gcc/testsuite/gcc.dg/countof-pedantic.c (new)
     +
     +int a[1];
     +int b[countof(a)];
    -+int c[_Countof(a)];  /* { dg-warning "ISO C does not support" */
    ++int c[_Countof(a)];  /* { dg-warning "ISO C does not support" } */
-- 
2.49.0


^ permalink raw reply	[flat|nested] 318+ messages in thread

* [PATCH v22 1/3] c: Add _Countof operator
  2025-05-15 22:37   ` [PATCH v22 0/3] c: Add _Countof and <stdcountof.h> Alejandro Colomar
@ 2025-05-15 22:37     ` Alejandro Colomar
  2025-05-15 22:37     ` [PATCH v22 2/3] c: Add <stdcountof.h> Alejandro Colomar
                       ` (3 subsequent siblings)
  4 siblings, 0 replies; 318+ messages in thread
From: Alejandro Colomar @ 2025-05-15 22:37 UTC (permalink / raw)
  To: gcc-patches
  Cc: Alejandro Colomar, Martin Uecker, JeanHeyd Meneide, Joseph Myers,
	Jakub Jelinek, Xavier Del Campo Romero, James K. Lowden

This operator is similar to sizeof but can only be applied to an array,
and returns its number of elements.

FUTURE DIRECTIONS:

-  We should make it work with array parameters to functions,
   and somehow magically return the number of elements of the array,
   regardless of it being really a pointer.

Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3550.pdf>
Link: <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117025>
Link: <https://inbox.sourceware.org/gcc/M8S4oQy--3-2@tutanota.com/T/>
Link: <https://inbox.sourceware.org/gcc-patches/20240728141547.302478-1-alx@kernel.org/T/#t>
Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3313.pdf>
Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3325.pdf>
Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3369.pdf>
Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3469.htm>
Link: <https://github.com/llvm/llvm-project/issues/102836>
Link: <https://thephd.dev/the-big-array-size-survey-for-c>
Link: <https://thephd.dev/the-big-array-size-survey-for-c-results>
Link: <https://stackoverflow.com/questions/37538/#57537491>

gcc/ChangeLog:

	* doc/extend.texi: Document _Countof operator.

gcc/c-family/ChangeLog:

	* c-common.h
	* c-common.def
	* c-common.cc (c_countof_type): Add _Countof operator.

gcc/c/ChangeLog:

	* c-tree.h
	(c_expr_countof_expr, c_expr_countof_type)
	* c-decl.cc
	(start_struct, finish_struct)
	(start_enum, finish_enum)
	* c-parser.cc
	(c_parser_sizeof_expression)
	(c_parser_countof_expression)
	(c_parser_sizeof_or_countof_expression)
	(c_parser_unary_expression)
	* c-typeck.cc
	(build_external_ref)
	(record_maybe_used_decl)
	(pop_maybe_used)
	(is_top_array_vla)
	(c_expr_countof_expr, c_expr_countof_type):
	Add _Countof operator.

gcc/testsuite/ChangeLog:

	* gcc.dg/countof-compile.c
	* gcc.dg/countof-vla.c
	* gcc.dg/countof-vmt.c
	* gcc.dg/countof-zero-compile.c
	* gcc.dg/countof-zero.c
	* gcc.dg/countof.c: Add tests for _Countof operator.

Suggested-by: Xavier Del Campo Romero <xavi.dcr@tutanota.com>
Co-authored-by: Martin Uecker <uecker@tugraz.at>
Acked-by: "James K. Lowden" <jklowden@schemamania.org>
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                             |  22 +++-
 gcc/c/c-parser.cc                           |  59 +++++++---
 gcc/c/c-tree.h                              |   4 +
 gcc/c/c-typeck.cc                           | 115 +++++++++++++++++-
 gcc/doc/extend.texi                         |  30 +++++
 gcc/testsuite/gcc.dg/countof-compile.c      | 124 ++++++++++++++++++++
 gcc/testsuite/gcc.dg/countof-vla.c          |  35 ++++++
 gcc/testsuite/gcc.dg/countof-vmt.c          |  21 ++++
 gcc/testsuite/gcc.dg/countof-zero-compile.c |  38 ++++++
 gcc/testsuite/gcc.dg/countof-zero.c         |  32 +++++
 gcc/testsuite/gcc.dg/countof.c              | 121 +++++++++++++++++++
 14 files changed, 608 insertions(+), 24 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/countof-compile.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-vla.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-vmt.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-zero-compile.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-zero.c
 create mode 100644 gcc/testsuite/gcc.dg/countof.c

diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
index 587d76461e9..f71cb2652d5 100644
--- a/gcc/c-family/c-common.cc
+++ b/gcc/c-family/c-common.cc
@@ -394,6 +394,7 @@ const struct c_common_resword c_common_reswords[] =
 {
   { "_Alignas",		RID_ALIGNAS,   D_CONLY },
   { "_Alignof",		RID_ALIGNOF,   D_CONLY },
+  { "_Countof",		RID_COUNTOF,   D_CONLY },
   { "_Atomic",		RID_ATOMIC,    D_CONLY },
   { "_BitInt",		RID_BITINT,    D_CONLY },
   { "_Bool",		RID_BOOL,      D_CONLY },
@@ -4080,6 +4081,31 @@ c_alignof_expr (location_t loc, tree expr)
 
   return fold_convert_loc (loc, size_type_node, t);
 }
+
+/* Implement the _Countof keyword:
+   Return the number of elements of an array.  */
+
+tree
+c_countof_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 %<_Countof%> to type %qT", type);
+      return error_mark_node;
+    }
+  if (!COMPLETE_TYPE_P (type))
+    {
+      error_at (loc,
+		"invalid application of %<_Countof%> 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 cf2228201fa..0bcc4998afe 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 'countof' expression.  */
+DEFTREECODE (COUNTOF_EXPR, "countof_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 ea6c2975056..91fd120e77e 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_COUNTOF,
   RID_C23_VA_START, RID_VA_ARG,
   RID_EXTENSION, RID_IMAGPART, RID_REALPART, RID_LABEL,    RID_CHOOSE_EXPR,
   RID_TYPES_COMPATIBLE_P,      RID_BUILTIN_COMPLEX,	   RID_BUILTIN_SHUFFLE,
@@ -890,6 +891,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_countof_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 ad66d7d258b..5bf638bfbd8 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -8943,12 +8943,17 @@ 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_countof))
     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"
+		       : "_Countof"))));
 
   if (in_underspecified_init)
     error_at (loc, "%qT defined in underspecified object initializer", ref);
@@ -9923,7 +9928,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_countof)
 	struct_parse_info->struct_types.safe_push (t);
      }
 
@@ -10097,12 +10102,17 @@ 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_countof))
     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"
+		       : "_Countof"))));
 
   if (in_underspecified_init)
     error_at (loc, "%qT defined in underspecified object initializer",
@@ -10296,7 +10306,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_countof)
     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 8a63dc54c79..87700339394 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -77,7 +77,17 @@ along with GCC; see the file COPYING3.  If not see
 #include "asan.h"
 #include "c-family/c-ubsan.h"
 #include "gcc-urlifier.h"
+\f
+#define c_parser_sizeof_expression(parser)                                    \
+(                                                                             \
+  c_parser_sizeof_or_countof_expression (parser, RID_SIZEOF)                  \
+)
 
+#define c_parser_countof_expression(parser)                                   \
+(                                                                             \
+  c_parser_sizeof_or_countof_expression (parser, RID_COUNTOF)                 \
+)
+\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
@@ -1737,7 +1747,8 @@ 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_countof_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 *,
@@ -10572,6 +10583,8 @@ c_parser_unary_expression (c_parser *parser)
     case CPP_KEYWORD:
       switch (c_parser_peek_token (parser)->keyword)
 	{
+	case RID_COUNTOF:
+	  return c_parser_countof_expression (parser);
 	case RID_SIZEOF:
 	  return c_parser_sizeof_expression (parser);
 	case RID_ALIGNOF:
@@ -10611,12 +10624,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_countof_expression (c_parser *parser, enum rid rid)
 {
+  const char *op_name = (rid == RID_COUNTOF) ? "_Countof" : "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;
@@ -10625,7 +10639,10 @@ c_parser_sizeof_expression (c_parser *parser)
 
   c_parser_consume_token (parser);
   c_inhibit_evaluation_warnings++;
-  in_sizeof++;
+  if (rid == RID_COUNTOF)
+    in_countof++;
+  else
+    in_sizeof++;
   if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)
       && c_token_starts_compound_literal (c_parser_peek_2nd_token (parser)))
     {
@@ -10646,7 +10663,7 @@ c_parser_sizeof_expression (c_parser *parser)
 	     for parsing error; the parsing of the expression could have
 	     called record_maybe_used_decl.  */
 	  expr.set_error ();
-	  goto sizeof_expr;
+	  goto Xof_expr;
 	}
       if (c_parser_next_token_is (parser, CPP_OPEN_BRACE))
 	{
@@ -10654,31 +10671,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_COUNTOF)
+	{
+	  in_countof--;
+	  result = c_expr_countof_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_COUNTOF)
+	in_countof--;
+      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_COUNTOF)
+	result = c_expr_countof_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 2098120de29..723a28b3906 100644
--- a/gcc/c/c-tree.h
+++ b/gcc/c/c-tree.h
@@ -765,6 +765,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_countof;
 extern int in_typeof;
 extern bool c_in_omp_for;
 extern bool c_omp_array_section_p;
@@ -827,6 +828,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_countof_expr (location_t, struct c_expr);
+extern struct c_expr c_expr_countof_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 0e1f842e22d..360216b9662 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -72,6 +72,9 @@ int in_alignof;
 /* The level of nesting inside "sizeof".  */
 int in_sizeof;
 
+/* The level of nesting inside "countof".  */
+int in_countof;
+
 /* The level of nesting inside "typeof".  */
 int in_typeof;
 
@@ -3540,7 +3543,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_countof)
 	C_DECL_USED (ref) = 1;
       else if (DECL_INITIAL (ref) == NULL_TREE
 	       && DECL_EXTERNAL (ref)
@@ -3596,7 +3599,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_countof).  */
   int level;
   /* The next one at this level or above, or NULL.  */
   struct maybe_used_decl *next;
@@ -3614,7 +3617,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_countof;
   t->next = maybe_used_decls;
   maybe_used_decls = t;
 }
@@ -3628,7 +3631,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_countof;
   while (p && p->level > cur_level)
     {
       if (used)
@@ -3738,6 +3741,110 @@ 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);
+  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 countof applied to EXPR.  */
+
+struct c_expr
+c_expr_countof_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_countof_type (loc, TREE_TYPE (folded_expr));
+      c_last_sizeof_arg = expr.value;
+      c_last_sizeof_loc = loc;
+      ret.original_code = COUNTOF_EXPR;
+      ret.original_type = NULL;
+      ret.m_decimal = 0;
+      if (is_top_array_vla (TREE_TYPE (folded_expr)))
+	{
+	  /* countof 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 countof applied to T, a structure for the type
+   name passed to countof (rather than the type itself).  LOC is the
+   location of the original expression.  */
+
+struct c_expr
+c_expr_countof_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_countof_type (loc, type);
+  c_last_sizeof_arg = type;
+  c_last_sizeof_loc = loc;
+  ret.original_code = COUNTOF_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 countof does not get folded to a constant by
+	 c_fully_fold, because if the number of elements is evaluated
+	 the result is not constant and so
+	 constraints on zero or negative size arrays must not be applied
+	 when this countof 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/doc/extend.texi b/gcc/doc/extend.texi
index 40ccf22b29f..18ee287a348 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -10706,6 +10706,36 @@ library.
 @xref{OpenMP and OpenACC Options}, for additional options useful with
 @option{-fopenacc}.
 
+@node _Countof
+@section Determining the Number of Elements of Arrays
+@cindex _Countof
+@cindex number of elements
+
+The keyword @code{_Countof} determines
+the number of elements of an array operand.
+Its syntax is similar to @code{sizeof}.
+The operand must be
+a parenthesized complete array type name
+or an expression of such a type.
+For example:
+
+@smallexample
+int a[n];
+_Countof (a);  // returns n
+_Countof (int [7][3]);  // returns 7
+@end smallexample
+
+The result of this operator is an integer constant expression,
+unless the array has a variable number of elements.
+The operand is only evaluated
+if the array has a variable number of elements.
+For example:
+
+@smallexample
+_Countof (int [7][n++]);  // integer constant expression
+_Countof (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/testsuite/gcc.dg/countof-compile.c b/gcc/testsuite/gcc.dg/countof-compile.c
new file mode 100644
index 00000000000..afd5659618b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/countof-compile.c
@@ -0,0 +1,124 @@
+/* { dg-do compile } */
+/* { dg-options "-std=c2y -pedantic-errors" } */
+
+#define NULL  ((void *) 0)
+
+extern int x[];
+
+static int w[] = {1, 2, 3};
+
+void
+completed (void)
+{
+  int i = 42;
+  int a[] = {1, 2, i};
+
+  _Static_assert(_Countof (w) == 3);
+  _Static_assert(_Countof (a) == 3);
+}
+
+void
+incomplete (int p[])
+{
+  _Countof (x);  /* { dg-error "incomplete" } */
+
+  /* We want to support array parameters in the future,
+     which should change this from "invalid" to "incomplete".  */
+  _Countof (p);  /* { dg-error "invalid" } */
+}
+
+void
+fam (void)
+{
+  struct {
+    int x;
+    int fam[];
+  } s;
+
+  _Countof (s.fam); /* { dg-error "incomplete" } */
+}
+
+void
+param (int n, int p[n])
+{
+  /* We want to support array parameters in the future,
+     which would make this work.  */
+  _Countof (p);  /* { dg-error "invalid" } */
+}
+
+void fix_fix (int i, char (*a)[3][5], int (*x)[_Countof (*a)],
+	      short (*)[_Generic(x, int (*)[3]: 1)]);
+void fix_var (int i, char (*a)[3][i], int (*x)[_Countof (*a)],
+	      short (*)[_Generic(x, int (*)[3]: 1)]);
+void fix_uns (int i, char (*a)[3][*], int (*x)[_Countof (*a)],
+	      short (*)[_Generic(x, int (*)[3]: 1)]);
+
+void
+func (void)
+{
+  int  i3[3];
+  int  i5[5];
+  char c35[3][5];
+
+  fix_fix (5, &c35, &i3, NULL);
+  fix_fix (5, &c35, &i5, NULL); /* { dg-error "incompatible-pointer-types" } */
+
+  fix_var (5, &c35, &i3, NULL);
+  fix_var (5, &c35, &i5, NULL); /* { dg-error "incompatible-pointer-types" } */
+
+  fix_uns (5, &c35, &i3, NULL);
+  fix_uns (5, &c35, &i5, NULL); /* { dg-error "incompatible-pointer-types" } */
+}
+
+void
+non_arr(void)
+{
+  int x;
+  int *p;
+  struct s {
+    int x[3];
+  } s;
+
+  _Countof (x); /* { dg-error "invalid" } */
+  _Countof (int); /* { dg-error "invalid" } */
+  _Countof (s); /* { dg-error "invalid" } */
+  _Countof (struct s); /* { dg-error "invalid" } */
+  _Countof (&x); /* { dg-error "invalid" } */
+  _Countof (p); /* { dg-error "invalid" } */
+  _Countof (int *); /* { dg-error "invalid" } */
+  _Countof (&s.x); /* { dg-error "invalid" } */
+  _Countof (int (*)[3]); /* { dg-error "invalid" } */
+}
+
+static int f1();
+static int f2(); /* { dg-error "never defined" } */
+int a[10][9];
+int n;
+
+void
+syms(void)
+{
+  int b[n][n];
+
+  _Countof (a[f1()]);
+  _Countof (b[f2()]);
+}
+
+void
+no_parens(void)
+{
+  _Static_assert(_Countof a == 10);
+  _Static_assert(_Countof *a == 9);
+  _Static_assert(_Countof (int [3]) {} == 3);
+
+  _Countof int [3]; /* { dg-error "expected expression before" } */
+}
+
+void
+const_expr(void)
+{
+  int n = 7;
+
+  _Static_assert (_Countof (int [3][n]) == 3);
+  _Static_assert (_Countof (int [n][3]) == 7); /* { dg-error "not constant" } */
+}
diff --git a/gcc/testsuite/gcc.dg/countof-vla.c b/gcc/testsuite/gcc.dg/countof-vla.c
new file mode 100644
index 00000000000..cc225df2068
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/countof-vla.c
@@ -0,0 +1,35 @@
+/* { dg-do compile } */
+/* { dg-options "-std=c2y -pedantic-errors -Wvla-parameter" } */
+
+void fix_fix (int i,
+	      char (*a)[3][5],
+	      int (*x)[_Countof (*a)],
+	      short (*)[_Generic(x, int (*)[3]: 1)]);
+void fix_var (int i,
+	      char (*a)[3][i], /* dg-warn "variable" */
+	      int (*x)[_Countof (*a)],
+	      short (*)[_Generic(x, int (*)[3]: 1)]);
+void fix_uns (int i,
+	      char (*a)[3][*],
+	      int (*x)[_Countof (*a)],
+	      short (*)[_Generic(x, int (*)[3]: 1)]);
+
+void var_fix (int i,
+	      char (*a)[i][5], /* dg-warn "variable" */
+	      int (*x)[_Countof (*a)]); /* dg-warn "variable" */
+void var_var (int i,
+	      char (*a)[i][i], /* dg-warn "variable" */
+	      int (*x)[_Countof (*a)]); /* dg-warn "variable" */
+void var_uns (int i,
+	      char (*a)[i][*], /* dg-warn "variable" */
+	      int (*x)[_Countof (*a)]); /* dg-warn "variable" */
+
+void uns_fix (int i,
+	      char (*a)[*][5],
+	      int (*x)[_Countof (*a)]);
+void uns_var (int i,
+	      char (*a)[*][i], /* dg-warn "variable" */
+	      int (*x)[_Countof (*a)]);
+void uns_uns (int i,
+	      char (*a)[*][*],
+	      int (*x)[_Countof (*a)]);
diff --git a/gcc/testsuite/gcc.dg/countof-vmt.c b/gcc/testsuite/gcc.dg/countof-vmt.c
new file mode 100644
index 00000000000..f84d5aa618d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/countof-vmt.c
@@ -0,0 +1,21 @@
+/* { dg-do run } */
+/* { dg-options "-std=c2y" } */
+
+#undef NDEBUG
+#include <assert.h>
+
+void
+inner_vla_noeval (void)
+{
+  int i;
+
+  i = 3;
+  static_assert (_Countof (struct {int x[i++];}[3]) == 3);
+  assert (i == 3);
+}
+
+int
+main (void)
+{
+  inner_vla_noeval ();
+}
diff --git a/gcc/testsuite/gcc.dg/countof-zero-compile.c b/gcc/testsuite/gcc.dg/countof-zero-compile.c
new file mode 100644
index 00000000000..3dc60ce293b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/countof-zero-compile.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-std=c2y" } */
+
+static int z[0];
+static int y[_Countof (z)];
+
+_Static_assert(_Countof (y) == 0);
+
+void
+completed (void)
+{
+  int z[] = {};
+
+  static_assert (_Countof (z) == 0);
+}
+
+void zro_fix (int i,
+	      char (*a)[0][5],
+	      int (*x)[_Countof (*a)],
+	      short (*)[_Generic(x, int (*)[0]: 1)]);
+void zro_var (int i,
+	      char (*a)[0][i], /* dg-warn "variable" */
+	      int (*x)[_Countof (*a)],
+	      short (*)[_Generic(x, int (*)[0]: 1)]);
+void zro_uns (int i,
+	      char (*a)[0][*],
+	      int (*x)[_Countof (*a)],
+	      short (*)[_Generic(x, int (*)[0]: 1)]);
+
+void
+const_expr(void)
+{
+  int n = 7;
+
+  _Static_assert (_Countof (int [0][3]) == 0);
+  _Static_assert (_Countof (int [0]) == 0);
+  _Static_assert (_Countof (int [0][n]) == 0);
+}
diff --git a/gcc/testsuite/gcc.dg/countof-zero.c b/gcc/testsuite/gcc.dg/countof-zero.c
new file mode 100644
index 00000000000..07dfc2bfbf2
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/countof-zero.c
@@ -0,0 +1,32 @@
+/* { dg-do run } */
+/* { dg-options "-std=c2y" } */
+
+#undef NDEBUG
+#include <assert.h>
+
+void
+vla (void)
+{
+  unsigned n;
+
+  n = 0;
+  int z[n];
+  assert (_Countof (z) == 0);
+}
+
+void
+matrix_vla (void)
+{
+  int i;
+
+  i = 0;
+  assert (_Countof (int [i++][4]) == 0);
+  assert (i == 0 + 1);
+}
+
+int
+main (void)
+{
+  vla ();
+  matrix_vla ();
+}
diff --git a/gcc/testsuite/gcc.dg/countof.c b/gcc/testsuite/gcc.dg/countof.c
new file mode 100644
index 00000000000..15ed7719100
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/countof.c
@@ -0,0 +1,121 @@
+/* { dg-do run } */
+/* { dg-options "-std=c2y -pedantic-errors" } */
+
+#undef NDEBUG
+#include <assert.h>
+
+void
+array (void)
+{
+  short a[7];
+
+  static_assert (_Countof (a) == 7);
+  static_assert (_Countof (unsigned [99]) == 99);
+}
+
+void
+completed (void)
+{
+  int a[] = {1, 2, 3};
+
+  static_assert (_Countof (a) == 3);
+}
+
+void
+vla (void)
+{
+  unsigned n;
+
+  n = 99;
+  assert (_Countof (short [n - 10]) == 99 - 10);
+
+  int v[n / 2];
+  assert (_Countof (v) == 99 / 2);
+}
+
+void
+member (void)
+{
+  struct {
+    int a[8];
+  } s;
+
+  static_assert (_Countof (s.a) == 8);
+}
+
+void
+vla_eval (void)
+{
+  int i;
+
+  i = 7;
+  assert (_Countof (struct {int x;}[i++]) == 7);
+  assert (i == 7 + 1);
+
+  int v[i];
+  int (*p)[i];
+  p = &v;
+  assert (_Countof (*p++) == i);
+  assert (p - 1 == &v);
+}
+
+void
+array_noeval (void)
+{
+  long a[5];
+  long (*p)[_Countof (a)];
+
+  p = &a;
+  static_assert (_Countof (*p++) == 5);
+  assert (p == &a);
+}
+
+void
+matrix_fixed (void)
+{
+  int i;
+
+  static_assert (_Countof (int [7][4]) == 7);
+  i = 3;
+  static_assert (_Countof (int [7][i]) == 7);
+}
+
+void
+matrix_vla (void)
+{
+  int i, j;
+
+  i = 7;
+  assert (_Countof (int [i++][4]) == 7);
+  assert (i == 7 + 1);
+
+  i = 9;
+  j = 3;
+  assert (_Countof (int [i++][j]) == 9);
+  assert (i == 9 + 1);
+}
+
+void
+no_parens(void)
+{
+  int n = 3;
+  int a[7];
+  int v[n];
+
+  static_assert (_Countof a == 7); 
+  assert (_Countof v == 3); 
+}
+
+int
+main (void)
+{
+  array ();
+  completed ();
+  vla ();
+  member ();
+  vla_eval ();
+  array_noeval ();
+  matrix_fixed ();
+  matrix_vla ();
+  no_parens ();
+}
-- 
2.49.0


^ permalink raw reply	[flat|nested] 318+ messages in thread

* [PATCH v22 2/3] c: Add <stdcountof.h>
  2025-05-15 22:37   ` [PATCH v22 0/3] c: Add _Countof and <stdcountof.h> Alejandro Colomar
  2025-05-15 22:37     ` [PATCH v22 1/3] c: Add _Countof operator Alejandro Colomar
@ 2025-05-15 22:37     ` Alejandro Colomar
  2025-05-15 22:37     ` [PATCH v22 3/3] c: Add -Wpedantic diagnostic for _Countof Alejandro Colomar
                       ` (2 subsequent siblings)
  4 siblings, 0 replies; 318+ messages in thread
From: Alejandro Colomar @ 2025-05-15 22:37 UTC (permalink / raw)
  To: gcc-patches
  Cc: Alejandro Colomar, Martin Uecker, JeanHeyd Meneide, Joseph Myers,
	Jakub Jelinek

gcc/ChangeLog:

	* Makefile.in (USER_H): Add <stdcountof.h>.
	* ginclude/stdcountof.h: Add countof macro.

gcc/testsuite/ChangeLog:

	* gcc.dg/countof-stdcountof.c: Add tests for <stdcountof.h>.

Signed-off-by: Alejandro Colomar <alx@kernel.org>
---
 gcc/Makefile.in                           |  1 +
 gcc/ginclude/stdcountof.h                 | 31 +++++++++++++++++++++++
 gcc/testsuite/gcc.dg/countof-stdcountof.c | 25 ++++++++++++++++++
 3 files changed, 57 insertions(+)
 create mode 100644 gcc/ginclude/stdcountof.h
 create mode 100644 gcc/testsuite/gcc.dg/countof-stdcountof.c

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 72d132207c0..fc8a7e532b9 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -481,6 +481,7 @@ USER_H = $(srcdir)/ginclude/float.h \
 	 $(srcdir)/ginclude/stdalign.h \
 	 $(srcdir)/ginclude/stdatomic.h \
 	 $(srcdir)/ginclude/stdckdint.h \
+	 $(srcdir)/ginclude/stdcountof.h \
 	 $(EXTRA_HEADERS)
 
 USER_H_INC_NEXT_PRE = @user_headers_inc_next_pre@
diff --git a/gcc/ginclude/stdcountof.h b/gcc/ginclude/stdcountof.h
new file mode 100644
index 00000000000..1d914f40e5d
--- /dev/null
+++ b/gcc/ginclude/stdcountof.h
@@ -0,0 +1,31 @@
+/* Copyright (C) 2025 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/>.  */
+
+/* ISO C2Y: 7.21 Array count <stdcountof.h>.  */
+
+#ifndef _STDCOUNTOF_H
+#define _STDCOUNTOF_H
+
+#define countof  _Countof
+
+#endif	/* stdcountof.h */
diff --git a/gcc/testsuite/gcc.dg/countof-stdcountof.c b/gcc/testsuite/gcc.dg/countof-stdcountof.c
new file mode 100644
index 00000000000..a7fe4079c69
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/countof-stdcountof.c
@@ -0,0 +1,25 @@
+/* { dg-do run } */
+/* { dg-options "-std=c2y -pedantic-errors" } */
+
+#include <stdcountof.h>
+
+#undef NDEBUG
+#include <assert.h>
+
+extern int strcmp (const char *, const char *);
+
+#ifndef countof
+#error "countof not defined"
+#endif
+
+int a[3];
+int b[countof a];
+
+#define str(x) #x
+#define xstr(x) str(x)
+
+int
+main (void)
+{
+  assert (strcmp (xstr(countof), "_Countof") == 0);
+}
-- 
2.49.0


^ permalink raw reply	[flat|nested] 318+ messages in thread

* [PATCH v22 3/3] c: Add -Wpedantic diagnostic for _Countof
  2025-05-15 22:37   ` [PATCH v22 0/3] c: Add _Countof and <stdcountof.h> Alejandro Colomar
  2025-05-15 22:37     ` [PATCH v22 1/3] c: Add _Countof operator Alejandro Colomar
  2025-05-15 22:37     ` [PATCH v22 2/3] c: Add <stdcountof.h> Alejandro Colomar
@ 2025-05-15 22:37     ` Alejandro Colomar
  2025-05-15 22:44     ` [PATCH v22 0/3] c: Add _Countof and <stdcountof.h> Alejandro Colomar
  2025-05-16 12:25     ` Joseph Myers
  4 siblings, 0 replies; 318+ messages in thread
From: Alejandro Colomar @ 2025-05-15 22:37 UTC (permalink / raw)
  To: gcc-patches
  Cc: Alejandro Colomar, Martin Uecker, JeanHeyd Meneide, Joseph Myers,
	Jakub Jelinek

It has been standardized in C2y.

gcc/c/ChangeLog:

	* c-parser.cc (c_parser_sizeof_or_countof_expression):
	Add -Wpedantic diagnostic for _Countof in <= C23 mode.

gcc/testsuite/ChangeLog:

	* gcc.dg/countof-compat.c
	* gcc.dg/countof-no-compat.c
	* gcc.dg/countof-pedantic.c
	* gcc.dg/countof-pedantic-errors.c:
	Test pedantic diagnostics for _Countof.

Signed-off-by: Alejandro Colomar <alx@kernel.org>
---
 gcc/c/c-parser.cc                              | 4 ++++
 gcc/testsuite/gcc.dg/countof-compat.c          | 8 ++++++++
 gcc/testsuite/gcc.dg/countof-no-compat.c       | 5 +++++
 gcc/testsuite/gcc.dg/countof-pedantic-errors.c | 8 ++++++++
 gcc/testsuite/gcc.dg/countof-pedantic.c        | 8 ++++++++
 5 files changed, 33 insertions(+)
 create mode 100644 gcc/testsuite/gcc.dg/countof-compat.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-no-compat.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-pedantic-errors.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-pedantic.c

diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
index 87700339394..d2193ad2f34 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -10637,6 +10637,10 @@ c_parser_sizeof_or_countof_expression (c_parser *parser, enum rid rid)
 
   start = c_parser_peek_token (parser)->location;
 
+  if (rid == RID_COUNTOF)
+    pedwarn_c23 (start, OPT_Wpedantic,
+		 "ISO C does not support %qs before C23", op_name);
+
   c_parser_consume_token (parser);
   c_inhibit_evaluation_warnings++;
   if (rid == RID_COUNTOF)
diff --git a/gcc/testsuite/gcc.dg/countof-compat.c b/gcc/testsuite/gcc.dg/countof-compat.c
new file mode 100644
index 00000000000..ab5b4ae6219
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/countof-compat.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-std=c2y -pedantic-errors -Wc23-c2y-compat" } */
+
+#include <stdcountof.h>
+
+int a[1];
+int b[countof(a)];
+int c[_Countof(a)];  /* { dg-warning "ISO C does not support" } */
diff --git a/gcc/testsuite/gcc.dg/countof-no-compat.c b/gcc/testsuite/gcc.dg/countof-no-compat.c
new file mode 100644
index 00000000000..4a244cf222f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/countof-no-compat.c
@@ -0,0 +1,5 @@
+/* { dg-do compile } */
+/* { dg-options "-std=c23 -pedantic-errors -Wno-c23-c2y-compat" } */
+
+int a[1];
+int b[_Countof(a)];
diff --git a/gcc/testsuite/gcc.dg/countof-pedantic-errors.c b/gcc/testsuite/gcc.dg/countof-pedantic-errors.c
new file mode 100644
index 00000000000..5d5bedbe1f7
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/countof-pedantic-errors.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-std=c23 -pedantic-errors" } */
+
+#include <stdcountof.h>
+
+int a[1];
+int b[countof(a)];
+int c[_Countof(a)];  /* { dg-error "ISO C does not support" } */
diff --git a/gcc/testsuite/gcc.dg/countof-pedantic.c b/gcc/testsuite/gcc.dg/countof-pedantic.c
new file mode 100644
index 00000000000..408dc6f9366
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/countof-pedantic.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-std=c23 -pedantic" } */
+
+#include <stdcountof.h>
+
+int a[1];
+int b[countof(a)];
+int c[_Countof(a)];  /* { dg-warning "ISO C does not support" } */
-- 
2.49.0


^ permalink raw reply	[flat|nested] 318+ messages in thread

* Re: [PATCH v22 0/3] c: Add _Countof and <stdcountof.h>
  2025-05-15 22:37   ` [PATCH v22 0/3] c: Add _Countof and <stdcountof.h> Alejandro Colomar
                       ` (2 preceding siblings ...)
  2025-05-15 22:37     ` [PATCH v22 3/3] c: Add -Wpedantic diagnostic for _Countof Alejandro Colomar
@ 2025-05-15 22:44     ` Alejandro Colomar
  2025-05-16 12:25     ` Joseph Myers
  4 siblings, 0 replies; 318+ messages in thread
From: Alejandro Colomar @ 2025-05-15 22:44 UTC (permalink / raw)
  To: gcc-patches; +Cc: Martin Uecker, JeanHeyd Meneide, Joseph Myers, Jakub Jelinek

[-- Attachment #1: Type: text/plain, Size: 18562 bytes --]

Here's the test run.  No regressions.

BTW, there are some differences between runs.  I _think_ this is due to
running them in separate days, and having run 'make install' in between,
which seems to have made some tests that would normally fail now succeed
but that's unrelated to the feature, and in other runs that I've run
immediately, those differences don't appear.  They started appearing
when I ran 'make install', which I suspect had some effect on them,
even if it shouldn't (because 'make check' is supposed to not be
affected by the system, IMO).  Anyway, here it goes.



alx@debian:/srv/alx/src/gnu/gcc/len$ cat /home/alx/tmp/rt 
alx@debian:/srv/alx/src/gnu/gcc/len$ git log --oneline gnu/master^..len22
c44ef4a2c75 (HEAD -> len, tag: len22, alx/len) c: Add -Wpedantic diagno>
418f81175e7 c: Add <stdcountof.h>
1c983c3baa7 c: Add _Countof operator
90c6ccebd76 (gnu/trunk, gnu/master, gnu/HEAD) RISC-V: Drop riscv_ext_fl>
alx@debian:/srv/alx/src/gnu/gcc/len$ git reset gnu/master --h
HEAD is now at 90c6ccebd76 RISC-V: Drop riscv_ext_flag_table in favor of riscv_ext_info_t data
alx@debian:/srv/alx/src/gnu/gcc/len$ mkdir ../len22
alx@debian:/srv/alx/src/gnu/gcc/len$ cd ../len22
alx@debian:/srv/alx/src/gnu/gcc/len22$ /bin/time ../len/configure --disable-multilib --prefix=/opt/local/gnu/gcc/countof22 |& ts -s | tail -n 3; echo $?
00:00:01 config.status: creating Makefile
00:00:01 1.59user 0.57system 0:01.78elapsed 122%CPU (0avgtext+0avgdata 26812maxresident)k
00:00:01 0inputs+8056outputs (0major+280314minor)pagefaults 0swaps
0
alx@debian:/srv/alx/src/gnu/gcc/len22$ /bin/time make -j12 bootstrap |& ts -s | tail -n 3; echo $?
00:32:17 make[1]: Leaving directory '/srv/alx/src/gnu/gcc/len22'
00:32:17 16769.95user 436.07system 32:16.93elapsed 888%CPU (0avgtext+0avgdata 1491560maxresident)k
00:32:17 0inputs+31383912outputs (856major+112120780minor)pagefaults 0swaps
0
alx@debian:/srv/alx/src/gnu/gcc/len22$ /bin/time make check |& ts -s | tail -n 3; echo $?
07:30:54 make[1]: Leaving directory '/srv/alx/src/gnu/gcc/len22'
07:30:54 23876.26user 3393.05system 7:30:54elapsed 100%CPU (0avgtext+0avgdata 1041556maxresident)k
07:30:54 700720inputs+21152256outputs (2963major+1060028942minor)pagefaults 0swaps
0
alx@debian:/srv/alx/src/gnu/gcc/len22$ cd ../len
alx@debian:/srv/alx/src/gnu/gcc/len$ git merge --ff-only len22
Updating 90c6ccebd76..c44ef4a2c75
Fast-forward
 gcc/Makefile.in                               |   1 +
 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                               |  22 +++-
 gcc/c/c-parser.cc                             |  63 +++++++--
 gcc/c/c-tree.h                                |   4 +
 gcc/c/c-typeck.cc                             | 115 +++++++++++++++-
 gcc/doc/extend.texi                           |  30 +++++
 gcc/ginclude/stdcountof.h                     |  31 +++++
 gcc/testsuite/gcc.dg/countof-compat.c         |   8 ++
 gcc/testsuite/gcc.dg/countof-compile.c        | 124 ++++++++++++++++++
 gcc/testsuite/gcc.dg/countof-no-compat.c      |   5 +
 .../gcc.dg/countof-pedantic-errors.c          |   8 ++
 gcc/testsuite/gcc.dg/countof-pedantic.c       |   8 ++
 gcc/testsuite/gcc.dg/countof-stdcountof.c     |  25 ++++
 gcc/testsuite/gcc.dg/countof-vla.c            |  35 +++++
 gcc/testsuite/gcc.dg/countof-vmt.c            |  21 +++
 gcc/testsuite/gcc.dg/countof-zero-compile.c   |  38 ++++++
 gcc/testsuite/gcc.dg/countof-zero.c           |  32 +++++
 gcc/testsuite/gcc.dg/countof.c                | 121 +++++++++++++++++
 21 files changed, 698 insertions(+), 24 deletions(-)
 create mode 100644 gcc/ginclude/stdcountof.h
 create mode 100644 gcc/testsuite/gcc.dg/countof-compat.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-compile.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-no-compat.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-pedantic-errors.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-pedantic.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-stdcountof.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-vla.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-vmt.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-zero-compile.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-zero.c
 create mode 100644 gcc/testsuite/gcc.dg/countof.c
alx@debian:/srv/alx/src/gnu/gcc/len$ cd ..
alx@debian:/srv/alx/src/gnu/gcc$ mv len22/ len22_b4
alx@debian:/srv/alx/src/gnu/gcc$ mkdir len22
alx@debian:/srv/alx/src/gnu/gcc$ cd len22
alx@debian:/srv/alx/src/gnu/gcc/len22$ /bin/time ../len/configure --disable-multilib --prefix=/opt/local/gnu/gcc/countof22 |& ts -s | tail -n 3; echo $?
00:00:01 config.status: creating Makefile
00:00:01 1.51user 0.56system 0:01.71elapsed 120%CPU (0avgtext+0avgdata 26792maxresident)k
00:00:01 0inputs+8056outputs (0major+278567minor)pagefaults 0swaps
0
alx@debian:/srv/alx/src/gnu/gcc/len22$ /bin/time make -j12 bootstrap |& ts -s | tail -n 3; echo $?
00:31:34 make[1]: Leaving directory '/srv/alx/src/gnu/gcc/len22'
00:31:34 17016.93user 422.52system 31:34.56elapsed 920%CPU (0avgtext+0avgdata 1491208maxresident)k
00:31:34 0inputs+31416288outputs (567major+112073730minor)pagefaults 0swaps
0
alx@debian:/srv/alx/src/gnu/gcc/len22$ /bin/time make check |& ts -s | tail -n 3; echo $?
06:45:55 make[1]: Leaving directory '/srv/alx/src/gnu/gcc/len22'
06:45:55 21372.00user 3206.73system 6:45:54elapsed 100%CPU (0avgtext+0avgdata 1041984maxresident)k
06:45:55 2373464inputs+21171544outputs (8250major+1061062398minor)pagefaults 0swaps
0
alx@debian:~/src/gnu/gcc/len22$ find -type f | grep '\.sum$' | while read f; do diff -u ../len22_b4/$f <(cat $f | sed s,/home/,/srv/,); done
--- ../len22_b4/./gcc/testsuite/objc/objc.sum	2025-05-13 14:22:51.748236998 +0200
+++ /dev/fd/63	2025-05-16 00:28:55.103842979 +0200
@@ -1,4 +1,4 @@
-Test run by alx on Tue May 13 14:22:02 2025
+Test run by alx on Thu May 15 20:13:12 2025
 Native configuration is x86_64-pc-linux-gnu
 
 		=== objc tests ===
--- ../len22_b4/./gcc/testsuite/g++/g++.sum	2025-05-13 13:50:08.360564526 +0200
+++ /dev/fd/63	2025-05-16 00:28:55.107842984 +0200
@@ -1,4 +1,4 @@
-Test run by alx on Tue May 13 13:01:57 2025
+Test run by alx on Thu May 15 18:51:11 2025
 Native configuration is x86_64-pc-linux-gnu
 
 		=== g++ tests ===
@@ -145913,9 +145913,27 @@
 PASS: g++.dg/warn/uninit-pr82800.C  -std=gnu++17 (test for excess errors)
 PASS: g++.dg/warn/uninit-pr82800.C  -std=gnu++26  (test for bogus messages, line 14)
 PASS: g++.dg/warn/uninit-pr82800.C  -std=gnu++26 (test for excess errors)
-UNSUPPORTED: g++.dg/warn/uninit-pr93100.C  -std=gnu++17
-UNSUPPORTED: g++.dg/warn/uninit-pr93100.C  -std=gnu++98
-UNSUPPORTED: g++.dg/warn/uninit-pr93100.C  -std=gnu++26
+PASS: g++.dg/warn/uninit-pr93100.C  -std=gnu++17  (test for warnings, line 13)
+PASS: g++.dg/warn/uninit-pr93100.C  -std=gnu++17  (test for warnings, line 20)
+PASS: g++.dg/warn/uninit-pr93100.C  -std=gnu++17  (test for warnings, line 31)
+PASS: g++.dg/warn/uninit-pr93100.C  -std=gnu++17  (test for warnings, line 38)
+PASS: g++.dg/warn/uninit-pr93100.C  -std=gnu++17  (test for warnings, line 49)
+PASS: g++.dg/warn/uninit-pr93100.C  -std=gnu++17  (test for warnings, line 56)
+PASS: g++.dg/warn/uninit-pr93100.C  -std=gnu++17 (test for excess errors)
+PASS: g++.dg/warn/uninit-pr93100.C  -std=gnu++98  (test for warnings, line 13)
+PASS: g++.dg/warn/uninit-pr93100.C  -std=gnu++98  (test for warnings, line 20)
+PASS: g++.dg/warn/uninit-pr93100.C  -std=gnu++98  (test for warnings, line 31)
+PASS: g++.dg/warn/uninit-pr93100.C  -std=gnu++98  (test for warnings, line 38)
+PASS: g++.dg/warn/uninit-pr93100.C  -std=gnu++98  (test for warnings, line 49)
+PASS: g++.dg/warn/uninit-pr93100.C  -std=gnu++98  (test for warnings, line 56)
+PASS: g++.dg/warn/uninit-pr93100.C  -std=gnu++98 (test for excess errors)
+PASS: g++.dg/warn/uninit-pr93100.C  -std=gnu++26  (test for warnings, line 13)
+PASS: g++.dg/warn/uninit-pr93100.C  -std=gnu++26  (test for warnings, line 20)
+PASS: g++.dg/warn/uninit-pr93100.C  -std=gnu++26  (test for warnings, line 31)
+PASS: g++.dg/warn/uninit-pr93100.C  -std=gnu++26  (test for warnings, line 38)
+PASS: g++.dg/warn/uninit-pr93100.C  -std=gnu++26  (test for warnings, line 49)
+PASS: g++.dg/warn/uninit-pr93100.C  -std=gnu++26  (test for warnings, line 56)
+PASS: g++.dg/warn/uninit-pr93100.C  -std=gnu++26 (test for excess errors)
 PASS: g++.dg/warn/unit-1.C  -std=gnu++17  (test for warnings, line 8)
 PASS: g++.dg/warn/unit-1.C  -std=gnu++17 (test for excess errors)
 PASS: g++.dg/warn/unit-1.C  -std=gnu++98  (test for warnings, line 8)
@@ -253049,10 +253067,10 @@
 
 		=== g++ Summary ===
 
-# of expected passes		248638
+# of expected passes		248659
 # of unexpected failures	10
 # of unexpected successes	3
 # of expected failures		2294
-# of unsupported tests		2033
+# of unsupported tests		2030
 /srv/alx/src/gnu/gcc/len22/gcc/xg++  version 16.0.0 20250513 (experimental) (GCC) 
 
--- ../len22_b4/./gcc/testsuite/gcc/gcc.sum	2025-05-13 13:01:57.374979956 +0200
+++ /dev/fd/63	2025-05-16 00:28:55.195843098 +0200
@@ -1,4 +1,4 @@
-Test run by alx on Tue May 13 11:20:06 2025
+Test run by alx on Thu May 15 17:21:01 2025
 Native configuration is x86_64-pc-linux-gnu
 
 		=== gcc tests ===
@@ -81360,6 +81360,43 @@
 PASS: gcc.dg/conv-2.c (test for excess errors)
 PASS: gcc.dg/conv-3.c (test for excess errors)
 PASS: gcc.dg/conv-3.c execution test
+PASS: gcc.dg/countof-compat.c  (test for warnings, line 8)
+PASS: gcc.dg/countof-compat.c (test for excess errors)
+PASS: gcc.dg/countof-compile.c  (test for errors, line 23)
+PASS: gcc.dg/countof-compile.c  (test for errors, line 27)
+PASS: gcc.dg/countof-compile.c  (test for errors, line 38)
+PASS: gcc.dg/countof-compile.c  (test for errors, line 46)
+PASS: gcc.dg/countof-compile.c  (test for errors, line 64)
+PASS: gcc.dg/countof-compile.c  (test for errors, line 67)
+PASS: gcc.dg/countof-compile.c  (test for errors, line 70)
+PASS: gcc.dg/countof-compile.c  (test for errors, line 82)
+PASS: gcc.dg/countof-compile.c  (test for errors, line 83)
+PASS: gcc.dg/countof-compile.c  (test for errors, line 84)
+PASS: gcc.dg/countof-compile.c  (test for errors, line 85)
+PASS: gcc.dg/countof-compile.c  (test for errors, line 86)
+PASS: gcc.dg/countof-compile.c  (test for errors, line 87)
+PASS: gcc.dg/countof-compile.c  (test for errors, line 88)
+PASS: gcc.dg/countof-compile.c  (test for errors, line 89)
+PASS: gcc.dg/countof-compile.c  (test for errors, line 90)
+PASS: gcc.dg/countof-compile.c  (test for errors, line 94)
+PASS: gcc.dg/countof-compile.c  (test for errors, line 114)
+PASS: gcc.dg/countof-compile.c  (test for errors, line 123)
+PASS: gcc.dg/countof-compile.c (test for excess errors)
+PASS: gcc.dg/countof-no-compat.c (test for excess errors)
+PASS: gcc.dg/countof-pedantic-errors.c  (test for errors, line 8)
+PASS: gcc.dg/countof-pedantic-errors.c (test for excess errors)
+PASS: gcc.dg/countof-pedantic.c  (test for warnings, line 8)
+PASS: gcc.dg/countof-pedantic.c (test for excess errors)
+PASS: gcc.dg/countof-stdcountof.c (test for excess errors)
+PASS: gcc.dg/countof-stdcountof.c execution test
+PASS: gcc.dg/countof-vla.c (test for excess errors)
+PASS: gcc.dg/countof-vmt.c (test for excess errors)
+PASS: gcc.dg/countof-vmt.c execution test
+PASS: gcc.dg/countof-zero-compile.c (test for excess errors)
+PASS: gcc.dg/countof-zero.c (test for excess errors)
+PASS: gcc.dg/countof-zero.c execution test
+PASS: gcc.dg/countof.c (test for excess errors)
+PASS: gcc.dg/countof.c execution test
 PASS: gcc.dg/cr-decimal-dig-1.c (test for excess errors)
 PASS: gcc.dg/cr-decimal-dig-2.c (test for excess errors)
 PASS: gcc.dg/cr-decimal-dig-3.c (test for excess errors)
@@ -91957,7 +91994,7 @@
 PASS: gcc.dg/pr91195.c  (test for bogus messages, line 14)
 PASS: gcc.dg/pr91195.c (test for excess errors)
 PASS: gcc.dg/pr91269.c (test for excess errors)
-UNSUPPORTED: gcc.dg/pr91441.c
+PASS: gcc.dg/pr91441.c (test for excess errors)
 PASS: gcc.dg/pr91570.c (test for excess errors)
 PASS: gcc.dg/pr91720.c (test for excess errors)
 PASS: gcc.dg/pr91720.c execution test
@@ -92166,10 +92203,10 @@
 PASS: gcc.dg/pr96239.c scan-tree-dump-times optimized " r>> 8;" 1
 PASS: gcc.dg/pr96239.c scan-tree-dump-times optimized " = __builtin_bswap64 " 1
 PASS: gcc.dg/pr96239.c scan-tree-dump-not optimized " >> (8|16|24|32|40|48|56);"
-UNSUPPORTED: gcc.dg/pr96260.c
+PASS: gcc.dg/pr96260.c (test for excess errors)
 PASS: gcc.dg/pr96298.c (test for excess errors)
 PASS: gcc.dg/pr96298.c execution test
-UNSUPPORTED: gcc.dg/pr96307.c
+PASS: gcc.dg/pr96307.c (test for excess errors)
 PASS: gcc.dg/pr96335.c (test for excess errors)
 PASS: gcc.dg/pr96370.c (test for excess errors)
 PASS: gcc.dg/pr96377-1.c  at line 2 (test for warnings, line )
@@ -96504,7 +96541,13 @@
 PASS: gcc.dg/uninit-pr90394-1-gimple.c  (test for warnings, line 9)
 PASS: gcc.dg/uninit-pr90394-1-gimple.c (test for excess errors)
 PASS: gcc.dg/uninit-pr90394.c (test for excess errors)
-UNSUPPORTED: gcc.dg/uninit-pr93100.c
+PASS: gcc.dg/uninit-pr93100.c  (test for warnings, line 16)
+PASS: gcc.dg/uninit-pr93100.c  (test for warnings, line 26)
+PASS: gcc.dg/uninit-pr93100.c  (test for warnings, line 38)
+PASS: gcc.dg/uninit-pr93100.c  (test for warnings, line 48)
+PASS: gcc.dg/uninit-pr93100.c  (test for warnings, line 61)
+PASS: gcc.dg/uninit-pr93100.c  (test for warnings, line 71)
+PASS: gcc.dg/uninit-pr93100.c (test for excess errors)
 PASS: gcc.dg/uninit-pr95136.c  (test for warnings, line 10)
 PASS: gcc.dg/uninit-pr95136.c  (test for warnings, line 12)
 PASS: gcc.dg/uninit-pr95136.c  (test for warnings, line 17)
@@ -98880,11 +98923,11 @@
 PASS: c-c++-common/Wbidi-chars-ranges.c  -Wc++-compat   at line 23 (test for warnings, line 22)
 PASS: c-c++-common/Wbidi-chars-ranges.c  -Wc++-compat   at line 39 (test for warnings, line 38)
 PASS: c-c++-common/Wbidi-chars-ranges.c  -Wc++-compat   at line 48 (test for warnings, line 47)
-FAIL: c-c++-common/Wbidi-chars-ranges.c  -Wc++-compat   expected multiline pattern lines 13-17
+PASS: c-c++-common/Wbidi-chars-ranges.c  -Wc++-compat   expected multiline pattern lines 13-17
 PASS: c-c++-common/Wbidi-chars-ranges.c  -Wc++-compat   expected multiline pattern lines 26-31
 PASS: c-c++-common/Wbidi-chars-ranges.c  -Wc++-compat   expected multiline pattern lines 42-43
 PASS: c-c++-common/Wbidi-chars-ranges.c  -Wc++-compat   expected multiline pattern lines 51-52
-FAIL: c-c++-common/Wbidi-chars-ranges.c  -Wc++-compat  (test for excess errors)
+PASS: c-c++-common/Wbidi-chars-ranges.c  -Wc++-compat  (test for excess errors)
 PASS: c-c++-common/Wbool-compare-1.c  -Wc++-compat   (test for warnings, line 19)
 PASS: c-c++-common/Wbool-compare-1.c  -Wc++-compat   (test for warnings, line 20)
 PASS: c-c++-common/Wbool-compare-1.c  -Wc++-compat   (test for warnings, line 21)
@@ -216929,10 +216972,10 @@
 
 		=== gcc Summary ===
 
-# of expected passes		211519
-# of unexpected failures	9
+# of expected passes		211568
+# of unexpected failures	7
 # of unexpected successes	2
 # of expected failures		1479
-# of unsupported tests		3731
+# of unsupported tests		3727
 /srv/alx/src/gnu/gcc/len22/gcc/xgcc  version 16.0.0 20250513 (experimental) (GCC) 
 
--- ../len22_b4/./gcc/testsuite/gfortran/gfortran.sum	2025-05-13 14:22:02.185557817 +0200
+++ /dev/fd/63	2025-05-16 00:28:55.267843192 +0200
@@ -1,4 +1,4 @@
-Test run by alx on Tue May 13 13:50:08 2025
+Test run by alx on Thu May 15 19:40:50 2025
 Native configuration is x86_64-pc-linux-gnu
 
 		=== gfortran tests ===
--- ../len22_b4/./x86_64-pc-linux-gnu/libstdc++-v3/testsuite/libstdc++.sum	2025-05-13 18:36:46.021382946 +0200
+++ /dev/fd/63	2025-05-16 00:28:55.283843213 +0200
@@ -1,4 +1,4 @@
-Test run by alx on Tue May 13 14:23:14 2025
+Test run by alx on Thu May 15 20:14:26 2025
 Native configuration is x86_64-pc-linux-gnu
 
 		=== libstdc++ tests ===
@@ -14391,8 +14391,10 @@
 PASS: 29_atomics/atomic_float/1.cc  -std=gnu++26 execution test
 PASS: 29_atomics/atomic_float/95282.cc  -std=gnu++20 (test for excess errors)
 PASS: 29_atomics/atomic_float/95282.cc  -std=gnu++26 (test for excess errors)
-UNSUPPORTED: 29_atomics/atomic_float/compare_exchange_padding.cc  -std=gnu++20
-UNSUPPORTED: 29_atomics/atomic_float/compare_exchange_padding.cc  -std=gnu++26
+PASS: 29_atomics/atomic_float/compare_exchange_padding.cc  -std=gnu++20 (test for excess errors)
+PASS: 29_atomics/atomic_float/compare_exchange_padding.cc  -std=gnu++20 execution test
+PASS: 29_atomics/atomic_float/compare_exchange_padding.cc  -std=gnu++26 (test for excess errors)
+PASS: 29_atomics/atomic_float/compare_exchange_padding.cc  -std=gnu++26 execution test
 PASS: 29_atomics/atomic_float/constinit.cc  -std=gnu++20 (test for excess errors)
 PASS: 29_atomics/atomic_float/constinit.cc  -std=gnu++26 (test for excess errors)
 PASS: 29_atomics/atomic_float/requirements.cc  -std=gnu++20 (test for excess errors)
@@ -19286,6 +19288,6 @@
 
 		=== libstdc++ Summary ===
 
-# of expected passes		18342
+# of expected passes		18346
 # of expected failures		131
-# of unsupported tests		799
+# of unsupported tests		797
--- ../len22_b4/./x86_64-pc-linux-gnu/libitm/testsuite/libitm.sum	2025-05-13 18:50:56.432974329 +0200
+++ /dev/fd/63	2025-05-16 00:28:55.291843222 +0200
@@ -1,4 +1,4 @@
-Test run by alx on Tue May 13 18:50:54 2025
+Test run by alx on Fri May 16 00:06:49 2025
 Native configuration is x86_64-pc-linux-gnu
 
 		=== libitm tests ===
--- ../len22_b4/./x86_64-pc-linux-gnu/libgomp/testsuite/libgomp.sum	2025-05-13 18:50:54.376984988 +0200
+++ /dev/fd/63	2025-05-16 00:28:55.295843228 +0200
@@ -1,4 +1,4 @@
-Test run by alx on Tue May 13 18:37:03 2025
+Test run by alx on Thu May 15 23:52:30 2025
 Native configuration is x86_64-pc-linux-gnu
 
 		=== libgomp tests ===
--- ../len22_b4/./x86_64-pc-linux-gnu/libatomic/testsuite/libatomic.sum	2025-05-13 18:50:57.936966534 +0200
+++ /dev/fd/63	2025-05-16 00:28:55.307843245 +0200
@@ -1,4 +1,4 @@
-Test run by alx on Tue May 13 18:50:56 2025
+Test run by alx on Fri May 16 00:06:51 2025
 Native configuration is x86_64-pc-linux-gnu
 
 		=== libatomic tests ===

-- 
<https://www.alejandro-colomar.es/>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 318+ messages in thread

* Re: [PATCH v22 0/3] c: Add _Countof and <stdcountof.h>
  2025-05-15 22:37   ` [PATCH v22 0/3] c: Add _Countof and <stdcountof.h> Alejandro Colomar
                       ` (3 preceding siblings ...)
  2025-05-15 22:44     ` [PATCH v22 0/3] c: Add _Countof and <stdcountof.h> Alejandro Colomar
@ 2025-05-16 12:25     ` Joseph Myers
  2025-05-16 16:56       ` Alejandro Colomar
  4 siblings, 1 reply; 318+ messages in thread
From: Joseph Myers @ 2025-05-16 12:25 UTC (permalink / raw)
  To: Alejandro Colomar
  Cc: gcc-patches, Martin Uecker, JeanHeyd Meneide, Jakub Jelinek

On Fri, 16 May 2025, Alejandro Colomar wrote:

> -  Add <assert.h> (and NDEBUG) to some test files that were missing it,
>    and also the forward declaration of strcmp(3).

Depending on libc headers like this in tests is discouraged.  The usual 
idiom is to use abort () on failure of a runtime check (rather than 
assert) and to declare abort in the test (or use __builtin_abort to avoid 
needing the declaration).

-- 
Joseph S. Myers
josmyers@redhat.com


^ permalink raw reply	[flat|nested] 318+ messages in thread

* Re: [PATCH v22 0/3] c: Add _Countof and <stdcountof.h>
  2025-05-16 12:25     ` Joseph Myers
@ 2025-05-16 16:56       ` Alejandro Colomar
  2025-05-16 17:01         ` Joseph Myers
  0 siblings, 1 reply; 318+ messages in thread
From: Alejandro Colomar @ 2025-05-16 16:56 UTC (permalink / raw)
  To: Joseph Myers; +Cc: gcc-patches, Martin Uecker, JeanHeyd Meneide, Jakub Jelinek

[-- Attachment #1: Type: text/plain, Size: 2635 bytes --]

Hi Joseph,

On Fri, May 16, 2025 at 12:25:39PM +0000, Joseph Myers wrote:
> On Fri, 16 May 2025, Alejandro Colomar wrote:
> 
> > -  Add <assert.h> (and NDEBUG) to some test files that were missing it,
> >    and also the forward declaration of strcmp(3).
> 
> Depending on libc headers like this in tests is discouraged.  The usual 
> idiom is to use abort () on failure of a runtime check (rather than 
> assert) and to declare abort in the test (or use __builtin_abort to avoid 
> needing the declaration).

Hmmm, I've been trying to find a compromise between readability and
simplicity, and I think I have something.  I've seen some tests that
define assert() themselves.  I like assert(3) because it's more
readable compared to a conditional plus abort(3).

So, how do you feel about the following change?

	diff --git i/gcc/testsuite/gcc.dg/countof-stdcountof.c w/gcc/testsuite/gcc.dg/countof-stdcountof.c
	index a7fe4079c69..2fb0c6306ef 100644
	--- i/gcc/testsuite/gcc.dg/countof-stdcountof.c
	+++ w/gcc/testsuite/gcc.dg/countof-stdcountof.c
	@@ -3,8 +3,7 @@
	 
	 #include <stdcountof.h>
	 
	-#undef NDEBUG
	-#include <assert.h>
	+#define assert(e)  ((e) ? (void) 0 : __builtin_abort ())
	 
	 extern int strcmp (const char *, const char *);
	 
	diff --git i/gcc/testsuite/gcc.dg/countof-vmt.c w/gcc/testsuite/gcc.dg/countof-vmt.c
	index f84d5aa618d..cf4bfd1aa74 100644
	--- i/gcc/testsuite/gcc.dg/countof-vmt.c
	+++ w/gcc/testsuite/gcc.dg/countof-vmt.c
	@@ -1,8 +1,7 @@
	 /* { dg-do run } */
	 /* { dg-options "-std=c2y" } */
	 
	-#undef NDEBUG
	-#include <assert.h>
	+#define assert(e)  ((e) ? (void) 0 : __builtin_abort ())
	 
	 void
	 inner_vla_noeval (void)
	diff --git i/gcc/testsuite/gcc.dg/countof-zero.c w/gcc/testsuite/gcc.dg/countof-zero.c
	index 07dfc2bfbf2..678a08148a5 100644
	--- i/gcc/testsuite/gcc.dg/countof-zero.c
	+++ w/gcc/testsuite/gcc.dg/countof-zero.c
	@@ -1,8 +1,7 @@
	 /* { dg-do run } */
	 /* { dg-options "-std=c2y" } */
	 
	-#undef NDEBUG
	-#include <assert.h>
	+#define assert(e)  ((e) ? (void) 0 : __builtin_abort ())
	 
	 void
	 vla (void)
	diff --git i/gcc/testsuite/gcc.dg/countof.c w/gcc/testsuite/gcc.dg/countof.c
	index 15ed7719100..534488501c6 100644
	--- i/gcc/testsuite/gcc.dg/countof.c
	+++ w/gcc/testsuite/gcc.dg/countof.c
	@@ -1,8 +1,7 @@
	 /* { dg-do run } */
	 /* { dg-options "-std=c2y -pedantic-errors" } */
	 
	-#undef NDEBUG
	-#include <assert.h>
	+#define assert(e)  ((e) ? (void) 0 : __builtin_abort ())
	 
	 void
	 array (void)


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] 318+ messages in thread

* Re: [PATCH v22 0/3] c: Add _Countof and <stdcountof.h>
  2025-05-16 16:56       ` Alejandro Colomar
@ 2025-05-16 17:01         ` Joseph Myers
  2025-05-16 17:13           ` Alejandro Colomar
  0 siblings, 1 reply; 318+ messages in thread
From: Joseph Myers @ 2025-05-16 17:01 UTC (permalink / raw)
  To: Alejandro Colomar
  Cc: gcc-patches, Martin Uecker, JeanHeyd Meneide, Jakub Jelinek

On Fri, 16 May 2025, Alejandro Colomar wrote:

> Hmmm, I've been trying to find a compromise between readability and
> simplicity, and I think I have something.  I've seen some tests that
> define assert() themselves.  I like assert(3) because it's more
> readable compared to a conditional plus abort(3).
> 
> So, how do you feel about the following change?
> 
> 	diff --git i/gcc/testsuite/gcc.dg/countof-stdcountof.c w/gcc/testsuite/gcc.dg/countof-stdcountof.c
> 	index a7fe4079c69..2fb0c6306ef 100644
> 	--- i/gcc/testsuite/gcc.dg/countof-stdcountof.c
> 	+++ w/gcc/testsuite/gcc.dg/countof-stdcountof.c
> 	@@ -3,8 +3,7 @@
> 	 
> 	 #include <stdcountof.h>
> 	 
> 	-#undef NDEBUG
> 	-#include <assert.h>
> 	+#define assert(e)  ((e) ? (void) 0 : __builtin_abort ())

Yes, I think that's a reasonable way for a test to do its assertions with 
assert syntax but without depending unnecessarily on libc headers.

-- 
Joseph S. Myers
josmyers@redhat.com


^ permalink raw reply	[flat|nested] 318+ messages in thread

* Re: [PATCH v22 0/3] c: Add _Countof and <stdcountof.h>
  2025-05-16 17:01         ` Joseph Myers
@ 2025-05-16 17:13           ` Alejandro Colomar
  2025-05-20 12:33             ` Alejandro Colomar
  0 siblings, 1 reply; 318+ messages in thread
From: Alejandro Colomar @ 2025-05-16 17:13 UTC (permalink / raw)
  To: Joseph Myers; +Cc: gcc-patches, Martin Uecker, JeanHeyd Meneide, Jakub Jelinek

[-- Attachment #1: Type: text/plain, Size: 1283 bytes --]

Hi Joseph,

On Fri, May 16, 2025 at 05:01:36PM +0000, Joseph Myers wrote:
> On Fri, 16 May 2025, Alejandro Colomar wrote:
> 
> > Hmmm, I've been trying to find a compromise between readability and
> > simplicity, and I think I have something.  I've seen some tests that
> > define assert() themselves.  I like assert(3) because it's more
> > readable compared to a conditional plus abort(3).
> > 
> > So, how do you feel about the following change?
> > 
> > 	diff --git i/gcc/testsuite/gcc.dg/countof-stdcountof.c w/gcc/testsuite/gcc.dg/countof-stdcountof.c
> > 	index a7fe4079c69..2fb0c6306ef 100644
> > 	--- i/gcc/testsuite/gcc.dg/countof-stdcountof.c
> > 	+++ w/gcc/testsuite/gcc.dg/countof-stdcountof.c
> > 	@@ -3,8 +3,7 @@
> > 	 
> > 	 #include <stdcountof.h>
> > 	 
> > 	-#undef NDEBUG
> > 	-#include <assert.h>
> > 	+#define assert(e)  ((e) ? (void) 0 : __builtin_abort ())
> 
> Yes, I think that's a reasonable way for a test to do its assertions with 
> assert syntax but without depending unnecessarily on libc headers.

If there are any other issues, I'll apply that change for v23.  If this
is the only one, would you mind amending yourself with that while
committing?  Thanks!


Cheers,
Alex

-- 
<https://www.alejandro-colomar.es/>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 318+ messages in thread

* Re: [PATCH v22 0/3] c: Add _Countof and <stdcountof.h>
  2025-05-16 17:13           ` Alejandro Colomar
@ 2025-05-20 12:33             ` Alejandro Colomar
  2025-05-20 14:43               ` Joseph Myers
  0 siblings, 1 reply; 318+ messages in thread
From: Alejandro Colomar @ 2025-05-20 12:33 UTC (permalink / raw)
  To: Joseph Myers; +Cc: gcc-patches, Martin Uecker, JeanHeyd Meneide, Jakub Jelinek

[-- Attachment #1: Type: text/plain, Size: 1947 bytes --]

Hi Joseph,

On Fri, May 16, 2025 at 07:13:15PM +0200, Alejandro Colomar wrote:
> On Fri, May 16, 2025 at 05:01:36PM +0000, Joseph Myers wrote:
> > On Fri, 16 May 2025, Alejandro Colomar wrote:
> > 
> > > Hmmm, I've been trying to find a compromise between readability and
> > > simplicity, and I think I have something.  I've seen some tests that
> > > define assert() themselves.  I like assert(3) because it's more
> > > readable compared to a conditional plus abort(3).
> > > 
> > > So, how do you feel about the following change?
> > > 
> > > 	diff --git i/gcc/testsuite/gcc.dg/countof-stdcountof.c w/gcc/testsuite/gcc.dg/countof-stdcountof.c
> > > 	index a7fe4079c69..2fb0c6306ef 100644
> > > 	--- i/gcc/testsuite/gcc.dg/countof-stdcountof.c
> > > 	+++ w/gcc/testsuite/gcc.dg/countof-stdcountof.c
> > > 	@@ -3,8 +3,7 @@
> > > 	 
> > > 	 #include <stdcountof.h>
> > > 	 
> > > 	-#undef NDEBUG
> > > 	-#include <assert.h>
> > > 	+#define assert(e)  ((e) ? (void) 0 : __builtin_abort ())
> > 
> > Yes, I think that's a reasonable way for a test to do its assertions with 
> > assert syntax but without depending unnecessarily on libc headers.
> 
> If there are any other issues, I'll apply that change for v23.  If this
> is the only one, would you mind amending yourself with that while
> committing?  Thanks!

Could you please clarify if I need to do anything or if this is already
scheduled for review when you have some time?  Also please clarify if
you're okay with amending that or if you prefer that I send v23.

TBH, I was a bit frustrated by the process when
-Wunterminated-string-initialization was reviewed, because nobody would
take the patch nor reply, and it was only when Martin asked me about it
that I said I had no idea about who should commit it that he committed
it.  A bit more communication would help.  :-)


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] 318+ messages in thread

* Re: [PATCH v22 0/3] c: Add _Countof and <stdcountof.h>
  2025-05-20 12:33             ` Alejandro Colomar
@ 2025-05-20 14:43               ` Joseph Myers
  2025-05-20 15:15                 ` Alejandro Colomar
  0 siblings, 1 reply; 318+ messages in thread
From: Joseph Myers @ 2025-05-20 14:43 UTC (permalink / raw)
  To: Alejandro Colomar
  Cc: gcc-patches, Martin Uecker, JeanHeyd Meneide, Jakub Jelinek

On Tue, 20 May 2025, Alejandro Colomar wrote:

> Could you please clarify if I need to do anything or if this is already
> scheduled for review when you have some time?  Also please clarify if
> you're okay with amending that or if you prefer that I send v23.

I have it on my list for review.  I'd prefer v23 (also with complete 
ChangeLog entries, please, rather than the present placeholders, so they 
don't need to be written at commit time).

-- 
Joseph S. Myers
josmyers@redhat.com


^ permalink raw reply	[flat|nested] 318+ messages in thread

* Re: [PATCH v22 0/3] c: Add _Countof and <stdcountof.h>
  2025-05-20 14:43               ` Joseph Myers
@ 2025-05-20 15:15                 ` Alejandro Colomar
  2025-05-20 15:25                   ` Jakub Jelinek
  0 siblings, 1 reply; 318+ messages in thread
From: Alejandro Colomar @ 2025-05-20 15:15 UTC (permalink / raw)
  To: Joseph Myers; +Cc: gcc-patches, Martin Uecker, JeanHeyd Meneide, Jakub Jelinek

[-- Attachment #1: Type: text/plain, Size: 2016 bytes --]

Hi Joseph,

On Tue, May 20, 2025 at 02:43:55PM +0000, Joseph Myers wrote:
> > Could you please clarify if I need to do anything or if this is already
> > scheduled for review when you have some time?  Also please clarify if
> > you're okay with amending that or if you prefer that I send v23.
> 
> I have it on my list for review.

Thanks!

>  I'd prefer v23 (also with complete 
> ChangeLog entries, please, rather than the present placeholders, so they 
> don't need to be written at commit time).

The ChangeLog entries that I've sent are supposed to be complete.  Did I
miss anything?

I've based on gnulib commits, which I believe follow the same
guidelines.  For example:

	commit 6608062398ef4c983a58b90a1520c39f12fb7ac1
	Author: Paul Eggert <eggert@cs.ucla.edu>
	Date:   Fri Jan 10 10:34:58 2025 -0800

	    doc: document some file system portability issues
	    
	    * doc/glibc-functions/flistxattr.texi:
	    * doc/glibc-functions/listxattr.texi:
	    * doc/glibc-functions/llistxattr.texi:
	    * doc/posix-functions/fchdir.texi, doc/posix-functions/fstat.texi:
	    * doc/posix-functions/fstatvfs.texi:
	    Document some portability gotchas that Gnulib does not work around.

Now I realize that maybe my changelog misses the trailing ':' for the
entries that have no text (because it's only once at the end)?  So for
example instead of

    gcc/c-family/ChangeLog:
    
            * c-common.h
            * c-common.def
            * c-common.cc (c_countof_type): Add __countof__ operator.

I should do this?

    gcc/c-family/ChangeLog:
    
            * c-common.h:
            * c-common.def:
            * c-common.cc (c_countof_type): Add __countof__ operator.

Or maybe this?

    gcc/c-family/ChangeLog:
    
            * c-common.h:
            * c-common.def:
            * c-common.cc (c_countof_type):
            Add __countof__ operator.

Please let me know.


Cheers,
Alex

-- 
<https://www.alejandro-colomar.es/>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 318+ messages in thread

* Re: [PATCH v22 0/3] c: Add _Countof and <stdcountof.h>
  2025-05-20 15:15                 ` Alejandro Colomar
@ 2025-05-20 15:25                   ` Jakub Jelinek
  2025-05-20 21:12                     ` Alejandro Colomar
  0 siblings, 1 reply; 318+ messages in thread
From: Jakub Jelinek @ 2025-05-20 15:25 UTC (permalink / raw)
  To: Alejandro Colomar
  Cc: Joseph Myers, gcc-patches, Martin Uecker, JeanHeyd Meneide

On Tue, May 20, 2025 at 05:15:33PM +0200, Alejandro Colomar wrote:
> I've based on gnulib commits, which I believe follow the same
> guidelines.  For example:
> 
> 	commit 6608062398ef4c983a58b90a1520c39f12fb7ac1
> 	Author: Paul Eggert <eggert@cs.ucla.edu>
> 	Date:   Fri Jan 10 10:34:58 2025 -0800
> 
> 	    doc: document some file system portability issues
> 	    
> 	    * doc/glibc-functions/flistxattr.texi:
> 	    * doc/glibc-functions/listxattr.texi:
> 	    * doc/glibc-functions/llistxattr.texi:
> 	    * doc/posix-functions/fchdir.texi, doc/posix-functions/fstat.texi:
> 	    * doc/posix-functions/fstatvfs.texi:
> 	    Document some portability gotchas that Gnulib does not work around.
> 
> Now I realize that maybe my changelog misses the trailing ':' for the
> entries that have no text (because it's only once at the end)?  So for
> example instead of
> 
>     gcc/c-family/ChangeLog:
>     
>             * c-common.h
>             * c-common.def
>             * c-common.cc (c_countof_type): Add __countof__ operator.
> 
> I should do this?
> 
>     gcc/c-family/ChangeLog:
>     
>             * c-common.h:
>             * c-common.def:
>             * c-common.cc (c_countof_type): Add __countof__ operator.
> 
> Or maybe this?
> 
>     gcc/c-family/ChangeLog:
>     
>             * c-common.h:
>             * c-common.def:
>             * c-common.cc (c_countof_type):
>             Add __countof__ operator.

We don't use (at least mostly) any of these, instead use
	* c-common.h (whatever changed): Description.
	* c-common.def (whatever else changed): Likewise.
	* c-common.cc (again what changed): Likewise.
and similar (or Ditto instead of Likewise).
And just c-common.h or c-common.def without actually specifying what
you've changed there is generally bad, there are some rare exceptions
(e.g. if you add #include, that is mentioned on the whole file, or
if there are massive repetitive changes everywhere).

	Jakub


^ permalink raw reply	[flat|nested] 318+ messages in thread

* Re: [PATCH v22 0/3] c: Add _Countof and <stdcountof.h>
  2025-05-20 15:25                   ` Jakub Jelinek
@ 2025-05-20 21:12                     ` Alejandro Colomar
  2025-05-20 21:20                       ` Jakub Jelinek
  0 siblings, 1 reply; 318+ messages in thread
From: Alejandro Colomar @ 2025-05-20 21:12 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: Joseph Myers, gcc-patches, Martin Uecker, JeanHeyd Meneide

[-- Attachment #1: Type: text/plain, Size: 2518 bytes --]

Hi Jakub,

On Tue, May 20, 2025 at 05:25:29PM +0200, Jakub Jelinek wrote:
> On Tue, May 20, 2025 at 05:15:33PM +0200, Alejandro Colomar wrote:
> > I've based on gnulib commits, which I believe follow the same
> > guidelines.  For example:
> > 
> > 	commit 6608062398ef4c983a58b90a1520c39f12fb7ac1
> > 	Author: Paul Eggert <eggert@cs.ucla.edu>
> > 	Date:   Fri Jan 10 10:34:58 2025 -0800
> > 
> > 	    doc: document some file system portability issues
> > 	    
> > 	    * doc/glibc-functions/flistxattr.texi:
> > 	    * doc/glibc-functions/listxattr.texi:
> > 	    * doc/glibc-functions/llistxattr.texi:
> > 	    * doc/posix-functions/fchdir.texi, doc/posix-functions/fstat.texi:
> > 	    * doc/posix-functions/fstatvfs.texi:
> > 	    Document some portability gotchas that Gnulib does not work around.
> > 
> > Now I realize that maybe my changelog misses the trailing ':' for the
> > entries that have no text (because it's only once at the end)?  So for
> > example instead of
> > 
> >     gcc/c-family/ChangeLog:
> >     
> >             * c-common.h
> >             * c-common.def
> >             * c-common.cc (c_countof_type): Add __countof__ operator.

Oops, I've now realized I should s/__countof__/_Countof/.

> > 
> > I should do this?
> > 
> >     gcc/c-family/ChangeLog:
> >     
> >             * c-common.h:
> >             * c-common.def:
> >             * c-common.cc (c_countof_type): Add __countof__ operator.
> > 
> > Or maybe this?
> > 
> >     gcc/c-family/ChangeLog:
> >     
> >             * c-common.h:
> >             * c-common.def:
> >             * c-common.cc (c_countof_type):
> >             Add __countof__ operator.
> 
> We don't use (at least mostly) any of these, instead use
> 	* c-common.h (whatever changed): Description.
> 	* c-common.def (whatever else changed): Likewise.
> 	* c-common.cc (again what changed): Likewise.
> and similar (or Ditto instead of Likewise).
> And just c-common.h or c-common.def without actually specifying what
> you've changed there is generally bad, there are some rare exceptions
> (e.g. if you add #include, that is mentioned on the whole file, or
> if there are massive repetitive changes everywhere).

Okay; how about this?

    gcc/c-family/ChangeLog:
    
            * c-common.h: Add _Countof operator.
            * c-common.def: Likewise.
            * c-common.cc (c_countof_type): Likewise.


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] 318+ messages in thread

* Re: [PATCH v22 0/3] c: Add _Countof and <stdcountof.h>
  2025-05-20 21:12                     ` Alejandro Colomar
@ 2025-05-20 21:20                       ` Jakub Jelinek
  2025-05-20 21:44                         ` Alejandro Colomar
  0 siblings, 1 reply; 318+ messages in thread
From: Jakub Jelinek @ 2025-05-20 21:20 UTC (permalink / raw)
  To: Alejandro Colomar
  Cc: Joseph Myers, gcc-patches, Martin Uecker, JeanHeyd Meneide

On Tue, May 20, 2025 at 11:12:38PM +0200, Alejandro Colomar wrote:
> Okay; how about this?
> 
>     gcc/c-family/ChangeLog:
>     
>             * c-common.h: Add _Countof operator.
>             * c-common.def: Likewise.
>             * c-common.cc (c_countof_type): Likewise.

No, that doesn't describe what you've changed and how.

So probably something like:

	* c-common.h (enum rid): Add RID_COUNTOF.
	* c-common.def (COUNTOF_EXPR): New tree.
	* c-common.cc (c_common_reswords): Add RID_COUNTOF entry.
	(c_countof_type): New function.

You can use contrib/mklog, that at least pre-fills some of it for you.

	Jakub


^ permalink raw reply	[flat|nested] 318+ messages in thread

* Re: [PATCH v22 0/3] c: Add _Countof and <stdcountof.h>
  2025-05-20 21:20                       ` Jakub Jelinek
@ 2025-05-20 21:44                         ` Alejandro Colomar
  2025-05-20 22:04                           ` Jakub Jelinek
  0 siblings, 1 reply; 318+ messages in thread
From: Alejandro Colomar @ 2025-05-20 21:44 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: Joseph Myers, gcc-patches, Martin Uecker, JeanHeyd Meneide

[-- Attachment #1: Type: text/plain, Size: 1589 bytes --]

Hi Jakub,

On Tue, May 20, 2025 at 11:20:27PM +0200, Jakub Jelinek wrote:
> On Tue, May 20, 2025 at 11:12:38PM +0200, Alejandro Colomar wrote:
> > Okay; how about this?
> > 
> >     gcc/c-family/ChangeLog:
> >     
> >             * c-common.h: Add _Countof operator.
> >             * c-common.def: Likewise.
> >             * c-common.cc (c_countof_type): Likewise.
> 
> No, that doesn't describe what you've changed and how.

Well, it does.  All the changes I've applied to those files are all
to implement the new _Countof operator, and only for that.  That is,
they're sufficient and necessary.  So, saying I've added the _Countof
operator is correct.  I could go and talk about the specific changes to
each file, but then I don't see the value in that change log over the
actual diff.

> 
> So probably something like:
> 
> 	* c-common.h (enum rid): Add RID_COUNTOF.
> 	* c-common.def (COUNTOF_EXPR): New tree.
> 	* c-common.cc (c_common_reswords): Add RID_COUNTOF entry.
> 	(c_countof_type): New function.

I'm honestly unsure about the usefulness of going too low level in the
changelog as to listing newly added functions as added functions,
instead of talking high-level about what they're for.  But if that's
what you want, then okay.

I think

	(c_countof_type): New function.

is an example of what I think is useless bureaucracy.  Could you please
confirm that's what you want?


Cheers,
Alex

> You can use contrib/mklog, that at least pre-fills some of it for you.
> 
> 	Jakub
> 

-- 
<https://www.alejandro-colomar.es/>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 318+ messages in thread

* Re: [PATCH v22 0/3] c: Add _Countof and <stdcountof.h>
  2025-05-20 21:44                         ` Alejandro Colomar
@ 2025-05-20 22:04                           ` Jakub Jelinek
  0 siblings, 0 replies; 318+ messages in thread
From: Jakub Jelinek @ 2025-05-20 22:04 UTC (permalink / raw)
  To: Alejandro Colomar
  Cc: Joseph Myers, gcc-patches, Martin Uecker, JeanHeyd Meneide

On Tue, May 20, 2025 at 11:44:43PM +0200, Alejandro Colomar wrote:
> Hi Jakub,
> 
> On Tue, May 20, 2025 at 11:20:27PM +0200, Jakub Jelinek wrote:
> > On Tue, May 20, 2025 at 11:12:38PM +0200, Alejandro Colomar wrote:
> > > Okay; how about this?
> > > 
> > >     gcc/c-family/ChangeLog:
> > >     
> > >             * c-common.h: Add _Countof operator.
> > >             * c-common.def: Likewise.
> > >             * c-common.cc (c_countof_type): Likewise.
> > 
> > No, that doesn't describe what you've changed and how.
> 
> Well, it does.  All the changes I've applied to those files are all
> to implement the new _Countof operator, and only for that.  That is,
> they're sufficient and necessary.  So, saying I've added the _Countof
> operator is correct.  I could go and talk about the specific changes to
> each file, but then I don't see the value in that change log over the
> actual diff.
> 
> > 
> > So probably something like:
> > 
> > 	* c-common.h (enum rid): Add RID_COUNTOF.
> > 	* c-common.def (COUNTOF_EXPR): New tree.
> > 	* c-common.cc (c_common_reswords): Add RID_COUNTOF entry.
> > 	(c_countof_type): New function.
> 
> I'm honestly unsure about the usefulness of going too low level in the
> changelog as to listing newly added functions as added functions,

No, that is exactly the level all others fill in and people grep that etc.

> instead of talking high-level about what they're for.  But if that's
> what you want, then okay.
> 
> I think
> 
> 	(c_countof_type): New function.
> 
> is an example of what I think is useless bureaucracy.  Could you please
> confirm that's what you want?

Yes, we want exactly that.

	Jakub


^ permalink raw reply	[flat|nested] 318+ messages in thread

* [PATCH v23 0/3] c: Add _Countof and <stdcountof.h>
  2024-07-28 14:15 ` [RFC v1 0/2] c: Add _Lengthof operator Alejandro Colomar
                     ` (25 preceding siblings ...)
  2025-05-15 22:37   ` [PATCH v22 0/3] c: Add _Countof and <stdcountof.h> Alejandro Colomar
@ 2025-05-21  0:17   ` Alejandro Colomar
  2025-05-21  0:18     ` [PATCH v23 1/3] c: Add _Countof operator Alejandro Colomar
                       ` (3 more replies)
  2025-05-21 21:01   ` [PATCH v24 " Alejandro Colomar
  2025-05-21 23:15   ` [PATCH v25 0/3] c: Add _Countof and <stdcountof.h> Alejandro Colomar
  28 siblings, 4 replies; 318+ messages in thread
From: Alejandro Colomar @ 2025-05-21  0:17 UTC (permalink / raw)
  To: gcc-patches
  Cc: Alejandro Colomar, Martin Uecker, JeanHeyd Meneide, Joseph Myers,
	Jakub Jelinek

Hi!

Here's another revision of this patch set.

v23 changes:

-  More specific change logs.
-  #define assert() instead of #include'ing <assert.h>.

`make check` says all's good.  I haven't diffed against master this
time, because that's slow as hell, and the changes are minimal.  I've
only ran `make check -j24` once at the tip, and all the countof tests
pass.


Have a lovely night!
Alex


Alejandro Colomar (3):
  c: Add _Countof operator
  c: Add <stdcountof.h>
  c: Add -Wpedantic diagnostic for _Countof

 gcc/Makefile.in                               |   1 +
 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                               |  22 +++-
 gcc/c/c-parser.cc                             |  63 +++++++--
 gcc/c/c-tree.h                                |   4 +
 gcc/c/c-typeck.cc                             | 115 +++++++++++++++-
 gcc/doc/extend.texi                           |  30 +++++
 gcc/ginclude/stdcountof.h                     |  31 +++++
 gcc/testsuite/gcc.dg/countof-compat.c         |   8 ++
 gcc/testsuite/gcc.dg/countof-compile.c        | 124 ++++++++++++++++++
 gcc/testsuite/gcc.dg/countof-no-compat.c      |   5 +
 .../gcc.dg/countof-pedantic-errors.c          |   8 ++
 gcc/testsuite/gcc.dg/countof-pedantic.c       |   8 ++
 gcc/testsuite/gcc.dg/countof-stdcountof.c     |  24 ++++
 gcc/testsuite/gcc.dg/countof-vla.c            |  35 +++++
 gcc/testsuite/gcc.dg/countof-vmt.c            |  20 +++
 gcc/testsuite/gcc.dg/countof-zero-compile.c   |  38 ++++++
 gcc/testsuite/gcc.dg/countof-zero.c           |  31 +++++
 gcc/testsuite/gcc.dg/countof.c                | 120 +++++++++++++++++
 21 files changed, 694 insertions(+), 24 deletions(-)
 create mode 100644 gcc/ginclude/stdcountof.h
 create mode 100644 gcc/testsuite/gcc.dg/countof-compat.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-compile.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-no-compat.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-pedantic-errors.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-pedantic.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-stdcountof.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-vla.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-vmt.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-zero-compile.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-zero.c
 create mode 100644 gcc/testsuite/gcc.dg/countof.c

Range-diff against v22:
1:  1c983c3baa7f ! 1:  5040a7d25a96 c: Add _Countof operator
    @@ Commit message
     
         gcc/c-family/ChangeLog:
     
    -            * c-common.h
    -            * c-common.def
    -            * c-common.cc (c_countof_type): Add _Countof operator.
    +            * c-common.h: Add RID_COUNTOF.
    +            (c_countof_type): New function prototype.
    +            * c-common.def (COUNTOF_EXPR): New tree.
    +            * c-common.cc
    +            (c_common_reswords): Add RID_COUNTOF entry.
    +            (c_countof_type): New function.
     
         gcc/c/ChangeLog:
     
                 * c-tree.h
    -            (c_expr_countof_expr, c_expr_countof_type)
    +            (in_countof): Add global variable declaration.
    +            (c_expr_countof_expr): Add function prototype.
    +            (c_expr_countof_type): Add function prototype.
                 * c-decl.cc
    -            (start_struct, finish_struct)
    -            (start_enum, finish_enum)
    +            (start_struct, finish_struct): Add support for _Countof.
    +            (start_enum, finish_enum): Add support for _Countof.
                 * c-parser.cc
    -            (c_parser_sizeof_expression)
    -            (c_parser_countof_expression)
    -            (c_parser_sizeof_or_countof_expression)
    -            (c_parser_unary_expression)
    +            (c_parser_sizeof_expression): New macro.
    +            (c_parser_countof_expression): New macro.
    +            (c_parser_sizeof_or_countof_expression):
    +            Rename function and add support for _Countof.
    +            (c_parser_unary_expression): Add RID_COUNTOF entry.
                 * c-typeck.cc
    -            (build_external_ref)
    -            (record_maybe_used_decl)
    -            (pop_maybe_used)
    -            (is_top_array_vla)
    -            (c_expr_countof_expr, c_expr_countof_type):
    +            (in_countof): Add global variable.
    +            (build_external_ref): Add support for _Countof.
    +            (record_maybe_used_decl): Add support for _Countof.
    +            (pop_maybe_used): Add support for _Countof.
    +            (is_top_array_vla): New function.
    +            (c_expr_countof_expr, c_expr_countof_type): New functions.
                 Add _Countof operator.
     
         gcc/testsuite/ChangeLog:
     
    -            * gcc.dg/countof-compile.c
    -            * gcc.dg/countof-vla.c
    -            * gcc.dg/countof-vmt.c
    -            * gcc.dg/countof-zero-compile.c
    -            * gcc.dg/countof-zero.c
    -            * gcc.dg/countof.c: Add tests for _Countof operator.
    +            * gcc.dg/countof-compile.c: Compile-time tests for _Countof.
    +            * gcc.dg/countof-vla.c: Tests for _Countof with VLAs.
    +            * gcc.dg/countof-vmt.c: Tests for _Countof with other VMTs.
    +            * gcc.dg/countof-zero-compile.c:
    +            Compile-time tests for _Countof with zero-sized arrays.
    +            * gcc.dg/countof-zero.c:
    +            Tests for _Countof with zero-sized arrays.
    +            * gcc.dg/countof.c: Tests for _Countof.
     
         Suggested-by: Xavier Del Campo Romero <xavi.dcr@tutanota.com>
         Co-authored-by: Martin Uecker <uecker@tugraz.at>
    @@ gcc/testsuite/gcc.dg/countof-vmt.c (new)
     +/* { dg-do run } */
     +/* { dg-options "-std=c2y" } */
     +
    -+#undef NDEBUG
    -+#include <assert.h>
    ++#define assert(e)  ((e) ? (void) 0 : __builtin_abort ())
     +
     +void
     +inner_vla_noeval (void)
    @@ gcc/testsuite/gcc.dg/countof-zero.c (new)
     +/* { dg-do run } */
     +/* { dg-options "-std=c2y" } */
     +
    -+#undef NDEBUG
    -+#include <assert.h>
    ++#define assert(e)  ((e) ? (void) 0 : __builtin_abort ())
     +
     +void
     +vla (void)
    @@ gcc/testsuite/gcc.dg/countof.c (new)
     +/* { dg-do run } */
     +/* { dg-options "-std=c2y -pedantic-errors" } */
     +
    -+#undef NDEBUG
    -+#include <assert.h>
    ++#define assert(e)  ((e) ? (void) 0 : __builtin_abort ())
     +
     +void
     +array (void)
2:  418f81175e78 ! 2:  a560cf1ae23b c: Add <stdcountof.h>
    @@ gcc/testsuite/gcc.dg/countof-stdcountof.c (new)
     +
     +#include <stdcountof.h>
     +
    -+#undef NDEBUG
    -+#include <assert.h>
    ++#define assert(e)  ((e) ? (void) 0 : __builtin_abort ())
     +
     +extern int strcmp (const char *, const char *);
     +
3:  c44ef4a2c751 ! 3:  b1974a4507bc c: Add -Wpedantic diagnostic for _Countof
    @@ Commit message
     
         gcc/testsuite/ChangeLog:
     
    -            * gcc.dg/countof-compat.c
    -            * gcc.dg/countof-no-compat.c
    -            * gcc.dg/countof-pedantic.c
    +            * gcc.dg/countof-compat.c:
    +            Test _Countof diagnostics with -Wc23-c2y-compat on C2y.
    +            * gcc.dg/countof-no-compat.c:
    +            Test _Countof diagnostics with -Wno-c23-c2y-compat on C23.
    +            * gcc.dg/countof-pedantic.c:
    +            Test _Countof diagnostics with -pedantic on C23.
                 * gcc.dg/countof-pedantic-errors.c:
    -            Test pedantic diagnostics for _Countof.
    +            Test _Countof diagnostics with -pedantic-errors on C23.
     
         Signed-off-by: Alejandro Colomar <alx@kernel.org>
     

base-commit: 90c6ccebd762ae920690fce20cd3f2b8e24357a7
-- 
2.49.0


^ permalink raw reply	[flat|nested] 318+ messages in thread

* [PATCH v23 1/3] c: Add _Countof operator
  2025-05-21  0:17   ` [PATCH v23 " Alejandro Colomar
@ 2025-05-21  0:18     ` Alejandro Colomar
  2025-05-21 16:26       ` Joseph Myers
  2025-05-21  0:18     ` [PATCH v23 2/3] c: Add <stdcountof.h> Alejandro Colomar
                       ` (2 subsequent siblings)
  3 siblings, 1 reply; 318+ messages in thread
From: Alejandro Colomar @ 2025-05-21  0:18 UTC (permalink / raw)
  To: gcc-patches
  Cc: Alejandro Colomar, Martin Uecker, JeanHeyd Meneide, Joseph Myers,
	Jakub Jelinek, Xavier Del Campo Romero, James K. Lowden

This operator is similar to sizeof but can only be applied to an array,
and returns its number of elements.

FUTURE DIRECTIONS:

-  We should make it work with array parameters to functions,
   and somehow magically return the number of elements of the array,
   regardless of it being really a pointer.

Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3550.pdf>
Link: <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117025>
Link: <https://inbox.sourceware.org/gcc/M8S4oQy--3-2@tutanota.com/T/>
Link: <https://inbox.sourceware.org/gcc-patches/20240728141547.302478-1-alx@kernel.org/T/#t>
Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3313.pdf>
Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3325.pdf>
Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3369.pdf>
Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3469.htm>
Link: <https://github.com/llvm/llvm-project/issues/102836>
Link: <https://thephd.dev/the-big-array-size-survey-for-c>
Link: <https://thephd.dev/the-big-array-size-survey-for-c-results>
Link: <https://stackoverflow.com/questions/37538/#57537491>

gcc/ChangeLog:

	* doc/extend.texi: Document _Countof operator.

gcc/c-family/ChangeLog:

	* c-common.h: Add RID_COUNTOF.
	(c_countof_type): New function prototype.
	* c-common.def (COUNTOF_EXPR): New tree.
	* c-common.cc
	(c_common_reswords): Add RID_COUNTOF entry.
	(c_countof_type): New function.

gcc/c/ChangeLog:

	* c-tree.h
	(in_countof): Add global variable declaration.
	(c_expr_countof_expr): Add function prototype.
	(c_expr_countof_type): Add function prototype.
	* c-decl.cc
	(start_struct, finish_struct): Add support for _Countof.
	(start_enum, finish_enum): Add support for _Countof.
	* c-parser.cc
	(c_parser_sizeof_expression): New macro.
	(c_parser_countof_expression): New macro.
	(c_parser_sizeof_or_countof_expression):
	Rename function and add support for _Countof.
	(c_parser_unary_expression): Add RID_COUNTOF entry.
	* c-typeck.cc
	(in_countof): Add global variable.
	(build_external_ref): Add support for _Countof.
	(record_maybe_used_decl): Add support for _Countof.
	(pop_maybe_used): Add support for _Countof.
	(is_top_array_vla): New function.
	(c_expr_countof_expr, c_expr_countof_type): New functions.
	Add _Countof operator.

gcc/testsuite/ChangeLog:

	* gcc.dg/countof-compile.c: Compile-time tests for _Countof.
	* gcc.dg/countof-vla.c: Tests for _Countof with VLAs.
	* gcc.dg/countof-vmt.c: Tests for _Countof with other VMTs.
	* gcc.dg/countof-zero-compile.c:
	Compile-time tests for _Countof with zero-sized arrays.
	* gcc.dg/countof-zero.c:
	Tests for _Countof with zero-sized arrays.
	* gcc.dg/countof.c: Tests for _Countof.

Suggested-by: Xavier Del Campo Romero <xavi.dcr@tutanota.com>
Co-authored-by: Martin Uecker <uecker@tugraz.at>
Acked-by: "James K. Lowden" <jklowden@schemamania.org>
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                             |  22 +++-
 gcc/c/c-parser.cc                           |  59 +++++++---
 gcc/c/c-tree.h                              |   4 +
 gcc/c/c-typeck.cc                           | 115 +++++++++++++++++-
 gcc/doc/extend.texi                         |  30 +++++
 gcc/testsuite/gcc.dg/countof-compile.c      | 124 ++++++++++++++++++++
 gcc/testsuite/gcc.dg/countof-vla.c          |  35 ++++++
 gcc/testsuite/gcc.dg/countof-vmt.c          |  20 ++++
 gcc/testsuite/gcc.dg/countof-zero-compile.c |  38 ++++++
 gcc/testsuite/gcc.dg/countof-zero.c         |  31 +++++
 gcc/testsuite/gcc.dg/countof.c              | 120 +++++++++++++++++++
 14 files changed, 605 insertions(+), 24 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/countof-compile.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-vla.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-vmt.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-zero-compile.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-zero.c
 create mode 100644 gcc/testsuite/gcc.dg/countof.c

diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
index 587d76461e9e..f71cb2652d5a 100644
--- a/gcc/c-family/c-common.cc
+++ b/gcc/c-family/c-common.cc
@@ -394,6 +394,7 @@ const struct c_common_resword c_common_reswords[] =
 {
   { "_Alignas",		RID_ALIGNAS,   D_CONLY },
   { "_Alignof",		RID_ALIGNOF,   D_CONLY },
+  { "_Countof",		RID_COUNTOF,   D_CONLY },
   { "_Atomic",		RID_ATOMIC,    D_CONLY },
   { "_BitInt",		RID_BITINT,    D_CONLY },
   { "_Bool",		RID_BOOL,      D_CONLY },
@@ -4080,6 +4081,31 @@ c_alignof_expr (location_t loc, tree expr)
 
   return fold_convert_loc (loc, size_type_node, t);
 }
+
+/* Implement the _Countof keyword:
+   Return the number of elements of an array.  */
+
+tree
+c_countof_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 %<_Countof%> to type %qT", type);
+      return error_mark_node;
+    }
+  if (!COMPLETE_TYPE_P (type))
+    {
+      error_at (loc,
+		"invalid application of %<_Countof%> 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 cf2228201fad..0bcc4998afe6 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 'countof' expression.  */
+DEFTREECODE (COUNTOF_EXPR, "countof_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 ea6c29750567..91fd120e77e1 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_COUNTOF,
   RID_C23_VA_START, RID_VA_ARG,
   RID_EXTENSION, RID_IMAGPART, RID_REALPART, RID_LABEL,    RID_CHOOSE_EXPR,
   RID_TYPES_COMPATIBLE_P,      RID_BUILTIN_COMPLEX,	   RID_BUILTIN_SHUFFLE,
@@ -890,6 +891,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_countof_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 ad66d7d258b8..5bf638bfbd81 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -8943,12 +8943,17 @@ 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_countof))
     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"
+		       : "_Countof"))));
 
   if (in_underspecified_init)
     error_at (loc, "%qT defined in underspecified object initializer", ref);
@@ -9923,7 +9928,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_countof)
 	struct_parse_info->struct_types.safe_push (t);
      }
 
@@ -10097,12 +10102,17 @@ 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_countof))
     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"
+		       : "_Countof"))));
 
   if (in_underspecified_init)
     error_at (loc, "%qT defined in underspecified object initializer",
@@ -10296,7 +10306,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_countof)
     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 8a63dc54c795..87700339394b 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -77,7 +77,17 @@ along with GCC; see the file COPYING3.  If not see
 #include "asan.h"
 #include "c-family/c-ubsan.h"
 #include "gcc-urlifier.h"
+\f
+#define c_parser_sizeof_expression(parser)                                    \
+(                                                                             \
+  c_parser_sizeof_or_countof_expression (parser, RID_SIZEOF)                  \
+)
 
+#define c_parser_countof_expression(parser)                                   \
+(                                                                             \
+  c_parser_sizeof_or_countof_expression (parser, RID_COUNTOF)                 \
+)
+\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
@@ -1737,7 +1747,8 @@ 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_countof_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 *,
@@ -10572,6 +10583,8 @@ c_parser_unary_expression (c_parser *parser)
     case CPP_KEYWORD:
       switch (c_parser_peek_token (parser)->keyword)
 	{
+	case RID_COUNTOF:
+	  return c_parser_countof_expression (parser);
 	case RID_SIZEOF:
 	  return c_parser_sizeof_expression (parser);
 	case RID_ALIGNOF:
@@ -10611,12 +10624,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_countof_expression (c_parser *parser, enum rid rid)
 {
+  const char *op_name = (rid == RID_COUNTOF) ? "_Countof" : "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;
@@ -10625,7 +10639,10 @@ c_parser_sizeof_expression (c_parser *parser)
 
   c_parser_consume_token (parser);
   c_inhibit_evaluation_warnings++;
-  in_sizeof++;
+  if (rid == RID_COUNTOF)
+    in_countof++;
+  else
+    in_sizeof++;
   if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)
       && c_token_starts_compound_literal (c_parser_peek_2nd_token (parser)))
     {
@@ -10646,7 +10663,7 @@ c_parser_sizeof_expression (c_parser *parser)
 	     for parsing error; the parsing of the expression could have
 	     called record_maybe_used_decl.  */
 	  expr.set_error ();
-	  goto sizeof_expr;
+	  goto Xof_expr;
 	}
       if (c_parser_next_token_is (parser, CPP_OPEN_BRACE))
 	{
@@ -10654,31 +10671,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_COUNTOF)
+	{
+	  in_countof--;
+	  result = c_expr_countof_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_COUNTOF)
+	in_countof--;
+      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_COUNTOF)
+	result = c_expr_countof_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 2098120de297..723a28b39069 100644
--- a/gcc/c/c-tree.h
+++ b/gcc/c/c-tree.h
@@ -765,6 +765,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_countof;
 extern int in_typeof;
 extern bool c_in_omp_for;
 extern bool c_omp_array_section_p;
@@ -827,6 +828,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_countof_expr (location_t, struct c_expr);
+extern struct c_expr c_expr_countof_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 0e1f842e22d3..360216b96621 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -72,6 +72,9 @@ int in_alignof;
 /* The level of nesting inside "sizeof".  */
 int in_sizeof;
 
+/* The level of nesting inside "countof".  */
+int in_countof;
+
 /* The level of nesting inside "typeof".  */
 int in_typeof;
 
@@ -3540,7 +3543,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_countof)
 	C_DECL_USED (ref) = 1;
       else if (DECL_INITIAL (ref) == NULL_TREE
 	       && DECL_EXTERNAL (ref)
@@ -3596,7 +3599,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_countof).  */
   int level;
   /* The next one at this level or above, or NULL.  */
   struct maybe_used_decl *next;
@@ -3614,7 +3617,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_countof;
   t->next = maybe_used_decls;
   maybe_used_decls = t;
 }
@@ -3628,7 +3631,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_countof;
   while (p && p->level > cur_level)
     {
       if (used)
@@ -3738,6 +3741,110 @@ 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);
+  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 countof applied to EXPR.  */
+
+struct c_expr
+c_expr_countof_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_countof_type (loc, TREE_TYPE (folded_expr));
+      c_last_sizeof_arg = expr.value;
+      c_last_sizeof_loc = loc;
+      ret.original_code = COUNTOF_EXPR;
+      ret.original_type = NULL;
+      ret.m_decimal = 0;
+      if (is_top_array_vla (TREE_TYPE (folded_expr)))
+	{
+	  /* countof 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 countof applied to T, a structure for the type
+   name passed to countof (rather than the type itself).  LOC is the
+   location of the original expression.  */
+
+struct c_expr
+c_expr_countof_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_countof_type (loc, type);
+  c_last_sizeof_arg = type;
+  c_last_sizeof_loc = loc;
+  ret.original_code = COUNTOF_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 countof does not get folded to a constant by
+	 c_fully_fold, because if the number of elements is evaluated
+	 the result is not constant and so
+	 constraints on zero or negative size arrays must not be applied
+	 when this countof 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/doc/extend.texi b/gcc/doc/extend.texi
index 40ccf22b29f4..18ee287a3480 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -10706,6 +10706,36 @@ library.
 @xref{OpenMP and OpenACC Options}, for additional options useful with
 @option{-fopenacc}.
 
+@node _Countof
+@section Determining the Number of Elements of Arrays
+@cindex _Countof
+@cindex number of elements
+
+The keyword @code{_Countof} determines
+the number of elements of an array operand.
+Its syntax is similar to @code{sizeof}.
+The operand must be
+a parenthesized complete array type name
+or an expression of such a type.
+For example:
+
+@smallexample
+int a[n];
+_Countof (a);  // returns n
+_Countof (int [7][3]);  // returns 7
+@end smallexample
+
+The result of this operator is an integer constant expression,
+unless the array has a variable number of elements.
+The operand is only evaluated
+if the array has a variable number of elements.
+For example:
+
+@smallexample
+_Countof (int [7][n++]);  // integer constant expression
+_Countof (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/testsuite/gcc.dg/countof-compile.c b/gcc/testsuite/gcc.dg/countof-compile.c
new file mode 100644
index 000000000000..afd5659618b4
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/countof-compile.c
@@ -0,0 +1,124 @@
+/* { dg-do compile } */
+/* { dg-options "-std=c2y -pedantic-errors" } */
+
+#define NULL  ((void *) 0)
+
+extern int x[];
+
+static int w[] = {1, 2, 3};
+
+void
+completed (void)
+{
+  int i = 42;
+  int a[] = {1, 2, i};
+
+  _Static_assert(_Countof (w) == 3);
+  _Static_assert(_Countof (a) == 3);
+}
+
+void
+incomplete (int p[])
+{
+  _Countof (x);  /* { dg-error "incomplete" } */
+
+  /* We want to support array parameters in the future,
+     which should change this from "invalid" to "incomplete".  */
+  _Countof (p);  /* { dg-error "invalid" } */
+}
+
+void
+fam (void)
+{
+  struct {
+    int x;
+    int fam[];
+  } s;
+
+  _Countof (s.fam); /* { dg-error "incomplete" } */
+}
+
+void
+param (int n, int p[n])
+{
+  /* We want to support array parameters in the future,
+     which would make this work.  */
+  _Countof (p);  /* { dg-error "invalid" } */
+}
+
+void fix_fix (int i, char (*a)[3][5], int (*x)[_Countof (*a)],
+	      short (*)[_Generic(x, int (*)[3]: 1)]);
+void fix_var (int i, char (*a)[3][i], int (*x)[_Countof (*a)],
+	      short (*)[_Generic(x, int (*)[3]: 1)]);
+void fix_uns (int i, char (*a)[3][*], int (*x)[_Countof (*a)],
+	      short (*)[_Generic(x, int (*)[3]: 1)]);
+
+void
+func (void)
+{
+  int  i3[3];
+  int  i5[5];
+  char c35[3][5];
+
+  fix_fix (5, &c35, &i3, NULL);
+  fix_fix (5, &c35, &i5, NULL); /* { dg-error "incompatible-pointer-types" } */
+
+  fix_var (5, &c35, &i3, NULL);
+  fix_var (5, &c35, &i5, NULL); /* { dg-error "incompatible-pointer-types" } */
+
+  fix_uns (5, &c35, &i3, NULL);
+  fix_uns (5, &c35, &i5, NULL); /* { dg-error "incompatible-pointer-types" } */
+}
+
+void
+non_arr(void)
+{
+  int x;
+  int *p;
+  struct s {
+    int x[3];
+  } s;
+
+  _Countof (x); /* { dg-error "invalid" } */
+  _Countof (int); /* { dg-error "invalid" } */
+  _Countof (s); /* { dg-error "invalid" } */
+  _Countof (struct s); /* { dg-error "invalid" } */
+  _Countof (&x); /* { dg-error "invalid" } */
+  _Countof (p); /* { dg-error "invalid" } */
+  _Countof (int *); /* { dg-error "invalid" } */
+  _Countof (&s.x); /* { dg-error "invalid" } */
+  _Countof (int (*)[3]); /* { dg-error "invalid" } */
+}
+
+static int f1();
+static int f2(); /* { dg-error "never defined" } */
+int a[10][9];
+int n;
+
+void
+syms(void)
+{
+  int b[n][n];
+
+  _Countof (a[f1()]);
+  _Countof (b[f2()]);
+}
+
+void
+no_parens(void)
+{
+  _Static_assert(_Countof a == 10);
+  _Static_assert(_Countof *a == 9);
+  _Static_assert(_Countof (int [3]) {} == 3);
+
+  _Countof int [3]; /* { dg-error "expected expression before" } */
+}
+
+void
+const_expr(void)
+{
+  int n = 7;
+
+  _Static_assert (_Countof (int [3][n]) == 3);
+  _Static_assert (_Countof (int [n][3]) == 7); /* { dg-error "not constant" } */
+}
diff --git a/gcc/testsuite/gcc.dg/countof-vla.c b/gcc/testsuite/gcc.dg/countof-vla.c
new file mode 100644
index 000000000000..cc225df20689
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/countof-vla.c
@@ -0,0 +1,35 @@
+/* { dg-do compile } */
+/* { dg-options "-std=c2y -pedantic-errors -Wvla-parameter" } */
+
+void fix_fix (int i,
+	      char (*a)[3][5],
+	      int (*x)[_Countof (*a)],
+	      short (*)[_Generic(x, int (*)[3]: 1)]);
+void fix_var (int i,
+	      char (*a)[3][i], /* dg-warn "variable" */
+	      int (*x)[_Countof (*a)],
+	      short (*)[_Generic(x, int (*)[3]: 1)]);
+void fix_uns (int i,
+	      char (*a)[3][*],
+	      int (*x)[_Countof (*a)],
+	      short (*)[_Generic(x, int (*)[3]: 1)]);
+
+void var_fix (int i,
+	      char (*a)[i][5], /* dg-warn "variable" */
+	      int (*x)[_Countof (*a)]); /* dg-warn "variable" */
+void var_var (int i,
+	      char (*a)[i][i], /* dg-warn "variable" */
+	      int (*x)[_Countof (*a)]); /* dg-warn "variable" */
+void var_uns (int i,
+	      char (*a)[i][*], /* dg-warn "variable" */
+	      int (*x)[_Countof (*a)]); /* dg-warn "variable" */
+
+void uns_fix (int i,
+	      char (*a)[*][5],
+	      int (*x)[_Countof (*a)]);
+void uns_var (int i,
+	      char (*a)[*][i], /* dg-warn "variable" */
+	      int (*x)[_Countof (*a)]);
+void uns_uns (int i,
+	      char (*a)[*][*],
+	      int (*x)[_Countof (*a)]);
diff --git a/gcc/testsuite/gcc.dg/countof-vmt.c b/gcc/testsuite/gcc.dg/countof-vmt.c
new file mode 100644
index 000000000000..cf4bfd1aa74e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/countof-vmt.c
@@ -0,0 +1,20 @@
+/* { dg-do run } */
+/* { dg-options "-std=c2y" } */
+
+#define assert(e)  ((e) ? (void) 0 : __builtin_abort ())
+
+void
+inner_vla_noeval (void)
+{
+  int i;
+
+  i = 3;
+  static_assert (_Countof (struct {int x[i++];}[3]) == 3);
+  assert (i == 3);
+}
+
+int
+main (void)
+{
+  inner_vla_noeval ();
+}
diff --git a/gcc/testsuite/gcc.dg/countof-zero-compile.c b/gcc/testsuite/gcc.dg/countof-zero-compile.c
new file mode 100644
index 000000000000..3dc60ce293bd
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/countof-zero-compile.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-std=c2y" } */
+
+static int z[0];
+static int y[_Countof (z)];
+
+_Static_assert(_Countof (y) == 0);
+
+void
+completed (void)
+{
+  int z[] = {};
+
+  static_assert (_Countof (z) == 0);
+}
+
+void zro_fix (int i,
+	      char (*a)[0][5],
+	      int (*x)[_Countof (*a)],
+	      short (*)[_Generic(x, int (*)[0]: 1)]);
+void zro_var (int i,
+	      char (*a)[0][i], /* dg-warn "variable" */
+	      int (*x)[_Countof (*a)],
+	      short (*)[_Generic(x, int (*)[0]: 1)]);
+void zro_uns (int i,
+	      char (*a)[0][*],
+	      int (*x)[_Countof (*a)],
+	      short (*)[_Generic(x, int (*)[0]: 1)]);
+
+void
+const_expr(void)
+{
+  int n = 7;
+
+  _Static_assert (_Countof (int [0][3]) == 0);
+  _Static_assert (_Countof (int [0]) == 0);
+  _Static_assert (_Countof (int [0][n]) == 0);
+}
diff --git a/gcc/testsuite/gcc.dg/countof-zero.c b/gcc/testsuite/gcc.dg/countof-zero.c
new file mode 100644
index 000000000000..678a08148a5c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/countof-zero.c
@@ -0,0 +1,31 @@
+/* { dg-do run } */
+/* { dg-options "-std=c2y" } */
+
+#define assert(e)  ((e) ? (void) 0 : __builtin_abort ())
+
+void
+vla (void)
+{
+  unsigned n;
+
+  n = 0;
+  int z[n];
+  assert (_Countof (z) == 0);
+}
+
+void
+matrix_vla (void)
+{
+  int i;
+
+  i = 0;
+  assert (_Countof (int [i++][4]) == 0);
+  assert (i == 0 + 1);
+}
+
+int
+main (void)
+{
+  vla ();
+  matrix_vla ();
+}
diff --git a/gcc/testsuite/gcc.dg/countof.c b/gcc/testsuite/gcc.dg/countof.c
new file mode 100644
index 000000000000..534488501c6a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/countof.c
@@ -0,0 +1,120 @@
+/* { dg-do run } */
+/* { dg-options "-std=c2y -pedantic-errors" } */
+
+#define assert(e)  ((e) ? (void) 0 : __builtin_abort ())
+
+void
+array (void)
+{
+  short a[7];
+
+  static_assert (_Countof (a) == 7);
+  static_assert (_Countof (unsigned [99]) == 99);
+}
+
+void
+completed (void)
+{
+  int a[] = {1, 2, 3};
+
+  static_assert (_Countof (a) == 3);
+}
+
+void
+vla (void)
+{
+  unsigned n;
+
+  n = 99;
+  assert (_Countof (short [n - 10]) == 99 - 10);
+
+  int v[n / 2];
+  assert (_Countof (v) == 99 / 2);
+}
+
+void
+member (void)
+{
+  struct {
+    int a[8];
+  } s;
+
+  static_assert (_Countof (s.a) == 8);
+}
+
+void
+vla_eval (void)
+{
+  int i;
+
+  i = 7;
+  assert (_Countof (struct {int x;}[i++]) == 7);
+  assert (i == 7 + 1);
+
+  int v[i];
+  int (*p)[i];
+  p = &v;
+  assert (_Countof (*p++) == i);
+  assert (p - 1 == &v);
+}
+
+void
+array_noeval (void)
+{
+  long a[5];
+  long (*p)[_Countof (a)];
+
+  p = &a;
+  static_assert (_Countof (*p++) == 5);
+  assert (p == &a);
+}
+
+void
+matrix_fixed (void)
+{
+  int i;
+
+  static_assert (_Countof (int [7][4]) == 7);
+  i = 3;
+  static_assert (_Countof (int [7][i]) == 7);
+}
+
+void
+matrix_vla (void)
+{
+  int i, j;
+
+  i = 7;
+  assert (_Countof (int [i++][4]) == 7);
+  assert (i == 7 + 1);
+
+  i = 9;
+  j = 3;
+  assert (_Countof (int [i++][j]) == 9);
+  assert (i == 9 + 1);
+}
+
+void
+no_parens(void)
+{
+  int n = 3;
+  int a[7];
+  int v[n];
+
+  static_assert (_Countof a == 7); 
+  assert (_Countof v == 3); 
+}
+
+int
+main (void)
+{
+  array ();
+  completed ();
+  vla ();
+  member ();
+  vla_eval ();
+  array_noeval ();
+  matrix_fixed ();
+  matrix_vla ();
+  no_parens ();
+}
-- 
2.49.0


^ permalink raw reply	[flat|nested] 318+ messages in thread

* [PATCH v23 2/3] c: Add <stdcountof.h>
  2025-05-21  0:17   ` [PATCH v23 " Alejandro Colomar
  2025-05-21  0:18     ` [PATCH v23 1/3] c: Add _Countof operator Alejandro Colomar
@ 2025-05-21  0:18     ` Alejandro Colomar
  2025-05-21  0:18     ` [PATCH v23 3/3] c: Add -Wpedantic diagnostic for _Countof Alejandro Colomar
  2025-05-21  8:56     ` [PATCH v23 0/3] c: Add _Countof and <stdcountof.h> Alejandro Colomar
  3 siblings, 0 replies; 318+ messages in thread
From: Alejandro Colomar @ 2025-05-21  0:18 UTC (permalink / raw)
  To: gcc-patches
  Cc: Alejandro Colomar, Martin Uecker, JeanHeyd Meneide, Joseph Myers,
	Jakub Jelinek

gcc/ChangeLog:

	* Makefile.in (USER_H): Add <stdcountof.h>.
	* ginclude/stdcountof.h: Add countof macro.

gcc/testsuite/ChangeLog:

	* gcc.dg/countof-stdcountof.c: Add tests for <stdcountof.h>.

Signed-off-by: Alejandro Colomar <alx@kernel.org>
---
 gcc/Makefile.in                           |  1 +
 gcc/ginclude/stdcountof.h                 | 31 +++++++++++++++++++++++
 gcc/testsuite/gcc.dg/countof-stdcountof.c | 24 ++++++++++++++++++
 3 files changed, 56 insertions(+)
 create mode 100644 gcc/ginclude/stdcountof.h
 create mode 100644 gcc/testsuite/gcc.dg/countof-stdcountof.c

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 72d132207c0d..fc8a7e532b97 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -481,6 +481,7 @@ USER_H = $(srcdir)/ginclude/float.h \
 	 $(srcdir)/ginclude/stdalign.h \
 	 $(srcdir)/ginclude/stdatomic.h \
 	 $(srcdir)/ginclude/stdckdint.h \
+	 $(srcdir)/ginclude/stdcountof.h \
 	 $(EXTRA_HEADERS)
 
 USER_H_INC_NEXT_PRE = @user_headers_inc_next_pre@
diff --git a/gcc/ginclude/stdcountof.h b/gcc/ginclude/stdcountof.h
new file mode 100644
index 000000000000..1d914f40e5db
--- /dev/null
+++ b/gcc/ginclude/stdcountof.h
@@ -0,0 +1,31 @@
+/* Copyright (C) 2025 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/>.  */
+
+/* ISO C2Y: 7.21 Array count <stdcountof.h>.  */
+
+#ifndef _STDCOUNTOF_H
+#define _STDCOUNTOF_H
+
+#define countof  _Countof
+
+#endif	/* stdcountof.h */
diff --git a/gcc/testsuite/gcc.dg/countof-stdcountof.c b/gcc/testsuite/gcc.dg/countof-stdcountof.c
new file mode 100644
index 000000000000..2fb0c6306ef0
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/countof-stdcountof.c
@@ -0,0 +1,24 @@
+/* { dg-do run } */
+/* { dg-options "-std=c2y -pedantic-errors" } */
+
+#include <stdcountof.h>
+
+#define assert(e)  ((e) ? (void) 0 : __builtin_abort ())
+
+extern int strcmp (const char *, const char *);
+
+#ifndef countof
+#error "countof not defined"
+#endif
+
+int a[3];
+int b[countof a];
+
+#define str(x) #x
+#define xstr(x) str(x)
+
+int
+main (void)
+{
+  assert (strcmp (xstr(countof), "_Countof") == 0);
+}
-- 
2.49.0


^ permalink raw reply	[flat|nested] 318+ messages in thread

* [PATCH v23 3/3] c: Add -Wpedantic diagnostic for _Countof
  2025-05-21  0:17   ` [PATCH v23 " Alejandro Colomar
  2025-05-21  0:18     ` [PATCH v23 1/3] c: Add _Countof operator Alejandro Colomar
  2025-05-21  0:18     ` [PATCH v23 2/3] c: Add <stdcountof.h> Alejandro Colomar
@ 2025-05-21  0:18     ` Alejandro Colomar
  2025-05-21  8:56     ` [PATCH v23 0/3] c: Add _Countof and <stdcountof.h> Alejandro Colomar
  3 siblings, 0 replies; 318+ messages in thread
From: Alejandro Colomar @ 2025-05-21  0:18 UTC (permalink / raw)
  To: gcc-patches
  Cc: Alejandro Colomar, Martin Uecker, JeanHeyd Meneide, Joseph Myers,
	Jakub Jelinek

It has been standardized in C2y.

gcc/c/ChangeLog:

	* c-parser.cc (c_parser_sizeof_or_countof_expression):
	Add -Wpedantic diagnostic for _Countof in <= C23 mode.

gcc/testsuite/ChangeLog:

	* gcc.dg/countof-compat.c:
	Test _Countof diagnostics with -Wc23-c2y-compat on C2y.
	* gcc.dg/countof-no-compat.c:
	Test _Countof diagnostics with -Wno-c23-c2y-compat on C23.
	* gcc.dg/countof-pedantic.c:
	Test _Countof diagnostics with -pedantic on C23.
	* gcc.dg/countof-pedantic-errors.c:
	Test _Countof diagnostics with -pedantic-errors on C23.

Signed-off-by: Alejandro Colomar <alx@kernel.org>
---
 gcc/c/c-parser.cc                              | 4 ++++
 gcc/testsuite/gcc.dg/countof-compat.c          | 8 ++++++++
 gcc/testsuite/gcc.dg/countof-no-compat.c       | 5 +++++
 gcc/testsuite/gcc.dg/countof-pedantic-errors.c | 8 ++++++++
 gcc/testsuite/gcc.dg/countof-pedantic.c        | 8 ++++++++
 5 files changed, 33 insertions(+)
 create mode 100644 gcc/testsuite/gcc.dg/countof-compat.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-no-compat.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-pedantic-errors.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-pedantic.c

diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
index 87700339394b..d2193ad2f34f 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -10637,6 +10637,10 @@ c_parser_sizeof_or_countof_expression (c_parser *parser, enum rid rid)
 
   start = c_parser_peek_token (parser)->location;
 
+  if (rid == RID_COUNTOF)
+    pedwarn_c23 (start, OPT_Wpedantic,
+		 "ISO C does not support %qs before C23", op_name);
+
   c_parser_consume_token (parser);
   c_inhibit_evaluation_warnings++;
   if (rid == RID_COUNTOF)
diff --git a/gcc/testsuite/gcc.dg/countof-compat.c b/gcc/testsuite/gcc.dg/countof-compat.c
new file mode 100644
index 000000000000..ab5b4ae6219c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/countof-compat.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-std=c2y -pedantic-errors -Wc23-c2y-compat" } */
+
+#include <stdcountof.h>
+
+int a[1];
+int b[countof(a)];
+int c[_Countof(a)];  /* { dg-warning "ISO C does not support" } */
diff --git a/gcc/testsuite/gcc.dg/countof-no-compat.c b/gcc/testsuite/gcc.dg/countof-no-compat.c
new file mode 100644
index 000000000000..4a244cf222f6
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/countof-no-compat.c
@@ -0,0 +1,5 @@
+/* { dg-do compile } */
+/* { dg-options "-std=c23 -pedantic-errors -Wno-c23-c2y-compat" } */
+
+int a[1];
+int b[_Countof(a)];
diff --git a/gcc/testsuite/gcc.dg/countof-pedantic-errors.c b/gcc/testsuite/gcc.dg/countof-pedantic-errors.c
new file mode 100644
index 000000000000..5d5bedbe1f7e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/countof-pedantic-errors.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-std=c23 -pedantic-errors" } */
+
+#include <stdcountof.h>
+
+int a[1];
+int b[countof(a)];
+int c[_Countof(a)];  /* { dg-error "ISO C does not support" } */
diff --git a/gcc/testsuite/gcc.dg/countof-pedantic.c b/gcc/testsuite/gcc.dg/countof-pedantic.c
new file mode 100644
index 000000000000..408dc6f93667
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/countof-pedantic.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-std=c23 -pedantic" } */
+
+#include <stdcountof.h>
+
+int a[1];
+int b[countof(a)];
+int c[_Countof(a)];  /* { dg-warning "ISO C does not support" } */
-- 
2.49.0


^ permalink raw reply	[flat|nested] 318+ messages in thread

* Re: [PATCH v23 0/3] c: Add _Countof and <stdcountof.h>
  2025-05-21  0:17   ` [PATCH v23 " Alejandro Colomar
                       ` (2 preceding siblings ...)
  2025-05-21  0:18     ` [PATCH v23 3/3] c: Add -Wpedantic diagnostic for _Countof Alejandro Colomar
@ 2025-05-21  8:56     ` Alejandro Colomar
  3 siblings, 0 replies; 318+ messages in thread
From: Alejandro Colomar @ 2025-05-21  8:56 UTC (permalink / raw)
  To: gcc-patches; +Cc: Martin Uecker, JeanHeyd Meneide, Joseph Myers, Jakub Jelinek

[-- Attachment #1: Type: text/plain, Size: 10930 bytes --]

On Wed, May 21, 2025 at 02:17:58AM +0200, Alejandro Colomar wrote:
> Hi!
> 
> Here's another revision of this patch set.
> 
> v23 changes:
> 
> -  More specific change logs.
> -  #define assert() instead of #include'ing <assert.h>.
> 
> `make check` says all's good.  I haven't diffed against master this
> time, because that's slow as hell, and the changes are minimal.  I've
> only ran `make check -j24` once at the tip, and all the countof tests
> pass.

BTW, I didn't paste the test results.  Here they are:

	$ cat ./gcc/testsuite/gcc/gcc.sum | grep countof
	PASS: gcc.dg/countof-compat.c  (test for warnings, line 8)
	PASS: gcc.dg/countof-compat.c (test for excess errors)
	PASS: gcc.dg/countof-compile.c  (test for errors, line 114)
	PASS: gcc.dg/countof-compile.c  (test for errors, line 123)
	PASS: gcc.dg/countof-compile.c  (test for errors, line 23)
	PASS: gcc.dg/countof-compile.c  (test for errors, line 27)
	PASS: gcc.dg/countof-compile.c  (test for errors, line 38)
	PASS: gcc.dg/countof-compile.c  (test for errors, line 46)
	PASS: gcc.dg/countof-compile.c  (test for errors, line 64)
	PASS: gcc.dg/countof-compile.c  (test for errors, line 67)
	PASS: gcc.dg/countof-compile.c  (test for errors, line 70)
	PASS: gcc.dg/countof-compile.c  (test for errors, line 82)
	PASS: gcc.dg/countof-compile.c  (test for errors, line 83)
	PASS: gcc.dg/countof-compile.c  (test for errors, line 84)
	PASS: gcc.dg/countof-compile.c  (test for errors, line 85)
	PASS: gcc.dg/countof-compile.c  (test for errors, line 86)
	PASS: gcc.dg/countof-compile.c  (test for errors, line 87)
	PASS: gcc.dg/countof-compile.c  (test for errors, line 88)
	PASS: gcc.dg/countof-compile.c  (test for errors, line 89)
	PASS: gcc.dg/countof-compile.c  (test for errors, line 90)
	PASS: gcc.dg/countof-compile.c  (test for errors, line 94)
	PASS: gcc.dg/countof-compile.c (test for excess errors)
	PASS: gcc.dg/countof-no-compat.c (test for excess errors)
	PASS: gcc.dg/countof-pedantic-errors.c  (test for errors, line 8)
	PASS: gcc.dg/countof-pedantic-errors.c (test for excess errors)
	PASS: gcc.dg/countof-pedantic.c  (test for warnings, line 8)
	PASS: gcc.dg/countof-pedantic.c (test for excess errors)
	PASS: gcc.dg/countof-stdcountof.c (test for excess errors)
	PASS: gcc.dg/countof-stdcountof.c execution test
	PASS: gcc.dg/countof-vla.c (test for excess errors)
	PASS: gcc.dg/countof-vmt.c (test for excess errors)
	PASS: gcc.dg/countof-vmt.c execution test
	PASS: gcc.dg/countof-zero-compile.c (test for excess errors)
	PASS: gcc.dg/countof-zero.c (test for excess errors)
	PASS: gcc.dg/countof-zero.c execution test
	PASS: gcc.dg/countof.c (test for excess errors)
	PASS: gcc.dg/countof.c execution test

> 
> 
> Have a lovely night!
> Alex
> 
> 
> Alejandro Colomar (3):
>   c: Add _Countof operator
>   c: Add <stdcountof.h>
>   c: Add -Wpedantic diagnostic for _Countof
> 
>  gcc/Makefile.in                               |   1 +
>  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                               |  22 +++-
>  gcc/c/c-parser.cc                             |  63 +++++++--
>  gcc/c/c-tree.h                                |   4 +
>  gcc/c/c-typeck.cc                             | 115 +++++++++++++++-
>  gcc/doc/extend.texi                           |  30 +++++
>  gcc/ginclude/stdcountof.h                     |  31 +++++
>  gcc/testsuite/gcc.dg/countof-compat.c         |   8 ++
>  gcc/testsuite/gcc.dg/countof-compile.c        | 124 ++++++++++++++++++
>  gcc/testsuite/gcc.dg/countof-no-compat.c      |   5 +
>  .../gcc.dg/countof-pedantic-errors.c          |   8 ++
>  gcc/testsuite/gcc.dg/countof-pedantic.c       |   8 ++
>  gcc/testsuite/gcc.dg/countof-stdcountof.c     |  24 ++++
>  gcc/testsuite/gcc.dg/countof-vla.c            |  35 +++++
>  gcc/testsuite/gcc.dg/countof-vmt.c            |  20 +++
>  gcc/testsuite/gcc.dg/countof-zero-compile.c   |  38 ++++++
>  gcc/testsuite/gcc.dg/countof-zero.c           |  31 +++++
>  gcc/testsuite/gcc.dg/countof.c                | 120 +++++++++++++++++
>  21 files changed, 694 insertions(+), 24 deletions(-)
>  create mode 100644 gcc/ginclude/stdcountof.h
>  create mode 100644 gcc/testsuite/gcc.dg/countof-compat.c
>  create mode 100644 gcc/testsuite/gcc.dg/countof-compile.c
>  create mode 100644 gcc/testsuite/gcc.dg/countof-no-compat.c
>  create mode 100644 gcc/testsuite/gcc.dg/countof-pedantic-errors.c
>  create mode 100644 gcc/testsuite/gcc.dg/countof-pedantic.c
>  create mode 100644 gcc/testsuite/gcc.dg/countof-stdcountof.c
>  create mode 100644 gcc/testsuite/gcc.dg/countof-vla.c
>  create mode 100644 gcc/testsuite/gcc.dg/countof-vmt.c
>  create mode 100644 gcc/testsuite/gcc.dg/countof-zero-compile.c
>  create mode 100644 gcc/testsuite/gcc.dg/countof-zero.c
>  create mode 100644 gcc/testsuite/gcc.dg/countof.c
> 
> Range-diff against v22:
> 1:  1c983c3baa7f ! 1:  5040a7d25a96 c: Add _Countof operator
>     @@ Commit message
>      
>          gcc/c-family/ChangeLog:
>      
>     -            * c-common.h
>     -            * c-common.def
>     -            * c-common.cc (c_countof_type): Add _Countof operator.
>     +            * c-common.h: Add RID_COUNTOF.
>     +            (c_countof_type): New function prototype.
>     +            * c-common.def (COUNTOF_EXPR): New tree.
>     +            * c-common.cc
>     +            (c_common_reswords): Add RID_COUNTOF entry.
>     +            (c_countof_type): New function.
>      
>          gcc/c/ChangeLog:
>      
>                  * c-tree.h
>     -            (c_expr_countof_expr, c_expr_countof_type)
>     +            (in_countof): Add global variable declaration.
>     +            (c_expr_countof_expr): Add function prototype.
>     +            (c_expr_countof_type): Add function prototype.
>                  * c-decl.cc
>     -            (start_struct, finish_struct)
>     -            (start_enum, finish_enum)
>     +            (start_struct, finish_struct): Add support for _Countof.
>     +            (start_enum, finish_enum): Add support for _Countof.
>                  * c-parser.cc
>     -            (c_parser_sizeof_expression)
>     -            (c_parser_countof_expression)
>     -            (c_parser_sizeof_or_countof_expression)
>     -            (c_parser_unary_expression)
>     +            (c_parser_sizeof_expression): New macro.
>     +            (c_parser_countof_expression): New macro.
>     +            (c_parser_sizeof_or_countof_expression):
>     +            Rename function and add support for _Countof.
>     +            (c_parser_unary_expression): Add RID_COUNTOF entry.
>                  * c-typeck.cc
>     -            (build_external_ref)
>     -            (record_maybe_used_decl)
>     -            (pop_maybe_used)
>     -            (is_top_array_vla)
>     -            (c_expr_countof_expr, c_expr_countof_type):
>     +            (in_countof): Add global variable.
>     +            (build_external_ref): Add support for _Countof.
>     +            (record_maybe_used_decl): Add support for _Countof.
>     +            (pop_maybe_used): Add support for _Countof.
>     +            (is_top_array_vla): New function.
>     +            (c_expr_countof_expr, c_expr_countof_type): New functions.
>                  Add _Countof operator.
>      
>          gcc/testsuite/ChangeLog:
>      
>     -            * gcc.dg/countof-compile.c
>     -            * gcc.dg/countof-vla.c
>     -            * gcc.dg/countof-vmt.c
>     -            * gcc.dg/countof-zero-compile.c
>     -            * gcc.dg/countof-zero.c
>     -            * gcc.dg/countof.c: Add tests for _Countof operator.
>     +            * gcc.dg/countof-compile.c: Compile-time tests for _Countof.
>     +            * gcc.dg/countof-vla.c: Tests for _Countof with VLAs.
>     +            * gcc.dg/countof-vmt.c: Tests for _Countof with other VMTs.
>     +            * gcc.dg/countof-zero-compile.c:
>     +            Compile-time tests for _Countof with zero-sized arrays.
>     +            * gcc.dg/countof-zero.c:
>     +            Tests for _Countof with zero-sized arrays.
>     +            * gcc.dg/countof.c: Tests for _Countof.
>      
>          Suggested-by: Xavier Del Campo Romero <xavi.dcr@tutanota.com>
>          Co-authored-by: Martin Uecker <uecker@tugraz.at>
>     @@ gcc/testsuite/gcc.dg/countof-vmt.c (new)
>      +/* { dg-do run } */
>      +/* { dg-options "-std=c2y" } */
>      +
>     -+#undef NDEBUG
>     -+#include <assert.h>
>     ++#define assert(e)  ((e) ? (void) 0 : __builtin_abort ())
>      +
>      +void
>      +inner_vla_noeval (void)
>     @@ gcc/testsuite/gcc.dg/countof-zero.c (new)
>      +/* { dg-do run } */
>      +/* { dg-options "-std=c2y" } */
>      +
>     -+#undef NDEBUG
>     -+#include <assert.h>
>     ++#define assert(e)  ((e) ? (void) 0 : __builtin_abort ())
>      +
>      +void
>      +vla (void)
>     @@ gcc/testsuite/gcc.dg/countof.c (new)
>      +/* { dg-do run } */
>      +/* { dg-options "-std=c2y -pedantic-errors" } */
>      +
>     -+#undef NDEBUG
>     -+#include <assert.h>
>     ++#define assert(e)  ((e) ? (void) 0 : __builtin_abort ())
>      +
>      +void
>      +array (void)
> 2:  418f81175e78 ! 2:  a560cf1ae23b c: Add <stdcountof.h>
>     @@ gcc/testsuite/gcc.dg/countof-stdcountof.c (new)
>      +
>      +#include <stdcountof.h>
>      +
>     -+#undef NDEBUG
>     -+#include <assert.h>
>     ++#define assert(e)  ((e) ? (void) 0 : __builtin_abort ())
>      +
>      +extern int strcmp (const char *, const char *);
>      +
> 3:  c44ef4a2c751 ! 3:  b1974a4507bc c: Add -Wpedantic diagnostic for _Countof
>     @@ Commit message
>      
>          gcc/testsuite/ChangeLog:
>      
>     -            * gcc.dg/countof-compat.c
>     -            * gcc.dg/countof-no-compat.c
>     -            * gcc.dg/countof-pedantic.c
>     +            * gcc.dg/countof-compat.c:
>     +            Test _Countof diagnostics with -Wc23-c2y-compat on C2y.
>     +            * gcc.dg/countof-no-compat.c:
>     +            Test _Countof diagnostics with -Wno-c23-c2y-compat on C23.
>     +            * gcc.dg/countof-pedantic.c:
>     +            Test _Countof diagnostics with -pedantic on C23.
>                  * gcc.dg/countof-pedantic-errors.c:
>     -            Test pedantic diagnostics for _Countof.
>     +            Test _Countof diagnostics with -pedantic-errors on C23.
>      
>          Signed-off-by: Alejandro Colomar <alx@kernel.org>
>      
> 
> base-commit: 90c6ccebd762ae920690fce20cd3f2b8e24357a7
> -- 
> 2.49.0
> 

-- 
<https://www.alejandro-colomar.es/>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 318+ messages in thread

* Re: [PATCH v23 1/3] c: Add _Countof operator
  2025-05-21  0:18     ` [PATCH v23 1/3] c: Add _Countof operator Alejandro Colomar
@ 2025-05-21 16:26       ` Joseph Myers
  2025-05-21 17:01         ` Alejandro Colomar
  0 siblings, 1 reply; 318+ messages in thread
From: Joseph Myers @ 2025-05-21 16:26 UTC (permalink / raw)
  To: Alejandro Colomar
  Cc: gcc-patches, Martin Uecker, JeanHeyd Meneide, Jakub Jelinek,
	Xavier Del Campo Romero, James K. Lowden

On Wed, 21 May 2025, Alejandro Colomar wrote:

> @@ -10572,6 +10583,8 @@ c_parser_unary_expression (c_parser *parser)
>      case CPP_KEYWORD:
>        switch (c_parser_peek_token (parser)->keyword)
>  	{
> +	case RID_COUNTOF:
> +	  return c_parser_countof_expression (parser);
>  	case RID_SIZEOF:
>  	  return c_parser_sizeof_expression (parser);
>  	case RID_ALIGNOF:

The comment above this function should be updated to include the _Countof 
syntax for C2Y.

> diff --git a/gcc/testsuite/gcc.dg/countof-vmt.c b/gcc/testsuite/gcc.dg/countof-vmt.c
> new file mode 100644
> index 000000000000..cf4bfd1aa74e
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/countof-vmt.c
> @@ -0,0 +1,20 @@
> +/* { dg-do run } */
> +/* { dg-options "-std=c2y" } */

I think -std=gnu2y is more appropriate for tests such as this that are 
concerned with GNU extensions (VLAs in structures, in this case).

> diff --git a/gcc/testsuite/gcc.dg/countof-zero-compile.c b/gcc/testsuite/gcc.dg/countof-zero-compile.c
> new file mode 100644
> index 000000000000..3dc60ce293bd
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/countof-zero-compile.c
> @@ -0,0 +1,38 @@
> +/* { dg-do compile } */
> +/* { dg-options "-std=c2y" } */

Likewise for this one using the extension of arrays with zero elements.

> diff --git a/gcc/testsuite/gcc.dg/countof-zero.c b/gcc/testsuite/gcc.dg/countof-zero.c
> new file mode 100644
> index 000000000000..678a08148a5c
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/countof-zero.c
> @@ -0,0 +1,31 @@
> +/* { dg-do run } */
> +/* { dg-options "-std=c2y" } */

Likewise for this one as well.

-- 
Joseph S. Myers
josmyers@redhat.com


^ permalink raw reply	[flat|nested] 318+ messages in thread

* Re: [PATCH v23 1/3] c: Add _Countof operator
  2025-05-21 16:26       ` Joseph Myers
@ 2025-05-21 17:01         ` Alejandro Colomar
  2025-05-21 17:48           ` Joseph Myers
  0 siblings, 1 reply; 318+ messages in thread
From: Alejandro Colomar @ 2025-05-21 17:01 UTC (permalink / raw)
  To: Joseph Myers
  Cc: gcc-patches, Martin Uecker, JeanHeyd Meneide, Jakub Jelinek,
	Xavier Del Campo Romero, James K. Lowden

[-- Attachment #1: Type: text/plain, Size: 2925 bytes --]

Hi Joseph,

On Wed, May 21, 2025 at 04:26:46PM +0000, Joseph Myers wrote:
> On Wed, 21 May 2025, Alejandro Colomar wrote:
> 
> > @@ -10572,6 +10583,8 @@ c_parser_unary_expression (c_parser *parser)
> >      case CPP_KEYWORD:
> >        switch (c_parser_peek_token (parser)->keyword)
> >  	{
> > +	case RID_COUNTOF:
> > +	  return c_parser_countof_expression (parser);
> >  	case RID_SIZEOF:
> >  	  return c_parser_sizeof_expression (parser);
> >  	case RID_ALIGNOF:
> 
> The comment above this function should be updated to include the _Countof 
> syntax for C2Y.

Makes sense.  I'm unsure where exactly I should put it.  Is this okay?

	diff --git i/gcc/c/c-parser.cc w/gcc/c/c-parser.cc
	index 87700339394b..08350a216dd8 100644
	--- i/gcc/c/c-parser.cc
	+++ w/gcc/c/c-parser.cc
	@@ -10456,20 +10456,22 @@ c_parser_cast_expression (c_parser *parser, struct c_expr *after)
	     return c_parser_unary_expression (parser);
	 }
	 
	 /* Parse an unary expression (C90 6.3.3, C99 6.5.3, C11 6.5.3).
	 
	    unary-expression:
	      postfix-expression
	      ++ unary-expression
	      -- unary-expression
	      unary-operator cast-expression
	+     _Countof unary-expression
	+     _Countof ( type-name )
	      sizeof unary-expression
	      sizeof ( type-name )
	 
	    unary-operator: one of
	      & * + - ~ !
	 
	    GNU extensions:
	 
	    unary-expression:
	      __alignof__ unary-expression

> > diff --git a/gcc/testsuite/gcc.dg/countof-vmt.c b/gcc/testsuite/gcc.dg/countof-vmt.c
> > new file mode 100644
> > index 000000000000..cf4bfd1aa74e
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.dg/countof-vmt.c
> > @@ -0,0 +1,20 @@
> > +/* { dg-do run } */
> > +/* { dg-options "-std=c2y" } */
> 
> I think -std=gnu2y is more appropriate for tests such as this that are 
> concerned with GNU extensions (VLAs in structures, in this case).

Makes sense (and likewise for the below).  When you confirm the above,
I'll send v24 your way.  Thanks for the review!


Have a lovely day!
Alex

> 
> > diff --git a/gcc/testsuite/gcc.dg/countof-zero-compile.c b/gcc/testsuite/gcc.dg/countof-zero-compile.c
> > new file mode 100644
> > index 000000000000..3dc60ce293bd
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.dg/countof-zero-compile.c
> > @@ -0,0 +1,38 @@
> > +/* { dg-do compile } */
> > +/* { dg-options "-std=c2y" } */
> 
> Likewise for this one using the extension of arrays with zero elements.
> 
> > diff --git a/gcc/testsuite/gcc.dg/countof-zero.c b/gcc/testsuite/gcc.dg/countof-zero.c
> > new file mode 100644
> > index 000000000000..678a08148a5c
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.dg/countof-zero.c
> > @@ -0,0 +1,31 @@
> > +/* { dg-do run } */
> > +/* { dg-options "-std=c2y" } */
> 
> Likewise for this one as well.
> 
> -- 
> 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] 318+ messages in thread

* Re: [PATCH v23 1/3] c: Add _Countof operator
  2025-05-21 17:01         ` Alejandro Colomar
@ 2025-05-21 17:48           ` Joseph Myers
  0 siblings, 0 replies; 318+ messages in thread
From: Joseph Myers @ 2025-05-21 17:48 UTC (permalink / raw)
  To: Alejandro Colomar
  Cc: gcc-patches, Martin Uecker, JeanHeyd Meneide, Jakub Jelinek,
	Xavier Del Campo Romero, James K. Lowden

On Wed, 21 May 2025, Alejandro Colomar wrote:

> Makes sense.  I'm unsure where exactly I should put it.  Is this okay?
> 
> 	diff --git i/gcc/c/c-parser.cc w/gcc/c/c-parser.cc
> 	index 87700339394b..08350a216dd8 100644
> 	--- i/gcc/c/c-parser.cc
> 	+++ w/gcc/c/c-parser.cc
> 	@@ -10456,20 +10456,22 @@ c_parser_cast_expression (c_parser *parser, struct c_expr *after)
> 	     return c_parser_unary_expression (parser);
> 	 }
> 	 
> 	 /* Parse an unary expression (C90 6.3.3, C99 6.5.3, C11 6.5.3).
> 	 
> 	    unary-expression:
> 	      postfix-expression
> 	      ++ unary-expression
> 	      -- unary-expression
> 	      unary-operator cast-expression
> 	+     _Countof unary-expression
> 	+     _Countof ( type-name )

With some kind of remark to indicate it's new in C2Y, yes.  E.g. 
c_parser_generic_selection's comment says "(The use of a type-name is new 
in C2Y.)".

-- 
Joseph S. Myers
josmyers@redhat.com


^ permalink raw reply	[flat|nested] 318+ messages in thread

* [PATCH v24 0/3] c: Add _Countof and <stdcountof.h>
  2024-07-28 14:15 ` [RFC v1 0/2] c: Add _Lengthof operator Alejandro Colomar
                     ` (26 preceding siblings ...)
  2025-05-21  0:17   ` [PATCH v23 " Alejandro Colomar
@ 2025-05-21 21:01   ` Alejandro Colomar
  2025-05-21 21:01     ` [PATCH v24 1/3] c: Add _Countof operator Alejandro Colomar
                       ` (2 more replies)
  2025-05-21 23:15   ` [PATCH v25 0/3] c: Add _Countof and <stdcountof.h> Alejandro Colomar
  28 siblings, 3 replies; 318+ messages in thread
From: Alejandro Colomar @ 2025-05-21 21:01 UTC (permalink / raw)
  To: gcc-patches
  Cc: Alejandro Colomar, Martin Uecker, JeanHeyd Meneide, Joseph Myers,
	Jakub Jelinek

Hi!

Here's v24.  Changes compared to v23 (see range-diff below):

-  Use a GNU dialect in tests that use GNU extensions.
-  Add comment about the syntax of _Countof.

Tests still pass:

	$ grep countof ./gcc/testsuite/gcc/gcc.sum
	PASS: gcc.dg/countof-compat.c  (test for warnings, line 8)
	PASS: gcc.dg/countof-compat.c (test for excess errors)
	PASS: gcc.dg/countof-compile.c  (test for errors, line 114)
	PASS: gcc.dg/countof-compile.c  (test for errors, line 123)
	PASS: gcc.dg/countof-compile.c  (test for errors, line 23)
	PASS: gcc.dg/countof-compile.c  (test for errors, line 27)
	PASS: gcc.dg/countof-compile.c  (test for errors, line 38)
	PASS: gcc.dg/countof-compile.c  (test for errors, line 46)
	PASS: gcc.dg/countof-compile.c  (test for errors, line 64)
	PASS: gcc.dg/countof-compile.c  (test for errors, line 67)
	PASS: gcc.dg/countof-compile.c  (test for errors, line 70)
	PASS: gcc.dg/countof-compile.c  (test for errors, line 82)
	PASS: gcc.dg/countof-compile.c  (test for errors, line 83)
	PASS: gcc.dg/countof-compile.c  (test for errors, line 84)
	PASS: gcc.dg/countof-compile.c  (test for errors, line 85)
	PASS: gcc.dg/countof-compile.c  (test for errors, line 86)
	PASS: gcc.dg/countof-compile.c  (test for errors, line 87)
	PASS: gcc.dg/countof-compile.c  (test for errors, line 88)
	PASS: gcc.dg/countof-compile.c  (test for errors, line 89)
	PASS: gcc.dg/countof-compile.c  (test for errors, line 90)
	PASS: gcc.dg/countof-compile.c  (test for errors, line 94)
	PASS: gcc.dg/countof-compile.c (test for excess errors)
	PASS: gcc.dg/countof-no-compat.c (test for excess errors)
	PASS: gcc.dg/countof-pedantic-errors.c  (test for errors, line 8)
	PASS: gcc.dg/countof-pedantic-errors.c (test for excess errors)
	PASS: gcc.dg/countof-pedantic.c  (test for warnings, line 8)
	PASS: gcc.dg/countof-pedantic.c (test for excess errors)
	PASS: gcc.dg/countof-stdcountof.c (test for excess errors)
	PASS: gcc.dg/countof-stdcountof.c execution test
	PASS: gcc.dg/countof-vla.c (test for excess errors)
	PASS: gcc.dg/countof-vmt.c (test for excess errors)
	PASS: gcc.dg/countof-vmt.c execution test
	PASS: gcc.dg/countof-zero-compile.c (test for excess errors)
	PASS: gcc.dg/countof-zero.c (test for excess errors)
	PASS: gcc.dg/countof-zero.c execution test
	PASS: gcc.dg/countof.c (test for excess errors)
	PASS: gcc.dg/countof.c execution test


Have a lovely day!
Alex


Alejandro Colomar (3):
  c: Add _Countof operator
  c: Add <stdcountof.h>
  c: Add -Wpedantic diagnostic for _Countof

 gcc/Makefile.in                               |   1 +
 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                               |  22 +++-
 gcc/c/c-parser.cc                             |  67 ++++++++--
 gcc/c/c-tree.h                                |   4 +
 gcc/c/c-typeck.cc                             | 115 +++++++++++++++-
 gcc/doc/extend.texi                           |  30 +++++
 gcc/ginclude/stdcountof.h                     |  31 +++++
 gcc/testsuite/gcc.dg/countof-compat.c         |   8 ++
 gcc/testsuite/gcc.dg/countof-compile.c        | 124 ++++++++++++++++++
 gcc/testsuite/gcc.dg/countof-no-compat.c      |   5 +
 .../gcc.dg/countof-pedantic-errors.c          |   8 ++
 gcc/testsuite/gcc.dg/countof-pedantic.c       |   8 ++
 gcc/testsuite/gcc.dg/countof-stdcountof.c     |  24 ++++
 gcc/testsuite/gcc.dg/countof-vla.c            |  35 +++++
 gcc/testsuite/gcc.dg/countof-vmt.c            |  20 +++
 gcc/testsuite/gcc.dg/countof-zero-compile.c   |  38 ++++++
 gcc/testsuite/gcc.dg/countof-zero.c           |  31 +++++
 gcc/testsuite/gcc.dg/countof.c                | 120 +++++++++++++++++
 21 files changed, 698 insertions(+), 24 deletions(-)
 create mode 100644 gcc/ginclude/stdcountof.h
 create mode 100644 gcc/testsuite/gcc.dg/countof-compat.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-compile.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-no-compat.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-pedantic-errors.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-pedantic.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-stdcountof.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-vla.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-vmt.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-zero-compile.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-zero.c
 create mode 100644 gcc/testsuite/gcc.dg/countof.c

Range-diff against v23:
1:  5040a7d25a96 ! 1:  1ac81ab0d3dc c: Add _Countof operator
    @@ gcc/c/c-parser.cc: static struct c_expr c_parser_binary_expression (c_parser *,
      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 *,
    +@@ gcc/c/c-parser.cc: c_parser_cast_expression (c_parser *parser, struct c_expr *after)
    +      ++ unary-expression
    +      -- unary-expression
    +      unary-operator cast-expression
    ++     _Countof unary-expression
    ++     _Countof ( type-name )
    +      sizeof unary-expression
    +      sizeof ( type-name )
    + 
    ++   (_Countof is new in C2y.)
    ++
    +    unary-operator: one of
    +      & * + - ~ !
    + 
     @@ gcc/c/c-parser.cc: c_parser_unary_expression (c_parser *parser)
          case CPP_KEYWORD:
            switch (c_parser_peek_token (parser)->keyword)
    @@ gcc/testsuite/gcc.dg/countof-vla.c (new)
      ## gcc/testsuite/gcc.dg/countof-vmt.c (new) ##
     @@
     +/* { dg-do run } */
    -+/* { dg-options "-std=c2y" } */
    ++/* { dg-options "-std=gnu2y" } */
     +
     +#define assert(e)  ((e) ? (void) 0 : __builtin_abort ())
     +
    @@ gcc/testsuite/gcc.dg/countof-vmt.c (new)
      ## gcc/testsuite/gcc.dg/countof-zero-compile.c (new) ##
     @@
     +/* { dg-do compile } */
    -+/* { dg-options "-std=c2y" } */
    ++/* { dg-options "-std=gnu2y" } */
     +
     +static int z[0];
     +static int y[_Countof (z)];
    @@ gcc/testsuite/gcc.dg/countof-zero-compile.c (new)
      ## gcc/testsuite/gcc.dg/countof-zero.c (new) ##
     @@
     +/* { dg-do run } */
    -+/* { dg-options "-std=c2y" } */
    ++/* { dg-options "-std=gnu2y" } */
     +
     +#define assert(e)  ((e) ? (void) 0 : __builtin_abort ())
     +
2:  a560cf1ae23b = 2:  b9e8bed2de2b c: Add <stdcountof.h>
3:  b1974a4507bc = 3:  264c87d60157 c: Add -Wpedantic diagnostic for _Countof

base-commit: 90c6ccebd762ae920690fce20cd3f2b8e24357a7
-- 
2.49.0


^ permalink raw reply	[flat|nested] 318+ messages in thread

* [PATCH v24 1/3] c: Add _Countof operator
  2025-05-21 21:01   ` [PATCH v24 " Alejandro Colomar
@ 2025-05-21 21:01     ` Alejandro Colomar
  2025-05-21 21:12       ` Jakub Jelinek
  2025-05-21 21:01     ` [PATCH v24 2/3] c: Add <stdcountof.h> Alejandro Colomar
  2025-05-21 21:01     ` [PATCH v24 3/3] c: Add -Wpedantic diagnostic for _Countof Alejandro Colomar
  2 siblings, 1 reply; 318+ messages in thread
From: Alejandro Colomar @ 2025-05-21 21:01 UTC (permalink / raw)
  To: gcc-patches
  Cc: Alejandro Colomar, Martin Uecker, JeanHeyd Meneide, Joseph Myers,
	Jakub Jelinek, Xavier Del Campo Romero, James K. Lowden

This operator is similar to sizeof but can only be applied to an array,
and returns its number of elements.

FUTURE DIRECTIONS:

-  We should make it work with array parameters to functions,
   and somehow magically return the number of elements of the array,
   regardless of it being really a pointer.

Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3550.pdf>
Link: <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117025>
Link: <https://inbox.sourceware.org/gcc/M8S4oQy--3-2@tutanota.com/T/>
Link: <https://inbox.sourceware.org/gcc-patches/20240728141547.302478-1-alx@kernel.org/T/#t>
Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3313.pdf>
Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3325.pdf>
Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3369.pdf>
Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3469.htm>
Link: <https://github.com/llvm/llvm-project/issues/102836>
Link: <https://thephd.dev/the-big-array-size-survey-for-c>
Link: <https://thephd.dev/the-big-array-size-survey-for-c-results>
Link: <https://stackoverflow.com/questions/37538/#57537491>

gcc/ChangeLog:

	* doc/extend.texi: Document _Countof operator.

gcc/c-family/ChangeLog:

	* c-common.h: Add RID_COUNTOF.
	(c_countof_type): New function prototype.
	* c-common.def (COUNTOF_EXPR): New tree.
	* c-common.cc
	(c_common_reswords): Add RID_COUNTOF entry.
	(c_countof_type): New function.

gcc/c/ChangeLog:

	* c-tree.h
	(in_countof): Add global variable declaration.
	(c_expr_countof_expr): Add function prototype.
	(c_expr_countof_type): Add function prototype.
	* c-decl.cc
	(start_struct, finish_struct): Add support for _Countof.
	(start_enum, finish_enum): Add support for _Countof.
	* c-parser.cc
	(c_parser_sizeof_expression): New macro.
	(c_parser_countof_expression): New macro.
	(c_parser_sizeof_or_countof_expression):
	Rename function and add support for _Countof.
	(c_parser_unary_expression): Add RID_COUNTOF entry.
	* c-typeck.cc
	(in_countof): Add global variable.
	(build_external_ref): Add support for _Countof.
	(record_maybe_used_decl): Add support for _Countof.
	(pop_maybe_used): Add support for _Countof.
	(is_top_array_vla): New function.
	(c_expr_countof_expr, c_expr_countof_type): New functions.
	Add _Countof operator.

gcc/testsuite/ChangeLog:

	* gcc.dg/countof-compile.c: Compile-time tests for _Countof.
	* gcc.dg/countof-vla.c: Tests for _Countof with VLAs.
	* gcc.dg/countof-vmt.c: Tests for _Countof with other VMTs.
	* gcc.dg/countof-zero-compile.c:
	Compile-time tests for _Countof with zero-sized arrays.
	* gcc.dg/countof-zero.c:
	Tests for _Countof with zero-sized arrays.
	* gcc.dg/countof.c: Tests for _Countof.

Suggested-by: Xavier Del Campo Romero <xavi.dcr@tutanota.com>
Co-authored-by: Martin Uecker <uecker@tugraz.at>
Acked-by: "James K. Lowden" <jklowden@schemamania.org>
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                             |  22 +++-
 gcc/c/c-parser.cc                           |  63 +++++++---
 gcc/c/c-tree.h                              |   4 +
 gcc/c/c-typeck.cc                           | 115 +++++++++++++++++-
 gcc/doc/extend.texi                         |  30 +++++
 gcc/testsuite/gcc.dg/countof-compile.c      | 124 ++++++++++++++++++++
 gcc/testsuite/gcc.dg/countof-vla.c          |  35 ++++++
 gcc/testsuite/gcc.dg/countof-vmt.c          |  20 ++++
 gcc/testsuite/gcc.dg/countof-zero-compile.c |  38 ++++++
 gcc/testsuite/gcc.dg/countof-zero.c         |  31 +++++
 gcc/testsuite/gcc.dg/countof.c              | 120 +++++++++++++++++++
 14 files changed, 609 insertions(+), 24 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/countof-compile.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-vla.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-vmt.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-zero-compile.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-zero.c
 create mode 100644 gcc/testsuite/gcc.dg/countof.c

diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
index 587d76461e9e..f71cb2652d5a 100644
--- a/gcc/c-family/c-common.cc
+++ b/gcc/c-family/c-common.cc
@@ -394,6 +394,7 @@ const struct c_common_resword c_common_reswords[] =
 {
   { "_Alignas",		RID_ALIGNAS,   D_CONLY },
   { "_Alignof",		RID_ALIGNOF,   D_CONLY },
+  { "_Countof",		RID_COUNTOF,   D_CONLY },
   { "_Atomic",		RID_ATOMIC,    D_CONLY },
   { "_BitInt",		RID_BITINT,    D_CONLY },
   { "_Bool",		RID_BOOL,      D_CONLY },
@@ -4080,6 +4081,31 @@ c_alignof_expr (location_t loc, tree expr)
 
   return fold_convert_loc (loc, size_type_node, t);
 }
+
+/* Implement the _Countof keyword:
+   Return the number of elements of an array.  */
+
+tree
+c_countof_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 %<_Countof%> to type %qT", type);
+      return error_mark_node;
+    }
+  if (!COMPLETE_TYPE_P (type))
+    {
+      error_at (loc,
+		"invalid application of %<_Countof%> 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 cf2228201fad..0bcc4998afe6 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 'countof' expression.  */
+DEFTREECODE (COUNTOF_EXPR, "countof_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 ea6c29750567..91fd120e77e1 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_COUNTOF,
   RID_C23_VA_START, RID_VA_ARG,
   RID_EXTENSION, RID_IMAGPART, RID_REALPART, RID_LABEL,    RID_CHOOSE_EXPR,
   RID_TYPES_COMPATIBLE_P,      RID_BUILTIN_COMPLEX,	   RID_BUILTIN_SHUFFLE,
@@ -890,6 +891,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_countof_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 ad66d7d258b8..5bf638bfbd81 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -8943,12 +8943,17 @@ 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_countof))
     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"
+		       : "_Countof"))));
 
   if (in_underspecified_init)
     error_at (loc, "%qT defined in underspecified object initializer", ref);
@@ -9923,7 +9928,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_countof)
 	struct_parse_info->struct_types.safe_push (t);
      }
 
@@ -10097,12 +10102,17 @@ 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_countof))
     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"
+		       : "_Countof"))));
 
   if (in_underspecified_init)
     error_at (loc, "%qT defined in underspecified object initializer",
@@ -10296,7 +10306,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_countof)
     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 8a63dc54c795..faa03c4903a2 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -77,7 +77,17 @@ along with GCC; see the file COPYING3.  If not see
 #include "asan.h"
 #include "c-family/c-ubsan.h"
 #include "gcc-urlifier.h"
+\f
+#define c_parser_sizeof_expression(parser)                                    \
+(                                                                             \
+  c_parser_sizeof_or_countof_expression (parser, RID_SIZEOF)                  \
+)
 
+#define c_parser_countof_expression(parser)                                   \
+(                                                                             \
+  c_parser_sizeof_or_countof_expression (parser, RID_COUNTOF)                 \
+)
+\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
@@ -1737,7 +1747,8 @@ 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_countof_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 *,
@@ -10452,9 +10463,13 @@ c_parser_cast_expression (c_parser *parser, struct c_expr *after)
      ++ unary-expression
      -- unary-expression
      unary-operator cast-expression
+     _Countof unary-expression
+     _Countof ( type-name )
      sizeof unary-expression
      sizeof ( type-name )
 
+   (_Countof is new in C2y.)
+
    unary-operator: one of
      & * + - ~ !
 
@@ -10572,6 +10587,8 @@ c_parser_unary_expression (c_parser *parser)
     case CPP_KEYWORD:
       switch (c_parser_peek_token (parser)->keyword)
 	{
+	case RID_COUNTOF:
+	  return c_parser_countof_expression (parser);
 	case RID_SIZEOF:
 	  return c_parser_sizeof_expression (parser);
 	case RID_ALIGNOF:
@@ -10611,12 +10628,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_countof_expression (c_parser *parser, enum rid rid)
 {
+  const char *op_name = (rid == RID_COUNTOF) ? "_Countof" : "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;
@@ -10625,7 +10643,10 @@ c_parser_sizeof_expression (c_parser *parser)
 
   c_parser_consume_token (parser);
   c_inhibit_evaluation_warnings++;
-  in_sizeof++;
+  if (rid == RID_COUNTOF)
+    in_countof++;
+  else
+    in_sizeof++;
   if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)
       && c_token_starts_compound_literal (c_parser_peek_2nd_token (parser)))
     {
@@ -10646,7 +10667,7 @@ c_parser_sizeof_expression (c_parser *parser)
 	     for parsing error; the parsing of the expression could have
 	     called record_maybe_used_decl.  */
 	  expr.set_error ();
-	  goto sizeof_expr;
+	  goto Xof_expr;
 	}
       if (c_parser_next_token_is (parser, CPP_OPEN_BRACE))
 	{
@@ -10654,31 +10675,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_COUNTOF)
+	{
+	  in_countof--;
+	  result = c_expr_countof_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_COUNTOF)
+	in_countof--;
+      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_COUNTOF)
+	result = c_expr_countof_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 2098120de297..723a28b39069 100644
--- a/gcc/c/c-tree.h
+++ b/gcc/c/c-tree.h
@@ -765,6 +765,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_countof;
 extern int in_typeof;
 extern bool c_in_omp_for;
 extern bool c_omp_array_section_p;
@@ -827,6 +828,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_countof_expr (location_t, struct c_expr);
+extern struct c_expr c_expr_countof_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 0e1f842e22d3..360216b96621 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -72,6 +72,9 @@ int in_alignof;
 /* The level of nesting inside "sizeof".  */
 int in_sizeof;
 
+/* The level of nesting inside "countof".  */
+int in_countof;
+
 /* The level of nesting inside "typeof".  */
 int in_typeof;
 
@@ -3540,7 +3543,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_countof)
 	C_DECL_USED (ref) = 1;
       else if (DECL_INITIAL (ref) == NULL_TREE
 	       && DECL_EXTERNAL (ref)
@@ -3596,7 +3599,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_countof).  */
   int level;
   /* The next one at this level or above, or NULL.  */
   struct maybe_used_decl *next;
@@ -3614,7 +3617,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_countof;
   t->next = maybe_used_decls;
   maybe_used_decls = t;
 }
@@ -3628,7 +3631,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_countof;
   while (p && p->level > cur_level)
     {
       if (used)
@@ -3738,6 +3741,110 @@ 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);
+  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 countof applied to EXPR.  */
+
+struct c_expr
+c_expr_countof_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_countof_type (loc, TREE_TYPE (folded_expr));
+      c_last_sizeof_arg = expr.value;
+      c_last_sizeof_loc = loc;
+      ret.original_code = COUNTOF_EXPR;
+      ret.original_type = NULL;
+      ret.m_decimal = 0;
+      if (is_top_array_vla (TREE_TYPE (folded_expr)))
+	{
+	  /* countof 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 countof applied to T, a structure for the type
+   name passed to countof (rather than the type itself).  LOC is the
+   location of the original expression.  */
+
+struct c_expr
+c_expr_countof_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_countof_type (loc, type);
+  c_last_sizeof_arg = type;
+  c_last_sizeof_loc = loc;
+  ret.original_code = COUNTOF_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 countof does not get folded to a constant by
+	 c_fully_fold, because if the number of elements is evaluated
+	 the result is not constant and so
+	 constraints on zero or negative size arrays must not be applied
+	 when this countof 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/doc/extend.texi b/gcc/doc/extend.texi
index 40ccf22b29f4..18ee287a3480 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -10706,6 +10706,36 @@ library.
 @xref{OpenMP and OpenACC Options}, for additional options useful with
 @option{-fopenacc}.
 
+@node _Countof
+@section Determining the Number of Elements of Arrays
+@cindex _Countof
+@cindex number of elements
+
+The keyword @code{_Countof} determines
+the number of elements of an array operand.
+Its syntax is similar to @code{sizeof}.
+The operand must be
+a parenthesized complete array type name
+or an expression of such a type.
+For example:
+
+@smallexample
+int a[n];
+_Countof (a);  // returns n
+_Countof (int [7][3]);  // returns 7
+@end smallexample
+
+The result of this operator is an integer constant expression,
+unless the array has a variable number of elements.
+The operand is only evaluated
+if the array has a variable number of elements.
+For example:
+
+@smallexample
+_Countof (int [7][n++]);  // integer constant expression
+_Countof (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/testsuite/gcc.dg/countof-compile.c b/gcc/testsuite/gcc.dg/countof-compile.c
new file mode 100644
index 000000000000..afd5659618b4
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/countof-compile.c
@@ -0,0 +1,124 @@
+/* { dg-do compile } */
+/* { dg-options "-std=c2y -pedantic-errors" } */
+
+#define NULL  ((void *) 0)
+
+extern int x[];
+
+static int w[] = {1, 2, 3};
+
+void
+completed (void)
+{
+  int i = 42;
+  int a[] = {1, 2, i};
+
+  _Static_assert(_Countof (w) == 3);
+  _Static_assert(_Countof (a) == 3);
+}
+
+void
+incomplete (int p[])
+{
+  _Countof (x);  /* { dg-error "incomplete" } */
+
+  /* We want to support array parameters in the future,
+     which should change this from "invalid" to "incomplete".  */
+  _Countof (p);  /* { dg-error "invalid" } */
+}
+
+void
+fam (void)
+{
+  struct {
+    int x;
+    int fam[];
+  } s;
+
+  _Countof (s.fam); /* { dg-error "incomplete" } */
+}
+
+void
+param (int n, int p[n])
+{
+  /* We want to support array parameters in the future,
+     which would make this work.  */
+  _Countof (p);  /* { dg-error "invalid" } */
+}
+
+void fix_fix (int i, char (*a)[3][5], int (*x)[_Countof (*a)],
+	      short (*)[_Generic(x, int (*)[3]: 1)]);
+void fix_var (int i, char (*a)[3][i], int (*x)[_Countof (*a)],
+	      short (*)[_Generic(x, int (*)[3]: 1)]);
+void fix_uns (int i, char (*a)[3][*], int (*x)[_Countof (*a)],
+	      short (*)[_Generic(x, int (*)[3]: 1)]);
+
+void
+func (void)
+{
+  int  i3[3];
+  int  i5[5];
+  char c35[3][5];
+
+  fix_fix (5, &c35, &i3, NULL);
+  fix_fix (5, &c35, &i5, NULL); /* { dg-error "incompatible-pointer-types" } */
+
+  fix_var (5, &c35, &i3, NULL);
+  fix_var (5, &c35, &i5, NULL); /* { dg-error "incompatible-pointer-types" } */
+
+  fix_uns (5, &c35, &i3, NULL);
+  fix_uns (5, &c35, &i5, NULL); /* { dg-error "incompatible-pointer-types" } */
+}
+
+void
+non_arr(void)
+{
+  int x;
+  int *p;
+  struct s {
+    int x[3];
+  } s;
+
+  _Countof (x); /* { dg-error "invalid" } */
+  _Countof (int); /* { dg-error "invalid" } */
+  _Countof (s); /* { dg-error "invalid" } */
+  _Countof (struct s); /* { dg-error "invalid" } */
+  _Countof (&x); /* { dg-error "invalid" } */
+  _Countof (p); /* { dg-error "invalid" } */
+  _Countof (int *); /* { dg-error "invalid" } */
+  _Countof (&s.x); /* { dg-error "invalid" } */
+  _Countof (int (*)[3]); /* { dg-error "invalid" } */
+}
+
+static int f1();
+static int f2(); /* { dg-error "never defined" } */
+int a[10][9];
+int n;
+
+void
+syms(void)
+{
+  int b[n][n];
+
+  _Countof (a[f1()]);
+  _Countof (b[f2()]);
+}
+
+void
+no_parens(void)
+{
+  _Static_assert(_Countof a == 10);
+  _Static_assert(_Countof *a == 9);
+  _Static_assert(_Countof (int [3]) {} == 3);
+
+  _Countof int [3]; /* { dg-error "expected expression before" } */
+}
+
+void
+const_expr(void)
+{
+  int n = 7;
+
+  _Static_assert (_Countof (int [3][n]) == 3);
+  _Static_assert (_Countof (int [n][3]) == 7); /* { dg-error "not constant" } */
+}
diff --git a/gcc/testsuite/gcc.dg/countof-vla.c b/gcc/testsuite/gcc.dg/countof-vla.c
new file mode 100644
index 000000000000..cc225df20689
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/countof-vla.c
@@ -0,0 +1,35 @@
+/* { dg-do compile } */
+/* { dg-options "-std=c2y -pedantic-errors -Wvla-parameter" } */
+
+void fix_fix (int i,
+	      char (*a)[3][5],
+	      int (*x)[_Countof (*a)],
+	      short (*)[_Generic(x, int (*)[3]: 1)]);
+void fix_var (int i,
+	      char (*a)[3][i], /* dg-warn "variable" */
+	      int (*x)[_Countof (*a)],
+	      short (*)[_Generic(x, int (*)[3]: 1)]);
+void fix_uns (int i,
+	      char (*a)[3][*],
+	      int (*x)[_Countof (*a)],
+	      short (*)[_Generic(x, int (*)[3]: 1)]);
+
+void var_fix (int i,
+	      char (*a)[i][5], /* dg-warn "variable" */
+	      int (*x)[_Countof (*a)]); /* dg-warn "variable" */
+void var_var (int i,
+	      char (*a)[i][i], /* dg-warn "variable" */
+	      int (*x)[_Countof (*a)]); /* dg-warn "variable" */
+void var_uns (int i,
+	      char (*a)[i][*], /* dg-warn "variable" */
+	      int (*x)[_Countof (*a)]); /* dg-warn "variable" */
+
+void uns_fix (int i,
+	      char (*a)[*][5],
+	      int (*x)[_Countof (*a)]);
+void uns_var (int i,
+	      char (*a)[*][i], /* dg-warn "variable" */
+	      int (*x)[_Countof (*a)]);
+void uns_uns (int i,
+	      char (*a)[*][*],
+	      int (*x)[_Countof (*a)]);
diff --git a/gcc/testsuite/gcc.dg/countof-vmt.c b/gcc/testsuite/gcc.dg/countof-vmt.c
new file mode 100644
index 000000000000..67467b0d2e0f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/countof-vmt.c
@@ -0,0 +1,20 @@
+/* { dg-do run } */
+/* { dg-options "-std=gnu2y" } */
+
+#define assert(e)  ((e) ? (void) 0 : __builtin_abort ())
+
+void
+inner_vla_noeval (void)
+{
+  int i;
+
+  i = 3;
+  static_assert (_Countof (struct {int x[i++];}[3]) == 3);
+  assert (i == 3);
+}
+
+int
+main (void)
+{
+  inner_vla_noeval ();
+}
diff --git a/gcc/testsuite/gcc.dg/countof-zero-compile.c b/gcc/testsuite/gcc.dg/countof-zero-compile.c
new file mode 100644
index 000000000000..b561186166c3
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/countof-zero-compile.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-std=gnu2y" } */
+
+static int z[0];
+static int y[_Countof (z)];
+
+_Static_assert(_Countof (y) == 0);
+
+void
+completed (void)
+{
+  int z[] = {};
+
+  static_assert (_Countof (z) == 0);
+}
+
+void zro_fix (int i,
+	      char (*a)[0][5],
+	      int (*x)[_Countof (*a)],
+	      short (*)[_Generic(x, int (*)[0]: 1)]);
+void zro_var (int i,
+	      char (*a)[0][i], /* dg-warn "variable" */
+	      int (*x)[_Countof (*a)],
+	      short (*)[_Generic(x, int (*)[0]: 1)]);
+void zro_uns (int i,
+	      char (*a)[0][*],
+	      int (*x)[_Countof (*a)],
+	      short (*)[_Generic(x, int (*)[0]: 1)]);
+
+void
+const_expr(void)
+{
+  int n = 7;
+
+  _Static_assert (_Countof (int [0][3]) == 0);
+  _Static_assert (_Countof (int [0]) == 0);
+  _Static_assert (_Countof (int [0][n]) == 0);
+}
diff --git a/gcc/testsuite/gcc.dg/countof-zero.c b/gcc/testsuite/gcc.dg/countof-zero.c
new file mode 100644
index 000000000000..27b5bdd490dd
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/countof-zero.c
@@ -0,0 +1,31 @@
+/* { dg-do run } */
+/* { dg-options "-std=gnu2y" } */
+
+#define assert(e)  ((e) ? (void) 0 : __builtin_abort ())
+
+void
+vla (void)
+{
+  unsigned n;
+
+  n = 0;
+  int z[n];
+  assert (_Countof (z) == 0);
+}
+
+void
+matrix_vla (void)
+{
+  int i;
+
+  i = 0;
+  assert (_Countof (int [i++][4]) == 0);
+  assert (i == 0 + 1);
+}
+
+int
+main (void)
+{
+  vla ();
+  matrix_vla ();
+}
diff --git a/gcc/testsuite/gcc.dg/countof.c b/gcc/testsuite/gcc.dg/countof.c
new file mode 100644
index 000000000000..534488501c6a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/countof.c
@@ -0,0 +1,120 @@
+/* { dg-do run } */
+/* { dg-options "-std=c2y -pedantic-errors" } */
+
+#define assert(e)  ((e) ? (void) 0 : __builtin_abort ())
+
+void
+array (void)
+{
+  short a[7];
+
+  static_assert (_Countof (a) == 7);
+  static_assert (_Countof (unsigned [99]) == 99);
+}
+
+void
+completed (void)
+{
+  int a[] = {1, 2, 3};
+
+  static_assert (_Countof (a) == 3);
+}
+
+void
+vla (void)
+{
+  unsigned n;
+
+  n = 99;
+  assert (_Countof (short [n - 10]) == 99 - 10);
+
+  int v[n / 2];
+  assert (_Countof (v) == 99 / 2);
+}
+
+void
+member (void)
+{
+  struct {
+    int a[8];
+  } s;
+
+  static_assert (_Countof (s.a) == 8);
+}
+
+void
+vla_eval (void)
+{
+  int i;
+
+  i = 7;
+  assert (_Countof (struct {int x;}[i++]) == 7);
+  assert (i == 7 + 1);
+
+  int v[i];
+  int (*p)[i];
+  p = &v;
+  assert (_Countof (*p++) == i);
+  assert (p - 1 == &v);
+}
+
+void
+array_noeval (void)
+{
+  long a[5];
+  long (*p)[_Countof (a)];
+
+  p = &a;
+  static_assert (_Countof (*p++) == 5);
+  assert (p == &a);
+}
+
+void
+matrix_fixed (void)
+{
+  int i;
+
+  static_assert (_Countof (int [7][4]) == 7);
+  i = 3;
+  static_assert (_Countof (int [7][i]) == 7);
+}
+
+void
+matrix_vla (void)
+{
+  int i, j;
+
+  i = 7;
+  assert (_Countof (int [i++][4]) == 7);
+  assert (i == 7 + 1);
+
+  i = 9;
+  j = 3;
+  assert (_Countof (int [i++][j]) == 9);
+  assert (i == 9 + 1);
+}
+
+void
+no_parens(void)
+{
+  int n = 3;
+  int a[7];
+  int v[n];
+
+  static_assert (_Countof a == 7); 
+  assert (_Countof v == 3); 
+}
+
+int
+main (void)
+{
+  array ();
+  completed ();
+  vla ();
+  member ();
+  vla_eval ();
+  array_noeval ();
+  matrix_fixed ();
+  matrix_vla ();
+  no_parens ();
+}
-- 
2.49.0


^ permalink raw reply	[flat|nested] 318+ messages in thread

* [PATCH v24 2/3] c: Add <stdcountof.h>
  2025-05-21 21:01   ` [PATCH v24 " Alejandro Colomar
  2025-05-21 21:01     ` [PATCH v24 1/3] c: Add _Countof operator Alejandro Colomar
@ 2025-05-21 21:01     ` Alejandro Colomar
  2025-05-21 21:06       ` Jakub Jelinek
  2025-05-21 21:01     ` [PATCH v24 3/3] c: Add -Wpedantic diagnostic for _Countof Alejandro Colomar
  2 siblings, 1 reply; 318+ messages in thread
From: Alejandro Colomar @ 2025-05-21 21:01 UTC (permalink / raw)
  To: gcc-patches
  Cc: Alejandro Colomar, Martin Uecker, JeanHeyd Meneide, Joseph Myers,
	Jakub Jelinek

gcc/ChangeLog:

	* Makefile.in (USER_H): Add <stdcountof.h>.
	* ginclude/stdcountof.h: Add countof macro.

gcc/testsuite/ChangeLog:

	* gcc.dg/countof-stdcountof.c: Add tests for <stdcountof.h>.

Signed-off-by: Alejandro Colomar <alx@kernel.org>
---
 gcc/Makefile.in                           |  1 +
 gcc/ginclude/stdcountof.h                 | 31 +++++++++++++++++++++++
 gcc/testsuite/gcc.dg/countof-stdcountof.c | 24 ++++++++++++++++++
 3 files changed, 56 insertions(+)
 create mode 100644 gcc/ginclude/stdcountof.h
 create mode 100644 gcc/testsuite/gcc.dg/countof-stdcountof.c

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 72d132207c0d..fc8a7e532b97 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -481,6 +481,7 @@ USER_H = $(srcdir)/ginclude/float.h \
 	 $(srcdir)/ginclude/stdalign.h \
 	 $(srcdir)/ginclude/stdatomic.h \
 	 $(srcdir)/ginclude/stdckdint.h \
+	 $(srcdir)/ginclude/stdcountof.h \
 	 $(EXTRA_HEADERS)
 
 USER_H_INC_NEXT_PRE = @user_headers_inc_next_pre@
diff --git a/gcc/ginclude/stdcountof.h b/gcc/ginclude/stdcountof.h
new file mode 100644
index 000000000000..1d914f40e5db
--- /dev/null
+++ b/gcc/ginclude/stdcountof.h
@@ -0,0 +1,31 @@
+/* Copyright (C) 2025 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/>.  */
+
+/* ISO C2Y: 7.21 Array count <stdcountof.h>.  */
+
+#ifndef _STDCOUNTOF_H
+#define _STDCOUNTOF_H
+
+#define countof  _Countof
+
+#endif	/* stdcountof.h */
diff --git a/gcc/testsuite/gcc.dg/countof-stdcountof.c b/gcc/testsuite/gcc.dg/countof-stdcountof.c
new file mode 100644
index 000000000000..2fb0c6306ef0
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/countof-stdcountof.c
@@ -0,0 +1,24 @@
+/* { dg-do run } */
+/* { dg-options "-std=c2y -pedantic-errors" } */
+
+#include <stdcountof.h>
+
+#define assert(e)  ((e) ? (void) 0 : __builtin_abort ())
+
+extern int strcmp (const char *, const char *);
+
+#ifndef countof
+#error "countof not defined"
+#endif
+
+int a[3];
+int b[countof a];
+
+#define str(x) #x
+#define xstr(x) str(x)
+
+int
+main (void)
+{
+  assert (strcmp (xstr(countof), "_Countof") == 0);
+}
-- 
2.49.0


^ permalink raw reply	[flat|nested] 318+ messages in thread

* [PATCH v24 3/3] c: Add -Wpedantic diagnostic for _Countof
  2025-05-21 21:01   ` [PATCH v24 " Alejandro Colomar
  2025-05-21 21:01     ` [PATCH v24 1/3] c: Add _Countof operator Alejandro Colomar
  2025-05-21 21:01     ` [PATCH v24 2/3] c: Add <stdcountof.h> Alejandro Colomar
@ 2025-05-21 21:01     ` Alejandro Colomar
  2025-05-21 21:12       ` Jakub Jelinek
  2 siblings, 1 reply; 318+ messages in thread
From: Alejandro Colomar @ 2025-05-21 21:01 UTC (permalink / raw)
  To: gcc-patches
  Cc: Alejandro Colomar, Martin Uecker, JeanHeyd Meneide, Joseph Myers,
	Jakub Jelinek

It has been standardized in C2y.

gcc/c/ChangeLog:

	* c-parser.cc (c_parser_sizeof_or_countof_expression):
	Add -Wpedantic diagnostic for _Countof in <= C23 mode.

gcc/testsuite/ChangeLog:

	* gcc.dg/countof-compat.c:
	Test _Countof diagnostics with -Wc23-c2y-compat on C2y.
	* gcc.dg/countof-no-compat.c:
	Test _Countof diagnostics with -Wno-c23-c2y-compat on C23.
	* gcc.dg/countof-pedantic.c:
	Test _Countof diagnostics with -pedantic on C23.
	* gcc.dg/countof-pedantic-errors.c:
	Test _Countof diagnostics with -pedantic-errors on C23.

Signed-off-by: Alejandro Colomar <alx@kernel.org>
---
 gcc/c/c-parser.cc                              | 4 ++++
 gcc/testsuite/gcc.dg/countof-compat.c          | 8 ++++++++
 gcc/testsuite/gcc.dg/countof-no-compat.c       | 5 +++++
 gcc/testsuite/gcc.dg/countof-pedantic-errors.c | 8 ++++++++
 gcc/testsuite/gcc.dg/countof-pedantic.c        | 8 ++++++++
 5 files changed, 33 insertions(+)
 create mode 100644 gcc/testsuite/gcc.dg/countof-compat.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-no-compat.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-pedantic-errors.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-pedantic.c

diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
index faa03c4903a2..de48a016dcdb 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -10641,6 +10641,10 @@ c_parser_sizeof_or_countof_expression (c_parser *parser, enum rid rid)
 
   start = c_parser_peek_token (parser)->location;
 
+  if (rid == RID_COUNTOF)
+    pedwarn_c23 (start, OPT_Wpedantic,
+		 "ISO C does not support %qs before C23", op_name);
+
   c_parser_consume_token (parser);
   c_inhibit_evaluation_warnings++;
   if (rid == RID_COUNTOF)
diff --git a/gcc/testsuite/gcc.dg/countof-compat.c b/gcc/testsuite/gcc.dg/countof-compat.c
new file mode 100644
index 000000000000..ab5b4ae6219c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/countof-compat.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-std=c2y -pedantic-errors -Wc23-c2y-compat" } */
+
+#include <stdcountof.h>
+
+int a[1];
+int b[countof(a)];
+int c[_Countof(a)];  /* { dg-warning "ISO C does not support" } */
diff --git a/gcc/testsuite/gcc.dg/countof-no-compat.c b/gcc/testsuite/gcc.dg/countof-no-compat.c
new file mode 100644
index 000000000000..4a244cf222f6
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/countof-no-compat.c
@@ -0,0 +1,5 @@
+/* { dg-do compile } */
+/* { dg-options "-std=c23 -pedantic-errors -Wno-c23-c2y-compat" } */
+
+int a[1];
+int b[_Countof(a)];
diff --git a/gcc/testsuite/gcc.dg/countof-pedantic-errors.c b/gcc/testsuite/gcc.dg/countof-pedantic-errors.c
new file mode 100644
index 000000000000..5d5bedbe1f7e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/countof-pedantic-errors.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-std=c23 -pedantic-errors" } */
+
+#include <stdcountof.h>
+
+int a[1];
+int b[countof(a)];
+int c[_Countof(a)];  /* { dg-error "ISO C does not support" } */
diff --git a/gcc/testsuite/gcc.dg/countof-pedantic.c b/gcc/testsuite/gcc.dg/countof-pedantic.c
new file mode 100644
index 000000000000..408dc6f93667
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/countof-pedantic.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-std=c23 -pedantic" } */
+
+#include <stdcountof.h>
+
+int a[1];
+int b[countof(a)];
+int c[_Countof(a)];  /* { dg-warning "ISO C does not support" } */
-- 
2.49.0


^ permalink raw reply	[flat|nested] 318+ messages in thread

* Re: [PATCH v24 2/3] c: Add <stdcountof.h>
  2025-05-21 21:01     ` [PATCH v24 2/3] c: Add <stdcountof.h> Alejandro Colomar
@ 2025-05-21 21:06       ` Jakub Jelinek
  0 siblings, 0 replies; 318+ messages in thread
From: Jakub Jelinek @ 2025-05-21 21:06 UTC (permalink / raw)
  To: Alejandro Colomar
  Cc: gcc-patches, Martin Uecker, JeanHeyd Meneide, Joseph Myers

On Wed, May 21, 2025 at 11:01:35PM +0200, Alejandro Colomar wrote:
> gcc/ChangeLog:
> 
> 	* Makefile.in (USER_H): Add <stdcountof.h>.
> 	* ginclude/stdcountof.h: Add countof macro.

This one is actually : New file.
If the header existed before and you've just added countof macro
definition, it would be (countof): Define.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* gcc.dg/countof-stdcountof.c: Add tests for <stdcountof.h>.

This is a new test, so you just say : New test.

	Jakub


^ permalink raw reply	[flat|nested] 318+ messages in thread

* Re: [PATCH v24 1/3] c: Add _Countof operator
  2025-05-21 21:01     ` [PATCH v24 1/3] c: Add _Countof operator Alejandro Colomar
@ 2025-05-21 21:12       ` Jakub Jelinek
  2025-05-21 21:31         ` Alejandro Colomar
  2025-05-21 21:36         ` Alejandro Colomar
  0 siblings, 2 replies; 318+ messages in thread
From: Jakub Jelinek @ 2025-05-21 21:12 UTC (permalink / raw)
  To: Alejandro Colomar
  Cc: gcc-patches, Martin Uecker, JeanHeyd Meneide, Joseph Myers,
	Xavier Del Campo Romero, James K. Lowden

On Wed, May 21, 2025 at 11:01:31PM +0200, Alejandro Colomar wrote:
> This operator is similar to sizeof but can only be applied to an array,
> and returns its number of elements.
> 
> FUTURE DIRECTIONS:
> 
> -  We should make it work with array parameters to functions,
>    and somehow magically return the number of elements of the array,
>    regardless of it being really a pointer.
> 
> Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3550.pdf>
> Link: <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117025>
> Link: <https://inbox.sourceware.org/gcc/M8S4oQy--3-2@tutanota.com/T/>
> Link: <https://inbox.sourceware.org/gcc-patches/20240728141547.302478-1-alx@kernel.org/T/#t>
> Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3313.pdf>
> Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3325.pdf>
> Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3369.pdf>
> Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3469.htm>
> Link: <https://github.com/llvm/llvm-project/issues/102836>
> Link: <https://thephd.dev/the-big-array-size-survey-for-c>
> Link: <https://thephd.dev/the-big-array-size-survey-for-c-results>
> Link: <https://stackoverflow.com/questions/37538/#57537491>
> 
> gcc/ChangeLog:
> 
> 	* doc/extend.texi: Document _Countof operator.
> 
> gcc/c-family/ChangeLog:
> 
> 	* c-common.h: Add RID_COUNTOF.

(enum rid): Add RID_COUNTOF.

> 	(c_countof_type): New function prototype.
> 	* c-common.def (COUNTOF_EXPR): New tree.
> 	* c-common.cc
> 	(c_common_reswords): Add RID_COUNTOF entry.

No newline in between the line with file and (c_common_reswords).
	* c-common.cc (c_common_reswords): Add RID_COUNTOF entry.
fits just fine.  And even if the description wouldn't fit completely,
you'd wrap on the first word that doesn't fit.

> 	(c_countof_type): New function.
> 
> gcc/c/ChangeLog:
> 
> 	* c-tree.h
> 	(in_countof): Add global variable declaration.

Ditto.
> 	(c_expr_countof_expr): Add function prototype.
> 	(c_expr_countof_type): Add function prototype.
> 	* c-decl.cc
> 	(start_struct, finish_struct): Add support for _Countof.

Ditto.

> 	(start_enum, finish_enum): Add support for _Countof.
> 	* c-parser.cc
> 	(c_parser_sizeof_expression): New macro.

Ditto.
> 	(c_parser_countof_expression): New macro.
> 	(c_parser_sizeof_or_countof_expression):
> 	Rename function and add support for _Countof.
> 	(c_parser_unary_expression): Add RID_COUNTOF entry.
> 	* c-typeck.cc
> 	(in_countof): Add global variable.

Ditto.
> 	(build_external_ref): Add support for _Countof.
> 	(record_maybe_used_decl): Add support for _Countof.
> 	(pop_maybe_used): Add support for _Countof.
> 	(is_top_array_vla): New function.
> 	(c_expr_countof_expr, c_expr_countof_type): New functions.
> 	Add _Countof operator.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* gcc.dg/countof-compile.c: Compile-time tests for _Countof.
> 	* gcc.dg/countof-vla.c: Tests for _Countof with VLAs.
> 	* gcc.dg/countof-vmt.c: Tests for _Countof with other VMTs.
> 	* gcc.dg/countof-zero-compile.c:
> 	Compile-time tests for _Countof with zero-sized arrays.
> 	* gcc.dg/countof-zero.c:
> 	Tests for _Countof with zero-sized arrays.
> 	* gcc.dg/countof.c: Tests for _Countof.
> 
> Suggested-by: Xavier Del Campo Romero <xavi.dcr@tutanota.com>
> Co-authored-by: Martin Uecker <uecker@tugraz.at>
> Acked-by: "James K. Lowden" <jklowden@schemamania.org>
> 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                             |  22 +++-
>  gcc/c/c-parser.cc                           |  63 +++++++---
>  gcc/c/c-tree.h                              |   4 +
>  gcc/c/c-typeck.cc                           | 115 +++++++++++++++++-
>  gcc/doc/extend.texi                         |  30 +++++
>  gcc/testsuite/gcc.dg/countof-compile.c      | 124 ++++++++++++++++++++
>  gcc/testsuite/gcc.dg/countof-vla.c          |  35 ++++++
>  gcc/testsuite/gcc.dg/countof-vmt.c          |  20 ++++
>  gcc/testsuite/gcc.dg/countof-zero-compile.c |  38 ++++++
>  gcc/testsuite/gcc.dg/countof-zero.c         |  31 +++++
>  gcc/testsuite/gcc.dg/countof.c              | 120 +++++++++++++++++++
>  14 files changed, 609 insertions(+), 24 deletions(-)
>  create mode 100644 gcc/testsuite/gcc.dg/countof-compile.c
>  create mode 100644 gcc/testsuite/gcc.dg/countof-vla.c
>  create mode 100644 gcc/testsuite/gcc.dg/countof-vmt.c
>  create mode 100644 gcc/testsuite/gcc.dg/countof-zero-compile.c
>  create mode 100644 gcc/testsuite/gcc.dg/countof-zero.c
>  create mode 100644 gcc/testsuite/gcc.dg/countof.c
> 
> diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
> index 587d76461e9e..f71cb2652d5a 100644
> --- a/gcc/c-family/c-common.cc
> +++ b/gcc/c-family/c-common.cc
> @@ -394,6 +394,7 @@ const struct c_common_resword c_common_reswords[] =
>  {
>    { "_Alignas",		RID_ALIGNAS,   D_CONLY },
>    { "_Alignof",		RID_ALIGNOF,   D_CONLY },
> +  { "_Countof",		RID_COUNTOF,   D_CONLY },
>    { "_Atomic",		RID_ATOMIC,    D_CONLY },
>    { "_BitInt",		RID_BITINT,    D_CONLY },
>    { "_Bool",		RID_BOOL,      D_CONLY },
> @@ -4080,6 +4081,31 @@ c_alignof_expr (location_t loc, tree expr)
>  
>    return fold_convert_loc (loc, size_type_node, t);
>  }
> +
> +/* Implement the _Countof keyword:
> +   Return the number of elements of an array.  */
> +
> +tree
> +c_countof_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 %<_Countof%> to type %qT", type);
> +      return error_mark_node;
> +    }
> +  if (!COMPLETE_TYPE_P (type))
> +    {
> +      error_at (loc,
> +		"invalid application of %<_Countof%> 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 cf2228201fad..0bcc4998afe6 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 'countof' expression.  */
> +DEFTREECODE (COUNTOF_EXPR, "countof_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 ea6c29750567..91fd120e77e1 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_COUNTOF,
>    RID_C23_VA_START, RID_VA_ARG,
>    RID_EXTENSION, RID_IMAGPART, RID_REALPART, RID_LABEL,    RID_CHOOSE_EXPR,
>    RID_TYPES_COMPATIBLE_P,      RID_BUILTIN_COMPLEX,	   RID_BUILTIN_SHUFFLE,
> @@ -890,6 +891,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_countof_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 ad66d7d258b8..5bf638bfbd81 100644
> --- a/gcc/c/c-decl.cc
> +++ b/gcc/c/c-decl.cc
> @@ -8943,12 +8943,17 @@ 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_countof))
>      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"
> +		       : "_Countof"))));

Why so many lines?  Plus no idea why there are the ()s around, I see it is
preexisting for the outermost where it can help emacs formatting, but the
rest doesn't need that.
>  		"defining type in %qs expression is invalid in C++",
>  		(in_sizeof
>  		 ? "sizeof"
> -		 : (in_typeof ? "typeof" : "alignof")));
> +		 : (in_typeof
> +		    ? "typeof"
> +		    : (in_alignof
> +		       ? "alignof"
> +		       : "_Countof"))));

Ditto.

> @@ -77,7 +77,17 @@ along with GCC; see the file COPYING3.  If not see
>  #include "asan.h"
>  #include "c-family/c-ubsan.h"
>  #include "gcc-urlifier.h"
> +\f
> +#define c_parser_sizeof_expression(parser)                                    \
> +(                                                                             \
> +  c_parser_sizeof_or_countof_expression (parser, RID_SIZEOF)                  \
> +)
>  
> +#define c_parser_countof_expression(parser)                                   \
> +(                                                                             \
> +  c_parser_sizeof_or_countof_expression (parser, RID_COUNTOF)                 \
> +)

Up to Joseph, but I'd say these should just be inline functions, not macros,
and defined after the declarations.

	Jakub


^ permalink raw reply	[flat|nested] 318+ messages in thread

* Re: [PATCH v24 3/3] c: Add -Wpedantic diagnostic for _Countof
  2025-05-21 21:01     ` [PATCH v24 3/3] c: Add -Wpedantic diagnostic for _Countof Alejandro Colomar
@ 2025-05-21 21:12       ` Jakub Jelinek
  0 siblings, 0 replies; 318+ messages in thread
From: Jakub Jelinek @ 2025-05-21 21:12 UTC (permalink / raw)
  To: Alejandro Colomar
  Cc: gcc-patches, Martin Uecker, JeanHeyd Meneide, Joseph Myers

On Wed, May 21, 2025 at 11:01:38PM +0200, Alejandro Colomar wrote:
> It has been standardized in C2y.
> 
> gcc/c/ChangeLog:
> 
> 	* c-parser.cc (c_parser_sizeof_or_countof_expression):
> 	Add -Wpedantic diagnostic for _Countof in <= C23 mode.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* gcc.dg/countof-compat.c:
> 	Test _Countof diagnostics with -Wc23-c2y-compat on C2y.
> 	* gcc.dg/countof-no-compat.c:
> 	Test _Countof diagnostics with -Wno-c23-c2y-compat on C23.
> 	* gcc.dg/countof-pedantic.c:
> 	Test _Countof diagnostics with -pedantic on C23.
> 	* gcc.dg/countof-pedantic-errors.c:
> 	Test _Countof diagnostics with -pedantic-errors on C23.

For new test files, just say : New test.

	Jakub


^ permalink raw reply	[flat|nested] 318+ messages in thread

* Re: [PATCH v24 1/3] c: Add _Countof operator
  2025-05-21 21:12       ` Jakub Jelinek
@ 2025-05-21 21:31         ` Alejandro Colomar
  2025-05-21 21:41           ` Jakub Jelinek
  2025-05-21 21:44           ` Alejandro Colomar
  2025-05-21 21:36         ` Alejandro Colomar
  1 sibling, 2 replies; 318+ messages in thread
From: Alejandro Colomar @ 2025-05-21 21:31 UTC (permalink / raw)
  To: Jakub Jelinek
  Cc: gcc-patches, Martin Uecker, JeanHeyd Meneide, Joseph Myers,
	Xavier Del Campo Romero, James K. Lowden

[-- Attachment #1: Type: text/plain, Size: 2462 bytes --]

Hi Jakub,

On Wed, May 21, 2025 at 11:12:07PM +0200, Jakub Jelinek wrote:
> > 	* c-common.h: Add RID_COUNTOF.
> 
> (enum rid): Add RID_COUNTOF.

Okay.

> 
> > 	(c_countof_type): New function prototype.
> > 	* c-common.def (COUNTOF_EXPR): New tree.
> > 	* c-common.cc
> > 	(c_common_reswords): Add RID_COUNTOF entry.
> 
> No newline in between the line with file and (c_common_reswords).
> 	* c-common.cc (c_common_reswords): Add RID_COUNTOF entry.
> fits just fine.  And even if the description wouldn't fit completely,
> you'd wrap on the first word that doesn't fit.

Okay.

> >      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"
> > +		       : "_Countof"))));
> 
> Why so many lines?  Plus no idea why there are the ()s around, I see it is
> preexisting for the outermost where it can help emacs formatting, but the
> rest doesn't need that.

The preexisting ones are not just the outermost ones.  The preexisting
code was 

		(in_sizeof
		 ? "sizeof"
		 : (in_typeof ? "typeof" : "alignof")));

The only pattern I can find in that code is wrapping every ?:
subexpression in ().  I would find not doing so for the last one I'm
adding inconsistent with it.  On the other hand, I would agree that
limiting it to just the outermost ones would be more readable, but that
would mean removing existing ()s.  So can you please confirm that I
should remove the existing inner ()?

> > +#define c_parser_sizeof_expression(parser)                                    \
> > +(                                                                             \
> > +  c_parser_sizeof_or_countof_expression (parser, RID_SIZEOF)                  \
> > +)
> >  
> > +#define c_parser_countof_expression(parser)                                   \
> > +(                                                                             \
> > +  c_parser_sizeof_or_countof_expression (parser, RID_COUNTOF)                 \
> > +)
> 
> Up to Joseph, but I'd say these should just be inline functions, not macros,
> and defined after the declarations.

I don't mind, so yeah, I'm okay with changing these to be inline.


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] 318+ messages in thread

* Re: [PATCH v24 1/3] c: Add _Countof operator
  2025-05-21 21:12       ` Jakub Jelinek
  2025-05-21 21:31         ` Alejandro Colomar
@ 2025-05-21 21:36         ` Alejandro Colomar
  2025-05-21 21:37           ` Alejandro Colomar
  1 sibling, 1 reply; 318+ messages in thread
From: Alejandro Colomar @ 2025-05-21 21:36 UTC (permalink / raw)
  To: Jakub Jelinek
  Cc: gcc-patches, Martin Uecker, JeanHeyd Meneide, Joseph Myers,
	Xavier Del Campo Romero, James K. Lowden

[-- Attachment #1: Type: text/plain, Size: 669 bytes --]

Hi Jakub,

On Wed, May 21, 2025 at 11:12:07PM +0200, Jakub Jelinek wrote:
> >      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"
> > +		       : "_Countof"))));
> 
> Why so many lines?

Because IMO using two lines and breaking at a random point would make it
less readable.  Which style do you prefer?  If you send me an exact way
I should use, I'll paste it.


Cheers,
Alex

-- 
<https://www.alejandro-colomar.es/>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 318+ messages in thread

* Re: [PATCH v24 1/3] c: Add _Countof operator
  2025-05-21 21:36         ` Alejandro Colomar
@ 2025-05-21 21:37           ` Alejandro Colomar
  0 siblings, 0 replies; 318+ messages in thread
From: Alejandro Colomar @ 2025-05-21 21:37 UTC (permalink / raw)
  To: Jakub Jelinek
  Cc: gcc-patches, Martin Uecker, JeanHeyd Meneide, Joseph Myers,
	Xavier Del Campo Romero, James K. Lowden

[-- Attachment #1: Type: text/plain, Size: 1581 bytes --]

On Wed, May 21, 2025 at 11:36:56PM +0200, Alejandro Colomar wrote:
> Hi Jakub,
> 
> On Wed, May 21, 2025 at 11:12:07PM +0200, Jakub Jelinek wrote:
> > >      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"
> > > +		       : "_Countof"))));
> > 
> > Why so many lines?
> 
> Because IMO using two lines and breaking at a random point would make it
> less readable.  Which style do you prefer?  If you send me an exact way
> I should use, I'll paste it.

I propose:

diff --git i/gcc/c/c-decl.cc w/gcc/c/c-decl.cc
index 5bf638bfbd81..e6b8a84e50b1 100644
--- i/gcc/c/c-decl.cc
+++ w/gcc/c/c-decl.cc
@@ -8949,11 +8949,11 @@ start_struct (location_t loc, enum tree_code code, tree name,
                "defining type in %qs expression is invalid in C++",
                (in_sizeof
                 ? "sizeof"
-                : (in_typeof
-                   ? "typeof"
-                   : (in_alignof
-                      ? "alignof"
-                      : "_Countof"))));
+                : in_typeof
+                  ? "typeof"
+                  : in_alignof
+                    ? "alignof"
+                    : "_Countof"));
 
   if (in_underspecified_init)
     error_at (loc, "%qT defined in underspecified object initializer", ref);



-- 
<https://www.alejandro-colomar.es/>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 318+ messages in thread

* Re: [PATCH v24 1/3] c: Add _Countof operator
  2025-05-21 21:31         ` Alejandro Colomar
@ 2025-05-21 21:41           ` Jakub Jelinek
  2025-05-21 21:44           ` Alejandro Colomar
  1 sibling, 0 replies; 318+ messages in thread
From: Jakub Jelinek @ 2025-05-21 21:41 UTC (permalink / raw)
  To: Alejandro Colomar
  Cc: gcc-patches, Martin Uecker, JeanHeyd Meneide, Joseph Myers,
	Xavier Del Campo Romero, James K. Lowden

On Wed, May 21, 2025 at 11:31:01PM +0200, Alejandro Colomar wrote:
> The preexisting ones are not just the outermost ones.  The preexisting
> code was 
> 
> 		(in_sizeof
> 		 ? "sizeof"
> 		 : (in_typeof ? "typeof" : "alignof")));
> 
> The only pattern I can find in that code is wrapping every ?:
> subexpression in ().  I would find not doing so for the last one I'm
> adding inconsistent with it.  On the other hand, I would agree that
> limiting it to just the outermost ones would be more readable, but that
> would mean removing existing ()s.  So can you please confirm that I
> should remove the existing inner ()?

I think
    warning_at (loc, OPT_Wc___compat,
		"defining type in %qs expression is invalid in C++",
                in_sizeof ? "sizeof" : in_typeof ? "typeof"
		: in_alignof ? "alignof" : "_Countof");
or say
                (in_sizeof ? "sizeof"
		 : in_typeof ? "typeof"
		 : in_alignof ? "alignof"
		 : "_Countof"));
or that without the extra () would look better.
Those are the styles used elsewhere, e.g.
alias.cc-  sizey = (!MEM_P (rtly) ? poly_int64 (GET_MODE_SIZE (GET_MODE (rtly)))
alias.cc:          : MEM_SIZE_KNOWN_P (rtly) ? MEM_SIZE (rtly)
alias.cc-          : -1);
or
cfgexpand.cc-                   allows_reg ? EXPAND_NORMAL
cfgexpand.cc:                   : allows_mem ? EXPAND_MEMORY
cfgexpand.cc-                   : EXPAND_INITIALIZER);
or
combine.cc-       inner = simplify_binary_operation (code == MINUS ? PLUS
combine.cc:                                          : code == DIV ? MULT
combine.cc-                                          : code,
combine.cc-                                          mode, inner_op0, inner_op1);
etc.

	Jakub


^ permalink raw reply	[flat|nested] 318+ messages in thread

* Re: [PATCH v24 1/3] c: Add _Countof operator
  2025-05-21 21:31         ` Alejandro Colomar
  2025-05-21 21:41           ` Jakub Jelinek
@ 2025-05-21 21:44           ` Alejandro Colomar
  2025-05-21 21:47             ` Jakub Jelinek
  1 sibling, 1 reply; 318+ messages in thread
From: Alejandro Colomar @ 2025-05-21 21:44 UTC (permalink / raw)
  To: Jakub Jelinek
  Cc: gcc-patches, Martin Uecker, JeanHeyd Meneide, Joseph Myers,
	Xavier Del Campo Romero, James K. Lowden

[-- Attachment #1: Type: text/plain, Size: 3140 bytes --]

Hi Jakub,

On Wed, May 21, 2025 at 11:31:05PM +0200, Alejandro Colomar wrote:
> > > +#define c_parser_sizeof_expression(parser)                                    \
> > > +(                                                                             \
> > > +  c_parser_sizeof_or_countof_expression (parser, RID_SIZEOF)                  \
> > > +)
> > >  
> > > +#define c_parser_countof_expression(parser)                                   \
> > > +(                                                                             \
> > > +  c_parser_sizeof_or_countof_expression (parser, RID_COUNTOF)                 \
> > > +)
> > 
> > Up to Joseph, but I'd say these should just be inline functions, not macros,
> > and defined after the declarations.
> 
> I don't mind, so yeah, I'm okay with changing these to be inline.

Does this sound good?

	diff --git i/gcc/c/c-parser.cc w/gcc/c/c-parser.cc
	index faa03c4903a2..733cb312341e 100644
	--- i/gcc/c/c-parser.cc
	+++ w/gcc/c/c-parser.cc
	@@ -78,16 +78,6 @@ along with GCC; see the file COPYING3.  If not see
	 #include "c-family/c-ubsan.h"
	 #include "gcc-urlifier.h"
	 ^L
	-#define c_parser_sizeof_expression(parser)                                    \
	-(                                                                             \
	-  c_parser_sizeof_or_countof_expression (parser, RID_SIZEOF)                  \
	-)
	-
	-#define c_parser_countof_expression(parser)                                   \
	-(                                                                             \
	-  c_parser_sizeof_or_countof_expression (parser, RID_COUNTOF)                 \
	-)
	-^L
	 /* 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
	@@ -1747,6 +1737,8 @@ 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 inline struct c_expr c_parser_sizeof_expression (c_parser *);
	+static inline struct c_expr c_parser_countof_expression (c_parser *);
	 static struct c_expr c_parser_sizeof_or_countof_expression (c_parser *,
								    enum rid);
	 static struct c_expr c_parser_alignof_expression (c_parser *);
	@@ -10627,6 +10619,22 @@ c_parser_unary_expression (c_parser *parser)
	 
	 /* Parse a sizeof expression.  */
	 
	+static inline struct c_expr
	+c_parser_sizeof_expression (c_parser *parser)
	+{
	+  return c_parser_sizeof_or_countof_expression (parser, RID_SIZEOF);
	+}
	+
	+/* Parse a _Countof expression.  */
	+
	+static inline struct c_expr
	+c_parser_countof_expression (c_parser *parser)
	+{
	+  return c_parser_sizeof_or_countof_expression (parser, RID_COUNTOF);
	+}
	+
	+/* Parse a sizeof or _Countof expression.  */
	+
	 static struct c_expr
	 c_parser_sizeof_or_countof_expression (c_parser *parser, enum rid rid)
	 {


Cheers,
Alex

-- 
<https://www.alejandro-colomar.es/>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 318+ messages in thread

* Re: [PATCH v24 1/3] c: Add _Countof operator
  2025-05-21 21:44           ` Alejandro Colomar
@ 2025-05-21 21:47             ` Jakub Jelinek
  2025-05-21 21:56               ` Alejandro Colomar
  0 siblings, 1 reply; 318+ messages in thread
From: Jakub Jelinek @ 2025-05-21 21:47 UTC (permalink / raw)
  To: Alejandro Colomar
  Cc: gcc-patches, Martin Uecker, JeanHeyd Meneide, Joseph Myers,
	Xavier Del Campo Romero, James K. Lowden

On Wed, May 21, 2025 at 11:44:42PM +0200, Alejandro Colomar wrote:
> Does this sound good?
> 
> 	diff --git i/gcc/c/c-parser.cc w/gcc/c/c-parser.cc
> 	index faa03c4903a2..733cb312341e 100644
> 	--- i/gcc/c/c-parser.cc
> 	+++ w/gcc/c/c-parser.cc
> 	@@ -78,16 +78,6 @@ along with GCC; see the file COPYING3.  If not see
> 	 #include "c-family/c-ubsan.h"
> 	 #include "gcc-urlifier.h"
> 	 ^L
> 	-#define c_parser_sizeof_expression(parser)                                    \
> 	-(                                                                             \
> 	-  c_parser_sizeof_or_countof_expression (parser, RID_SIZEOF)                  \
> 	-)
> 	-
> 	-#define c_parser_countof_expression(parser)                                   \
> 	-(                                                                             \
> 	-  c_parser_sizeof_or_countof_expression (parser, RID_COUNTOF)                 \
> 	-)
> 	-^L
> 	 /* 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
> 	@@ -1747,6 +1737,8 @@ 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 inline struct c_expr c_parser_sizeof_expression (c_parser *);
> 	+static inline struct c_expr c_parser_countof_expression (c_parser *);

I don't see the point of the above (unless they are defined after first
use, but then it would be better to define them before the first use).

> 	 static struct c_expr c_parser_sizeof_or_countof_expression (c_parser *,
> 								    enum rid);
> 	 static struct c_expr c_parser_alignof_expression (c_parser *);
> 	@@ -10627,6 +10619,22 @@ c_parser_unary_expression (c_parser *parser)
> 	 
> 	 /* Parse a sizeof expression.  */
> 	 
> 	+static inline struct c_expr
> 	+c_parser_sizeof_expression (c_parser *parser)
> 	+{
> 	+  return c_parser_sizeof_or_countof_expression (parser, RID_SIZEOF);
> 	+}
> 	+
> 	+/* Parse a _Countof expression.  */
> 	+
> 	+static inline struct c_expr
> 	+c_parser_countof_expression (c_parser *parser)
> 	+{
> 	+  return c_parser_sizeof_or_countof_expression (parser, RID_COUNTOF);
> 	+}
> 	+
> 	+/* Parse a sizeof or _Countof expression.  */
> 	+

This looks good to me (but Joseph or Marek should have the final say in C
FE).

	Jakub


^ permalink raw reply	[flat|nested] 318+ messages in thread

* Re: [PATCH v24 1/3] c: Add _Countof operator
  2025-05-21 21:47             ` Jakub Jelinek
@ 2025-05-21 21:56               ` Alejandro Colomar
  0 siblings, 0 replies; 318+ messages in thread
From: Alejandro Colomar @ 2025-05-21 21:56 UTC (permalink / raw)
  To: Jakub Jelinek
  Cc: gcc-patches, Martin Uecker, JeanHeyd Meneide, Joseph Myers,
	Xavier Del Campo Romero, James K. Lowden

[-- Attachment #1: Type: text/plain, Size: 1900 bytes --]

Hi Jakub,

On Wed, May 21, 2025 at 11:47:30PM +0200, Jakub Jelinek wrote:
> > 	@@ -1747,6 +1737,8 @@ 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 inline struct c_expr c_parser_sizeof_expression (c_parser *);
> > 	+static inline struct c_expr c_parser_countof_expression (c_parser *);
> 
> I don't see the point of the above (unless they are defined after first
> use,

They are indeed defined after first use.

> but then it would be better to define them before the first use).

Moving them before the first use would separate them from
c_parser_sizeof_or_countof_expression(), which is their closest
relative.  I find them more organized this way.  Please confirm what I
should do.


Cheers,
Alex

> 
> > 	 static struct c_expr c_parser_sizeof_or_countof_expression (c_parser *,
> > 								    enum rid);
> > 	 static struct c_expr c_parser_alignof_expression (c_parser *);
> > 	@@ -10627,6 +10619,22 @@ c_parser_unary_expression (c_parser *parser)
> > 	 
> > 	 /* Parse a sizeof expression.  */
> > 	 
> > 	+static inline struct c_expr
> > 	+c_parser_sizeof_expression (c_parser *parser)
> > 	+{
> > 	+  return c_parser_sizeof_or_countof_expression (parser, RID_SIZEOF);
> > 	+}
> > 	+
> > 	+/* Parse a _Countof expression.  */
> > 	+
> > 	+static inline struct c_expr
> > 	+c_parser_countof_expression (c_parser *parser)
> > 	+{
> > 	+  return c_parser_sizeof_or_countof_expression (parser, RID_COUNTOF);
> > 	+}
> > 	+
> > 	+/* Parse a sizeof or _Countof expression.  */
> > 	+
> 
> This looks good to me (but Joseph or Marek should have the final say in C
> FE).
> 
> 	Jakub
> 

-- 
<https://www.alejandro-colomar.es/>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 318+ messages in thread

* [PATCH v25 0/3] c: Add _Countof and <stdcountof.h>
  2024-07-28 14:15 ` [RFC v1 0/2] c: Add _Lengthof operator Alejandro Colomar
                     ` (27 preceding siblings ...)
  2025-05-21 21:01   ` [PATCH v24 " Alejandro Colomar
@ 2025-05-21 23:15   ` Alejandro Colomar
  2025-05-21 23:15     ` [PATCH v25 1/3] c: Add _Countof operator Alejandro Colomar
                       ` (3 more replies)
  28 siblings, 4 replies; 318+ messages in thread
From: Alejandro Colomar @ 2025-05-21 23:15 UTC (permalink / raw)
  To: gcc-patches
  Cc: Alejandro Colomar, Martin Uecker, JeanHeyd Meneide, Joseph Myers,
	Jakub Jelinek

Hi!

Here's v25.  Changes compared to v24 (see range-diff below):

-  Small fixes to the change logs.
-  Rewrap and remove parentheses in chains of ?: .
-  Implement c_parser_{sizeof,countof}_expression() as static inline.

Tests still pass:

	$ grep countof ./gcc/testsuite/gcc/gcc.sum
	PASS: gcc.dg/countof-compat.c  (test for warnings, line 8)
	PASS: gcc.dg/countof-compat.c (test for excess errors)
	PASS: gcc.dg/countof-compile.c  (test for errors, line 114)
	PASS: gcc.dg/countof-compile.c  (test for errors, line 123)
	PASS: gcc.dg/countof-compile.c  (test for errors, line 23)
	PASS: gcc.dg/countof-compile.c  (test for errors, line 27)
	PASS: gcc.dg/countof-compile.c  (test for errors, line 38)
	PASS: gcc.dg/countof-compile.c  (test for errors, line 46)
	PASS: gcc.dg/countof-compile.c  (test for errors, line 64)
	PASS: gcc.dg/countof-compile.c  (test for errors, line 67)
	PASS: gcc.dg/countof-compile.c  (test for errors, line 70)
	PASS: gcc.dg/countof-compile.c  (test for errors, line 82)
	PASS: gcc.dg/countof-compile.c  (test for errors, line 83)
	PASS: gcc.dg/countof-compile.c  (test for errors, line 84)
	PASS: gcc.dg/countof-compile.c  (test for errors, line 85)
	PASS: gcc.dg/countof-compile.c  (test for errors, line 86)
	PASS: gcc.dg/countof-compile.c  (test for errors, line 87)
	PASS: gcc.dg/countof-compile.c  (test for errors, line 88)
	PASS: gcc.dg/countof-compile.c  (test for errors, line 89)
	PASS: gcc.dg/countof-compile.c  (test for errors, line 90)
	PASS: gcc.dg/countof-compile.c  (test for errors, line 94)
	PASS: gcc.dg/countof-compile.c (test for excess errors)
	PASS: gcc.dg/countof-no-compat.c (test for excess errors)
	PASS: gcc.dg/countof-pedantic-errors.c  (test for errors, line 8)
	PASS: gcc.dg/countof-pedantic-errors.c (test for excess errors)
	PASS: gcc.dg/countof-pedantic.c  (test for warnings, line 8)
	PASS: gcc.dg/countof-pedantic.c (test for excess errors)
	PASS: gcc.dg/countof-stdcountof.c (test for excess errors)
	PASS: gcc.dg/countof-stdcountof.c execution test
	PASS: gcc.dg/countof-vla.c (test for excess errors)
	PASS: gcc.dg/countof-vmt.c (test for excess errors)
	PASS: gcc.dg/countof-vmt.c execution test
	PASS: gcc.dg/countof-zero-compile.c (test for excess errors)
	PASS: gcc.dg/countof-zero.c (test for excess errors)
	PASS: gcc.dg/countof-zero.c execution test
	PASS: gcc.dg/countof.c (test for excess errors)
	PASS: gcc.dg/countof.c execution test


Have a lovely night!
Alex


Alejandro Colomar (3):
  c: Add _Countof operator
  c: Add <stdcountof.h>
  c: Add -Wpedantic diagnostic for _Countof

 gcc/Makefile.in                               |   1 +
 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                               |  24 ++--
 gcc/c/c-parser.cc                             |  77 ++++++++---
 gcc/c/c-tree.h                                |   4 +
 gcc/c/c-typeck.cc                             | 115 +++++++++++++++-
 gcc/doc/extend.texi                           |  30 +++++
 gcc/ginclude/stdcountof.h                     |  31 +++++
 gcc/testsuite/gcc.dg/countof-compat.c         |   8 ++
 gcc/testsuite/gcc.dg/countof-compile.c        | 124 ++++++++++++++++++
 gcc/testsuite/gcc.dg/countof-no-compat.c      |   5 +
 .../gcc.dg/countof-pedantic-errors.c          |   8 ++
 gcc/testsuite/gcc.dg/countof-pedantic.c       |   8 ++
 gcc/testsuite/gcc.dg/countof-stdcountof.c     |  24 ++++
 gcc/testsuite/gcc.dg/countof-vla.c            |  35 +++++
 gcc/testsuite/gcc.dg/countof-vmt.c            |  20 +++
 gcc/testsuite/gcc.dg/countof-zero-compile.c   |  38 ++++++
 gcc/testsuite/gcc.dg/countof-zero.c           |  31 +++++
 gcc/testsuite/gcc.dg/countof.c                | 120 +++++++++++++++++
 21 files changed, 705 insertions(+), 29 deletions(-)
 create mode 100644 gcc/ginclude/stdcountof.h
 create mode 100644 gcc/testsuite/gcc.dg/countof-compat.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-compile.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-no-compat.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-pedantic-errors.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-pedantic.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-stdcountof.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-vla.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-vmt.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-zero-compile.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-zero.c
 create mode 100644 gcc/testsuite/gcc.dg/countof.c

Range-diff against v24:
1:  1ac81ab0d3dc ! 1:  a3fb6089a388 c: Add _Countof operator
    @@ Commit message
     
         gcc/c-family/ChangeLog:
     
    -            * c-common.h: Add RID_COUNTOF.
    +            * c-common.h (enum rid): Add RID_COUNTOF.
                 (c_countof_type): New function prototype.
                 * c-common.def (COUNTOF_EXPR): New tree.
    -            * c-common.cc
    -            (c_common_reswords): Add RID_COUNTOF entry.
    +            * c-common.cc (c_common_reswords): Add RID_COUNTOF entry.
                 (c_countof_type): New function.
     
         gcc/c/ChangeLog:
     
    -            * c-tree.h
    -            (in_countof): Add global variable declaration.
    +            * c-tree.h (in_countof): Add global variable declaration.
                 (c_expr_countof_expr): Add function prototype.
                 (c_expr_countof_type): Add function prototype.
    -            * c-decl.cc
    -            (start_struct, finish_struct): Add support for _Countof.
    +            * c-decl.cc (start_struct, finish_struct): Add support for
    +            _Countof.
                 (start_enum, finish_enum): Add support for _Countof.
    -            * c-parser.cc
    -            (c_parser_sizeof_expression): New macro.
    +            * c-parser.cc (c_parser_sizeof_expression): New macro.
                 (c_parser_countof_expression): New macro.
    -            (c_parser_sizeof_or_countof_expression):
    -            Rename function and add support for _Countof.
    +            (c_parser_sizeof_or_countof_expression): Rename function and add
    +            support for _Countof.
                 (c_parser_unary_expression): Add RID_COUNTOF entry.
    -            * c-typeck.cc
    -            (in_countof): Add global variable.
    +            * c-typeck.cc (in_countof): Add global variable.
                 (build_external_ref): Add support for _Countof.
                 (record_maybe_used_decl): Add support for _Countof.
                 (pop_maybe_used): Add support for _Countof.
                 (is_top_array_vla): New function.
                 (c_expr_countof_expr, c_expr_countof_type): New functions.
    -            Add _Countof operator.
     
         gcc/testsuite/ChangeLog:
     
    -            * gcc.dg/countof-compile.c: Compile-time tests for _Countof.
    -            * gcc.dg/countof-vla.c: Tests for _Countof with VLAs.
    -            * gcc.dg/countof-vmt.c: Tests for _Countof with other VMTs.
    -            * gcc.dg/countof-zero-compile.c:
    -            Compile-time tests for _Countof with zero-sized arrays.
    -            * gcc.dg/countof-zero.c:
    -            Tests for _Countof with zero-sized arrays.
    -            * gcc.dg/countof.c: Tests for _Countof.
    +            * gcc.dg/countof-compile.c: New test.
    +            * gcc.dg/countof-vla.c: New test.
    +            * gcc.dg/countof-vmt.c: New test.
    +            * gcc.dg/countof-zero-compile.c: New test.
    +            * gcc.dg/countof-zero.c: New test.
    +            * gcc.dg/countof.c: New test.
     
         Suggested-by: Xavier Del Campo Romero <xavi.dcr@tutanota.com>
         Co-authored-by: Martin Uecker <uecker@tugraz.at>
    @@ gcc/c/c-decl.cc: start_struct (location_t loc, enum tree_code code, tree name,
     +      && (in_sizeof || in_typeof || in_alignof || in_countof))
          warning_at (loc, OPT_Wc___compat,
      		"defining type in %qs expression is invalid in C++",
    - 		(in_sizeof
    - 		 ? "sizeof"
    +-		(in_sizeof
    +-		 ? "sizeof"
     -		 : (in_typeof ? "typeof" : "alignof")));
    -+		 : (in_typeof
    -+		    ? "typeof"
    -+		    : (in_alignof
    -+		       ? "alignof"
    -+		       : "_Countof"))));
    ++		(in_sizeof ? "sizeof"
    ++		 : in_typeof ? "typeof"
    ++		 : in_alignof ? "alignof"
    ++		 : "_Countof"));
      
        if (in_underspecified_init)
          error_at (loc, "%qT defined in underspecified object initializer", ref);
    @@ gcc/c/c-decl.cc: start_enum (location_t loc, struct c_enum_contents *the_enum, t
     +      && (in_sizeof || in_typeof || in_alignof || in_countof))
          warning_at (loc, OPT_Wc___compat,
      		"defining type in %qs expression is invalid in C++",
    - 		(in_sizeof
    - 		 ? "sizeof"
    +-		(in_sizeof
    +-		 ? "sizeof"
     -		 : (in_typeof ? "typeof" : "alignof")));
    -+		 : (in_typeof
    -+		    ? "typeof"
    -+		    : (in_alignof
    -+		       ? "alignof"
    -+		       : "_Countof"))));
    ++		(in_sizeof ? "sizeof"
    ++		 : in_typeof ? "typeof"
    ++		 : in_alignof ? "alignof"
    ++		 : "_Countof"));
      
        if (in_underspecified_init)
          error_at (loc, "%qT defined in underspecified object initializer",
    @@ gcc/c/c-parser.cc: along with GCC; see the file COPYING3.  If not see
      #include "asan.h"
      #include "c-family/c-ubsan.h"
      #include "gcc-urlifier.h"
    -+\f
    -+#define c_parser_sizeof_expression(parser)                                    \
    -+(                                                                             \
    -+  c_parser_sizeof_or_countof_expression (parser, RID_SIZEOF)                  \
    -+)
    - 
    -+#define c_parser_countof_expression(parser)                                   \
    -+(                                                                             \
    -+  c_parser_sizeof_or_countof_expression (parser, RID_COUNTOF)                 \
    -+)
    +-
     +\f
      /* We need to walk over decls with incomplete struct/union/enum types
         after parsing the whole translation unit.
    @@ gcc/c/c-parser.cc: static struct c_expr c_parser_binary_expression (c_parser *,
      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 inline struct c_expr c_parser_sizeof_expression (c_parser *);
    ++static inline struct c_expr c_parser_countof_expression (c_parser *);
     +static struct c_expr c_parser_sizeof_or_countof_expression (c_parser *,
     +							    enum rid);
      static struct c_expr c_parser_alignof_expression (c_parser *);
    @@ gcc/c/c-parser.cc: c_parser_unary_expression (c_parser *parser)
      	  return c_parser_sizeof_expression (parser);
      	case RID_ALIGNOF:
     @@ gcc/c/c-parser.cc: 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_countof_expression (c_parser *parser, enum rid rid)
    +-static struct c_expr
    ++static inline struct c_expr
    + c_parser_sizeof_expression (c_parser *parser)
      {
    ++  return c_parser_sizeof_or_countof_expression (parser, RID_SIZEOF);
    ++}
    ++
    ++/* Parse a _Countof expression.  */
    ++
    ++static inline struct c_expr
    ++c_parser_countof_expression (c_parser *parser)
    ++{
    ++  return c_parser_sizeof_or_countof_expression (parser, RID_COUNTOF);
    ++}
    ++
    ++/* Parse a sizeof or _Countof expression.  */
    ++
    ++static struct c_expr
    ++c_parser_sizeof_or_countof_expression (c_parser *parser, enum rid rid)
    ++{
     +  const char *op_name = (rid == RID_COUNTOF) ? "_Countof" : "sizeof";
        struct c_expr expr;
        struct c_expr result;
2:  b9e8bed2de2b ! 2:  bad376570c9a c: Add <stdcountof.h>
    @@ Commit message
         gcc/ChangeLog:
     
                 * Makefile.in (USER_H): Add <stdcountof.h>.
    -            * ginclude/stdcountof.h: Add countof macro.
    +            * ginclude/stdcountof.h: New file.
     
         gcc/testsuite/ChangeLog:
     
    -            * gcc.dg/countof-stdcountof.c: Add tests for <stdcountof.h>.
    +            * gcc.dg/countof-stdcountof.c: New test.
     
         Signed-off-by: Alejandro Colomar <alx@kernel.org>
     
3:  264c87d60157 ! 3:  85de63d37f8d c: Add -Wpedantic diagnostic for _Countof
    @@ Commit message
     
         gcc/testsuite/ChangeLog:
     
    -            * gcc.dg/countof-compat.c:
    -            Test _Countof diagnostics with -Wc23-c2y-compat on C2y.
    -            * gcc.dg/countof-no-compat.c:
    -            Test _Countof diagnostics with -Wno-c23-c2y-compat on C23.
    -            * gcc.dg/countof-pedantic.c:
    -            Test _Countof diagnostics with -pedantic on C23.
    -            * gcc.dg/countof-pedantic-errors.c:
    -            Test _Countof diagnostics with -pedantic-errors on C23.
    +            * gcc.dg/countof-compat.c: New test.
    +            * gcc.dg/countof-no-compat.c: New test.
    +            * gcc.dg/countof-pedantic.c: New test.
    +            * gcc.dg/countof-pedantic-errors.c: New test.
     
         Signed-off-by: Alejandro Colomar <alx@kernel.org>
     

base-commit: 90c6ccebd762ae920690fce20cd3f2b8e24357a7
-- 
2.49.0


^ permalink raw reply	[flat|nested] 318+ messages in thread

* [PATCH v25 1/3] c: Add _Countof operator
  2025-05-21 23:15   ` [PATCH v25 0/3] c: Add _Countof and <stdcountof.h> Alejandro Colomar
@ 2025-05-21 23:15     ` Alejandro Colomar
  2025-05-28  9:35       ` Sam James
  2025-05-21 23:15     ` [PATCH v25 2/3] c: Add <stdcountof.h> Alejandro Colomar
                       ` (2 subsequent siblings)
  3 siblings, 1 reply; 318+ messages in thread
From: Alejandro Colomar @ 2025-05-21 23:15 UTC (permalink / raw)
  To: gcc-patches
  Cc: Alejandro Colomar, Martin Uecker, JeanHeyd Meneide, Joseph Myers,
	Jakub Jelinek, Xavier Del Campo Romero, James K. Lowden

This operator is similar to sizeof but can only be applied to an array,
and returns its number of elements.

FUTURE DIRECTIONS:

-  We should make it work with array parameters to functions,
   and somehow magically return the number of elements of the array,
   regardless of it being really a pointer.

Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3550.pdf>
Link: <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117025>
Link: <https://inbox.sourceware.org/gcc/M8S4oQy--3-2@tutanota.com/T/>
Link: <https://inbox.sourceware.org/gcc-patches/20240728141547.302478-1-alx@kernel.org/T/#t>
Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3313.pdf>
Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3325.pdf>
Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3369.pdf>
Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3469.htm>
Link: <https://github.com/llvm/llvm-project/issues/102836>
Link: <https://thephd.dev/the-big-array-size-survey-for-c>
Link: <https://thephd.dev/the-big-array-size-survey-for-c-results>
Link: <https://stackoverflow.com/questions/37538/#57537491>

gcc/ChangeLog:

	* doc/extend.texi: Document _Countof operator.

gcc/c-family/ChangeLog:

	* c-common.h (enum rid): Add RID_COUNTOF.
	(c_countof_type): New function prototype.
	* c-common.def (COUNTOF_EXPR): New tree.
	* c-common.cc (c_common_reswords): Add RID_COUNTOF entry.
	(c_countof_type): New function.

gcc/c/ChangeLog:

	* c-tree.h (in_countof): Add global variable declaration.
	(c_expr_countof_expr): Add function prototype.
	(c_expr_countof_type): Add function prototype.
	* c-decl.cc (start_struct, finish_struct): Add support for
	_Countof.
	(start_enum, finish_enum): Add support for _Countof.
	* c-parser.cc (c_parser_sizeof_expression): New macro.
	(c_parser_countof_expression): New macro.
	(c_parser_sizeof_or_countof_expression): Rename function and add
	support for _Countof.
	(c_parser_unary_expression): Add RID_COUNTOF entry.
	* c-typeck.cc (in_countof): Add global variable.
	(build_external_ref): Add support for _Countof.
	(record_maybe_used_decl): Add support for _Countof.
	(pop_maybe_used): Add support for _Countof.
	(is_top_array_vla): New function.
	(c_expr_countof_expr, c_expr_countof_type): New functions.

gcc/testsuite/ChangeLog:

	* gcc.dg/countof-compile.c: New test.
	* gcc.dg/countof-vla.c: New test.
	* gcc.dg/countof-vmt.c: New test.
	* gcc.dg/countof-zero-compile.c: New test.
	* gcc.dg/countof-zero.c: New test.
	* gcc.dg/countof.c: New test.

Suggested-by: Xavier Del Campo Romero <xavi.dcr@tutanota.com>
Co-authored-by: Martin Uecker <uecker@tugraz.at>
Acked-by: "James K. Lowden" <jklowden@schemamania.org>
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                             |  24 ++--
 gcc/c/c-parser.cc                           |  73 +++++++++---
 gcc/c/c-tree.h                              |   4 +
 gcc/c/c-typeck.cc                           | 115 +++++++++++++++++-
 gcc/doc/extend.texi                         |  30 +++++
 gcc/testsuite/gcc.dg/countof-compile.c      | 124 ++++++++++++++++++++
 gcc/testsuite/gcc.dg/countof-vla.c          |  35 ++++++
 gcc/testsuite/gcc.dg/countof-vmt.c          |  20 ++++
 gcc/testsuite/gcc.dg/countof-zero-compile.c |  38 ++++++
 gcc/testsuite/gcc.dg/countof-zero.c         |  31 +++++
 gcc/testsuite/gcc.dg/countof.c              | 120 +++++++++++++++++++
 14 files changed, 616 insertions(+), 29 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/countof-compile.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-vla.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-vmt.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-zero-compile.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-zero.c
 create mode 100644 gcc/testsuite/gcc.dg/countof.c

diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
index 587d76461e9e..f71cb2652d5a 100644
--- a/gcc/c-family/c-common.cc
+++ b/gcc/c-family/c-common.cc
@@ -394,6 +394,7 @@ const struct c_common_resword c_common_reswords[] =
 {
   { "_Alignas",		RID_ALIGNAS,   D_CONLY },
   { "_Alignof",		RID_ALIGNOF,   D_CONLY },
+  { "_Countof",		RID_COUNTOF,   D_CONLY },
   { "_Atomic",		RID_ATOMIC,    D_CONLY },
   { "_BitInt",		RID_BITINT,    D_CONLY },
   { "_Bool",		RID_BOOL,      D_CONLY },
@@ -4080,6 +4081,31 @@ c_alignof_expr (location_t loc, tree expr)
 
   return fold_convert_loc (loc, size_type_node, t);
 }
+
+/* Implement the _Countof keyword:
+   Return the number of elements of an array.  */
+
+tree
+c_countof_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 %<_Countof%> to type %qT", type);
+      return error_mark_node;
+    }
+  if (!COMPLETE_TYPE_P (type))
+    {
+      error_at (loc,
+		"invalid application of %<_Countof%> 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 cf2228201fad..0bcc4998afe6 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 'countof' expression.  */
+DEFTREECODE (COUNTOF_EXPR, "countof_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 ea6c29750567..91fd120e77e1 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_COUNTOF,
   RID_C23_VA_START, RID_VA_ARG,
   RID_EXTENSION, RID_IMAGPART, RID_REALPART, RID_LABEL,    RID_CHOOSE_EXPR,
   RID_TYPES_COMPATIBLE_P,      RID_BUILTIN_COMPLEX,	   RID_BUILTIN_SHUFFLE,
@@ -890,6 +891,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_countof_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 ad66d7d258b8..33d0ec1b88ff 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -8943,12 +8943,14 @@ 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_countof))
     warning_at (loc, OPT_Wc___compat,
 		"defining type in %qs expression is invalid in C++",
-		(in_sizeof
-		 ? "sizeof"
-		 : (in_typeof ? "typeof" : "alignof")));
+		(in_sizeof ? "sizeof"
+		 : in_typeof ? "typeof"
+		 : in_alignof ? "alignof"
+		 : "_Countof"));
 
   if (in_underspecified_init)
     error_at (loc, "%qT defined in underspecified object initializer", ref);
@@ -9923,7 +9925,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_countof)
 	struct_parse_info->struct_types.safe_push (t);
      }
 
@@ -10097,12 +10099,14 @@ 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_countof))
     warning_at (loc, OPT_Wc___compat,
 		"defining type in %qs expression is invalid in C++",
-		(in_sizeof
-		 ? "sizeof"
-		 : (in_typeof ? "typeof" : "alignof")));
+		(in_sizeof ? "sizeof"
+		 : in_typeof ? "typeof"
+		 : in_alignof ? "alignof"
+		 : "_Countof"));
 
   if (in_underspecified_init)
     error_at (loc, "%qT defined in underspecified object initializer",
@@ -10296,7 +10300,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_countof)
     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 8a63dc54c795..733cb312341e 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -77,7 +77,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "asan.h"
 #include "c-family/c-ubsan.h"
 #include "gcc-urlifier.h"
-
+\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
@@ -1737,7 +1737,10 @@ 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 inline struct c_expr c_parser_sizeof_expression (c_parser *);
+static inline struct c_expr c_parser_countof_expression (c_parser *);
+static struct c_expr c_parser_sizeof_or_countof_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 *,
@@ -10452,9 +10455,13 @@ c_parser_cast_expression (c_parser *parser, struct c_expr *after)
      ++ unary-expression
      -- unary-expression
      unary-operator cast-expression
+     _Countof unary-expression
+     _Countof ( type-name )
      sizeof unary-expression
      sizeof ( type-name )
 
+   (_Countof is new in C2y.)
+
    unary-operator: one of
      & * + - ~ !
 
@@ -10572,6 +10579,8 @@ c_parser_unary_expression (c_parser *parser)
     case CPP_KEYWORD:
       switch (c_parser_peek_token (parser)->keyword)
 	{
+	case RID_COUNTOF:
+	  return c_parser_countof_expression (parser);
 	case RID_SIZEOF:
 	  return c_parser_sizeof_expression (parser);
 	case RID_ALIGNOF:
@@ -10610,13 +10619,30 @@ c_parser_unary_expression (c_parser *parser)
 
 /* Parse a sizeof expression.  */
 
-static struct c_expr
+static inline struct c_expr
 c_parser_sizeof_expression (c_parser *parser)
 {
+  return c_parser_sizeof_or_countof_expression (parser, RID_SIZEOF);
+}
+
+/* Parse a _Countof expression.  */
+
+static inline struct c_expr
+c_parser_countof_expression (c_parser *parser)
+{
+  return c_parser_sizeof_or_countof_expression (parser, RID_COUNTOF);
+}
+
+/* Parse a sizeof or _Countof expression.  */
+
+static struct c_expr
+c_parser_sizeof_or_countof_expression (c_parser *parser, enum rid rid)
+{
+  const char *op_name = (rid == RID_COUNTOF) ? "_Countof" : "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;
@@ -10625,7 +10651,10 @@ c_parser_sizeof_expression (c_parser *parser)
 
   c_parser_consume_token (parser);
   c_inhibit_evaluation_warnings++;
-  in_sizeof++;
+  if (rid == RID_COUNTOF)
+    in_countof++;
+  else
+    in_sizeof++;
   if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)
       && c_token_starts_compound_literal (c_parser_peek_2nd_token (parser)))
     {
@@ -10646,7 +10675,7 @@ c_parser_sizeof_expression (c_parser *parser)
 	     for parsing error; the parsing of the expression could have
 	     called record_maybe_used_decl.  */
 	  expr.set_error ();
-	  goto sizeof_expr;
+	  goto Xof_expr;
 	}
       if (c_parser_next_token_is (parser, CPP_OPEN_BRACE))
 	{
@@ -10654,31 +10683,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_COUNTOF)
+	{
+	  in_countof--;
+	  result = c_expr_countof_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_COUNTOF)
+	in_countof--;
+      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_COUNTOF)
+	result = c_expr_countof_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 2098120de297..723a28b39069 100644
--- a/gcc/c/c-tree.h
+++ b/gcc/c/c-tree.h
@@ -765,6 +765,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_countof;
 extern int in_typeof;
 extern bool c_in_omp_for;
 extern bool c_omp_array_section_p;
@@ -827,6 +828,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_countof_expr (location_t, struct c_expr);
+extern struct c_expr c_expr_countof_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 0e1f842e22d3..360216b96621 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -72,6 +72,9 @@ int in_alignof;
 /* The level of nesting inside "sizeof".  */
 int in_sizeof;
 
+/* The level of nesting inside "countof".  */
+int in_countof;
+
 /* The level of nesting inside "typeof".  */
 int in_typeof;
 
@@ -3540,7 +3543,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_countof)
 	C_DECL_USED (ref) = 1;
       else if (DECL_INITIAL (ref) == NULL_TREE
 	       && DECL_EXTERNAL (ref)
@@ -3596,7 +3599,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_countof).  */
   int level;
   /* The next one at this level or above, or NULL.  */
   struct maybe_used_decl *next;
@@ -3614,7 +3617,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_countof;
   t->next = maybe_used_decls;
   maybe_used_decls = t;
 }
@@ -3628,7 +3631,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_countof;
   while (p && p->level > cur_level)
     {
       if (used)
@@ -3738,6 +3741,110 @@ 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);
+  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 countof applied to EXPR.  */
+
+struct c_expr
+c_expr_countof_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_countof_type (loc, TREE_TYPE (folded_expr));
+      c_last_sizeof_arg = expr.value;
+      c_last_sizeof_loc = loc;
+      ret.original_code = COUNTOF_EXPR;
+      ret.original_type = NULL;
+      ret.m_decimal = 0;
+      if (is_top_array_vla (TREE_TYPE (folded_expr)))
+	{
+	  /* countof 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 countof applied to T, a structure for the type
+   name passed to countof (rather than the type itself).  LOC is the
+   location of the original expression.  */
+
+struct c_expr
+c_expr_countof_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_countof_type (loc, type);
+  c_last_sizeof_arg = type;
+  c_last_sizeof_loc = loc;
+  ret.original_code = COUNTOF_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 countof does not get folded to a constant by
+	 c_fully_fold, because if the number of elements is evaluated
+	 the result is not constant and so
+	 constraints on zero or negative size arrays must not be applied
+	 when this countof 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/doc/extend.texi b/gcc/doc/extend.texi
index 40ccf22b29f4..18ee287a3480 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -10706,6 +10706,36 @@ library.
 @xref{OpenMP and OpenACC Options}, for additional options useful with
 @option{-fopenacc}.
 
+@node _Countof
+@section Determining the Number of Elements of Arrays
+@cindex _Countof
+@cindex number of elements
+
+The keyword @code{_Countof} determines
+the number of elements of an array operand.
+Its syntax is similar to @code{sizeof}.
+The operand must be
+a parenthesized complete array type name
+or an expression of such a type.
+For example:
+
+@smallexample
+int a[n];
+_Countof (a);  // returns n
+_Countof (int [7][3]);  // returns 7
+@end smallexample
+
+The result of this operator is an integer constant expression,
+unless the array has a variable number of elements.
+The operand is only evaluated
+if the array has a variable number of elements.
+For example:
+
+@smallexample
+_Countof (int [7][n++]);  // integer constant expression
+_Countof (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/testsuite/gcc.dg/countof-compile.c b/gcc/testsuite/gcc.dg/countof-compile.c
new file mode 100644
index 000000000000..afd5659618b4
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/countof-compile.c
@@ -0,0 +1,124 @@
+/* { dg-do compile } */
+/* { dg-options "-std=c2y -pedantic-errors" } */
+
+#define NULL  ((void *) 0)
+
+extern int x[];
+
+static int w[] = {1, 2, 3};
+
+void
+completed (void)
+{
+  int i = 42;
+  int a[] = {1, 2, i};
+
+  _Static_assert(_Countof (w) == 3);
+  _Static_assert(_Countof (a) == 3);
+}
+
+void
+incomplete (int p[])
+{
+  _Countof (x);  /* { dg-error "incomplete" } */
+
+  /* We want to support array parameters in the future,
+     which should change this from "invalid" to "incomplete".  */
+  _Countof (p);  /* { dg-error "invalid" } */
+}
+
+void
+fam (void)
+{
+  struct {
+    int x;
+    int fam[];
+  } s;
+
+  _Countof (s.fam); /* { dg-error "incomplete" } */
+}
+
+void
+param (int n, int p[n])
+{
+  /* We want to support array parameters in the future,
+     which would make this work.  */
+  _Countof (p);  /* { dg-error "invalid" } */
+}
+
+void fix_fix (int i, char (*a)[3][5], int (*x)[_Countof (*a)],
+	      short (*)[_Generic(x, int (*)[3]: 1)]);
+void fix_var (int i, char (*a)[3][i], int (*x)[_Countof (*a)],
+	      short (*)[_Generic(x, int (*)[3]: 1)]);
+void fix_uns (int i, char (*a)[3][*], int (*x)[_Countof (*a)],
+	      short (*)[_Generic(x, int (*)[3]: 1)]);
+
+void
+func (void)
+{
+  int  i3[3];
+  int  i5[5];
+  char c35[3][5];
+
+  fix_fix (5, &c35, &i3, NULL);
+  fix_fix (5, &c35, &i5, NULL); /* { dg-error "incompatible-pointer-types" } */
+
+  fix_var (5, &c35, &i3, NULL);
+  fix_var (5, &c35, &i5, NULL); /* { dg-error "incompatible-pointer-types" } */
+
+  fix_uns (5, &c35, &i3, NULL);
+  fix_uns (5, &c35, &i5, NULL); /* { dg-error "incompatible-pointer-types" } */
+}
+
+void
+non_arr(void)
+{
+  int x;
+  int *p;
+  struct s {
+    int x[3];
+  } s;
+
+  _Countof (x); /* { dg-error "invalid" } */
+  _Countof (int); /* { dg-error "invalid" } */
+  _Countof (s); /* { dg-error "invalid" } */
+  _Countof (struct s); /* { dg-error "invalid" } */
+  _Countof (&x); /* { dg-error "invalid" } */
+  _Countof (p); /* { dg-error "invalid" } */
+  _Countof (int *); /* { dg-error "invalid" } */
+  _Countof (&s.x); /* { dg-error "invalid" } */
+  _Countof (int (*)[3]); /* { dg-error "invalid" } */
+}
+
+static int f1();
+static int f2(); /* { dg-error "never defined" } */
+int a[10][9];
+int n;
+
+void
+syms(void)
+{
+  int b[n][n];
+
+  _Countof (a[f1()]);
+  _Countof (b[f2()]);
+}
+
+void
+no_parens(void)
+{
+  _Static_assert(_Countof a == 10);
+  _Static_assert(_Countof *a == 9);
+  _Static_assert(_Countof (int [3]) {} == 3);
+
+  _Countof int [3]; /* { dg-error "expected expression before" } */
+}
+
+void
+const_expr(void)
+{
+  int n = 7;
+
+  _Static_assert (_Countof (int [3][n]) == 3);
+  _Static_assert (_Countof (int [n][3]) == 7); /* { dg-error "not constant" } */
+}
diff --git a/gcc/testsuite/gcc.dg/countof-vla.c b/gcc/testsuite/gcc.dg/countof-vla.c
new file mode 100644
index 000000000000..cc225df20689
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/countof-vla.c
@@ -0,0 +1,35 @@
+/* { dg-do compile } */
+/* { dg-options "-std=c2y -pedantic-errors -Wvla-parameter" } */
+
+void fix_fix (int i,
+	      char (*a)[3][5],
+	      int (*x)[_Countof (*a)],
+	      short (*)[_Generic(x, int (*)[3]: 1)]);
+void fix_var (int i,
+	      char (*a)[3][i], /* dg-warn "variable" */
+	      int (*x)[_Countof (*a)],
+	      short (*)[_Generic(x, int (*)[3]: 1)]);
+void fix_uns (int i,
+	      char (*a)[3][*],
+	      int (*x)[_Countof (*a)],
+	      short (*)[_Generic(x, int (*)[3]: 1)]);
+
+void var_fix (int i,
+	      char (*a)[i][5], /* dg-warn "variable" */
+	      int (*x)[_Countof (*a)]); /* dg-warn "variable" */
+void var_var (int i,
+	      char (*a)[i][i], /* dg-warn "variable" */
+	      int (*x)[_Countof (*a)]); /* dg-warn "variable" */
+void var_uns (int i,
+	      char (*a)[i][*], /* dg-warn "variable" */
+	      int (*x)[_Countof (*a)]); /* dg-warn "variable" */
+
+void uns_fix (int i,
+	      char (*a)[*][5],
+	      int (*x)[_Countof (*a)]);
+void uns_var (int i,
+	      char (*a)[*][i], /* dg-warn "variable" */
+	      int (*x)[_Countof (*a)]);
+void uns_uns (int i,
+	      char (*a)[*][*],
+	      int (*x)[_Countof (*a)]);
diff --git a/gcc/testsuite/gcc.dg/countof-vmt.c b/gcc/testsuite/gcc.dg/countof-vmt.c
new file mode 100644
index 000000000000..67467b0d2e0f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/countof-vmt.c
@@ -0,0 +1,20 @@
+/* { dg-do run } */
+/* { dg-options "-std=gnu2y" } */
+
+#define assert(e)  ((e) ? (void) 0 : __builtin_abort ())
+
+void
+inner_vla_noeval (void)
+{
+  int i;
+
+  i = 3;
+  static_assert (_Countof (struct {int x[i++];}[3]) == 3);
+  assert (i == 3);
+}
+
+int
+main (void)
+{
+  inner_vla_noeval ();
+}
diff --git a/gcc/testsuite/gcc.dg/countof-zero-compile.c b/gcc/testsuite/gcc.dg/countof-zero-compile.c
new file mode 100644
index 000000000000..b561186166c3
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/countof-zero-compile.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-std=gnu2y" } */
+
+static int z[0];
+static int y[_Countof (z)];
+
+_Static_assert(_Countof (y) == 0);
+
+void
+completed (void)
+{
+  int z[] = {};
+
+  static_assert (_Countof (z) == 0);
+}
+
+void zro_fix (int i,
+	      char (*a)[0][5],
+	      int (*x)[_Countof (*a)],
+	      short (*)[_Generic(x, int (*)[0]: 1)]);
+void zro_var (int i,
+	      char (*a)[0][i], /* dg-warn "variable" */
+	      int (*x)[_Countof (*a)],
+	      short (*)[_Generic(x, int (*)[0]: 1)]);
+void zro_uns (int i,
+	      char (*a)[0][*],
+	      int (*x)[_Countof (*a)],
+	      short (*)[_Generic(x, int (*)[0]: 1)]);
+
+void
+const_expr(void)
+{
+  int n = 7;
+
+  _Static_assert (_Countof (int [0][3]) == 0);
+  _Static_assert (_Countof (int [0]) == 0);
+  _Static_assert (_Countof (int [0][n]) == 0);
+}
diff --git a/gcc/testsuite/gcc.dg/countof-zero.c b/gcc/testsuite/gcc.dg/countof-zero.c
new file mode 100644
index 000000000000..27b5bdd490dd
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/countof-zero.c
@@ -0,0 +1,31 @@
+/* { dg-do run } */
+/* { dg-options "-std=gnu2y" } */
+
+#define assert(e)  ((e) ? (void) 0 : __builtin_abort ())
+
+void
+vla (void)
+{
+  unsigned n;
+
+  n = 0;
+  int z[n];
+  assert (_Countof (z) == 0);
+}
+
+void
+matrix_vla (void)
+{
+  int i;
+
+  i = 0;
+  assert (_Countof (int [i++][4]) == 0);
+  assert (i == 0 + 1);
+}
+
+int
+main (void)
+{
+  vla ();
+  matrix_vla ();
+}
diff --git a/gcc/testsuite/gcc.dg/countof.c b/gcc/testsuite/gcc.dg/countof.c
new file mode 100644
index 000000000000..534488501c6a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/countof.c
@@ -0,0 +1,120 @@
+/* { dg-do run } */
+/* { dg-options "-std=c2y -pedantic-errors" } */
+
+#define assert(e)  ((e) ? (void) 0 : __builtin_abort ())
+
+void
+array (void)
+{
+  short a[7];
+
+  static_assert (_Countof (a) == 7);
+  static_assert (_Countof (unsigned [99]) == 99);
+}
+
+void
+completed (void)
+{
+  int a[] = {1, 2, 3};
+
+  static_assert (_Countof (a) == 3);
+}
+
+void
+vla (void)
+{
+  unsigned n;
+
+  n = 99;
+  assert (_Countof (short [n - 10]) == 99 - 10);
+
+  int v[n / 2];
+  assert (_Countof (v) == 99 / 2);
+}
+
+void
+member (void)
+{
+  struct {
+    int a[8];
+  } s;
+
+  static_assert (_Countof (s.a) == 8);
+}
+
+void
+vla_eval (void)
+{
+  int i;
+
+  i = 7;
+  assert (_Countof (struct {int x;}[i++]) == 7);
+  assert (i == 7 + 1);
+
+  int v[i];
+  int (*p)[i];
+  p = &v;
+  assert (_Countof (*p++) == i);
+  assert (p - 1 == &v);
+}
+
+void
+array_noeval (void)
+{
+  long a[5];
+  long (*p)[_Countof (a)];
+
+  p = &a;
+  static_assert (_Countof (*p++) == 5);
+  assert (p == &a);
+}
+
+void
+matrix_fixed (void)
+{
+  int i;
+
+  static_assert (_Countof (int [7][4]) == 7);
+  i = 3;
+  static_assert (_Countof (int [7][i]) == 7);
+}
+
+void
+matrix_vla (void)
+{
+  int i, j;
+
+  i = 7;
+  assert (_Countof (int [i++][4]) == 7);
+  assert (i == 7 + 1);
+
+  i = 9;
+  j = 3;
+  assert (_Countof (int [i++][j]) == 9);
+  assert (i == 9 + 1);
+}
+
+void
+no_parens(void)
+{
+  int n = 3;
+  int a[7];
+  int v[n];
+
+  static_assert (_Countof a == 7); 
+  assert (_Countof v == 3); 
+}
+
+int
+main (void)
+{
+  array ();
+  completed ();
+  vla ();
+  member ();
+  vla_eval ();
+  array_noeval ();
+  matrix_fixed ();
+  matrix_vla ();
+  no_parens ();
+}
-- 
2.49.0


^ permalink raw reply	[flat|nested] 318+ messages in thread

* [PATCH v25 2/3] c: Add <stdcountof.h>
  2025-05-21 23:15   ` [PATCH v25 0/3] c: Add _Countof and <stdcountof.h> Alejandro Colomar
  2025-05-21 23:15     ` [PATCH v25 1/3] c: Add _Countof operator Alejandro Colomar
@ 2025-05-21 23:15     ` Alejandro Colomar
  2025-05-21 23:15     ` [PATCH v25 3/3] c: Add -Wpedantic diagnostic for _Countof Alejandro Colomar
  2025-05-27 20:22     ` [PATCH v25 0/3] c: Add _Countof and <stdcountof.h> Joseph Myers
  3 siblings, 0 replies; 318+ messages in thread
From: Alejandro Colomar @ 2025-05-21 23:15 UTC (permalink / raw)
  To: gcc-patches
  Cc: Alejandro Colomar, Martin Uecker, JeanHeyd Meneide, Joseph Myers,
	Jakub Jelinek

gcc/ChangeLog:

	* Makefile.in (USER_H): Add <stdcountof.h>.
	* ginclude/stdcountof.h: New file.

gcc/testsuite/ChangeLog:

	* gcc.dg/countof-stdcountof.c: New test.

Signed-off-by: Alejandro Colomar <alx@kernel.org>
---
 gcc/Makefile.in                           |  1 +
 gcc/ginclude/stdcountof.h                 | 31 +++++++++++++++++++++++
 gcc/testsuite/gcc.dg/countof-stdcountof.c | 24 ++++++++++++++++++
 3 files changed, 56 insertions(+)
 create mode 100644 gcc/ginclude/stdcountof.h
 create mode 100644 gcc/testsuite/gcc.dg/countof-stdcountof.c

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 72d132207c0d..fc8a7e532b97 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -481,6 +481,7 @@ USER_H = $(srcdir)/ginclude/float.h \
 	 $(srcdir)/ginclude/stdalign.h \
 	 $(srcdir)/ginclude/stdatomic.h \
 	 $(srcdir)/ginclude/stdckdint.h \
+	 $(srcdir)/ginclude/stdcountof.h \
 	 $(EXTRA_HEADERS)
 
 USER_H_INC_NEXT_PRE = @user_headers_inc_next_pre@
diff --git a/gcc/ginclude/stdcountof.h b/gcc/ginclude/stdcountof.h
new file mode 100644
index 000000000000..1d914f40e5db
--- /dev/null
+++ b/gcc/ginclude/stdcountof.h
@@ -0,0 +1,31 @@
+/* Copyright (C) 2025 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/>.  */
+
+/* ISO C2Y: 7.21 Array count <stdcountof.h>.  */
+
+#ifndef _STDCOUNTOF_H
+#define _STDCOUNTOF_H
+
+#define countof  _Countof
+
+#endif	/* stdcountof.h */
diff --git a/gcc/testsuite/gcc.dg/countof-stdcountof.c b/gcc/testsuite/gcc.dg/countof-stdcountof.c
new file mode 100644
index 000000000000..2fb0c6306ef0
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/countof-stdcountof.c
@@ -0,0 +1,24 @@
+/* { dg-do run } */
+/* { dg-options "-std=c2y -pedantic-errors" } */
+
+#include <stdcountof.h>
+
+#define assert(e)  ((e) ? (void) 0 : __builtin_abort ())
+
+extern int strcmp (const char *, const char *);
+
+#ifndef countof
+#error "countof not defined"
+#endif
+
+int a[3];
+int b[countof a];
+
+#define str(x) #x
+#define xstr(x) str(x)
+
+int
+main (void)
+{
+  assert (strcmp (xstr(countof), "_Countof") == 0);
+}
-- 
2.49.0


^ permalink raw reply	[flat|nested] 318+ messages in thread

* [PATCH v25 3/3] c: Add -Wpedantic diagnostic for _Countof
  2025-05-21 23:15   ` [PATCH v25 0/3] c: Add _Countof and <stdcountof.h> Alejandro Colomar
  2025-05-21 23:15     ` [PATCH v25 1/3] c: Add _Countof operator Alejandro Colomar
  2025-05-21 23:15     ` [PATCH v25 2/3] c: Add <stdcountof.h> Alejandro Colomar
@ 2025-05-21 23:15     ` Alejandro Colomar
  2025-05-27 20:22     ` [PATCH v25 0/3] c: Add _Countof and <stdcountof.h> Joseph Myers
  3 siblings, 0 replies; 318+ messages in thread
From: Alejandro Colomar @ 2025-05-21 23:15 UTC (permalink / raw)
  To: gcc-patches
  Cc: Alejandro Colomar, Martin Uecker, JeanHeyd Meneide, Joseph Myers,
	Jakub Jelinek

It has been standardized in C2y.

gcc/c/ChangeLog:

	* c-parser.cc (c_parser_sizeof_or_countof_expression):
	Add -Wpedantic diagnostic for _Countof in <= C23 mode.

gcc/testsuite/ChangeLog:

	* gcc.dg/countof-compat.c: New test.
	* gcc.dg/countof-no-compat.c: New test.
	* gcc.dg/countof-pedantic.c: New test.
	* gcc.dg/countof-pedantic-errors.c: New test.

Signed-off-by: Alejandro Colomar <alx@kernel.org>
---
 gcc/c/c-parser.cc                              | 4 ++++
 gcc/testsuite/gcc.dg/countof-compat.c          | 8 ++++++++
 gcc/testsuite/gcc.dg/countof-no-compat.c       | 5 +++++
 gcc/testsuite/gcc.dg/countof-pedantic-errors.c | 8 ++++++++
 gcc/testsuite/gcc.dg/countof-pedantic.c        | 8 ++++++++
 5 files changed, 33 insertions(+)
 create mode 100644 gcc/testsuite/gcc.dg/countof-compat.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-no-compat.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-pedantic-errors.c
 create mode 100644 gcc/testsuite/gcc.dg/countof-pedantic.c

diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
index 733cb312341e..98a0c5632805 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -10649,6 +10649,10 @@ c_parser_sizeof_or_countof_expression (c_parser *parser, enum rid rid)
 
   start = c_parser_peek_token (parser)->location;
 
+  if (rid == RID_COUNTOF)
+    pedwarn_c23 (start, OPT_Wpedantic,
+		 "ISO C does not support %qs before C23", op_name);
+
   c_parser_consume_token (parser);
   c_inhibit_evaluation_warnings++;
   if (rid == RID_COUNTOF)
diff --git a/gcc/testsuite/gcc.dg/countof-compat.c b/gcc/testsuite/gcc.dg/countof-compat.c
new file mode 100644
index 000000000000..ab5b4ae6219c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/countof-compat.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-std=c2y -pedantic-errors -Wc23-c2y-compat" } */
+
+#include <stdcountof.h>
+
+int a[1];
+int b[countof(a)];
+int c[_Countof(a)];  /* { dg-warning "ISO C does not support" } */
diff --git a/gcc/testsuite/gcc.dg/countof-no-compat.c b/gcc/testsuite/gcc.dg/countof-no-compat.c
new file mode 100644
index 000000000000..4a244cf222f6
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/countof-no-compat.c
@@ -0,0 +1,5 @@
+/* { dg-do compile } */
+/* { dg-options "-std=c23 -pedantic-errors -Wno-c23-c2y-compat" } */
+
+int a[1];
+int b[_Countof(a)];
diff --git a/gcc/testsuite/gcc.dg/countof-pedantic-errors.c b/gcc/testsuite/gcc.dg/countof-pedantic-errors.c
new file mode 100644
index 000000000000..5d5bedbe1f7e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/countof-pedantic-errors.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-std=c23 -pedantic-errors" } */
+
+#include <stdcountof.h>
+
+int a[1];
+int b[countof(a)];
+int c[_Countof(a)];  /* { dg-error "ISO C does not support" } */
diff --git a/gcc/testsuite/gcc.dg/countof-pedantic.c b/gcc/testsuite/gcc.dg/countof-pedantic.c
new file mode 100644
index 000000000000..408dc6f93667
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/countof-pedantic.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-std=c23 -pedantic" } */
+
+#include <stdcountof.h>
+
+int a[1];
+int b[countof(a)];
+int c[_Countof(a)];  /* { dg-warning "ISO C does not support" } */
-- 
2.49.0


^ permalink raw reply	[flat|nested] 318+ messages in thread

* Re: [PATCH v25 0/3] c: Add _Countof and <stdcountof.h>
  2025-05-21 23:15   ` [PATCH v25 0/3] c: Add _Countof and <stdcountof.h> Alejandro Colomar
                       ` (2 preceding siblings ...)
  2025-05-21 23:15     ` [PATCH v25 3/3] c: Add -Wpedantic diagnostic for _Countof Alejandro Colomar
@ 2025-05-27 20:22     ` Joseph Myers
  2025-05-27 20:28       ` Jakub Jelinek
  3 siblings, 1 reply; 318+ messages in thread
From: Joseph Myers @ 2025-05-27 20:22 UTC (permalink / raw)
  To: Alejandro Colomar
  Cc: gcc-patches, Martin Uecker, JeanHeyd Meneide, Jakub Jelinek

Thanks, I've committed these patches, with additional commit message 
changes to reference PR117025 in the standard way for GCC so that Bugzilla 
picks up the commits automatically.

-- 
Joseph S. Myers
josmyers@redhat.com


^ permalink raw reply	[flat|nested] 318+ messages in thread

* Re: [PATCH v25 0/3] c: Add _Countof and <stdcountof.h>
  2025-05-27 20:22     ` [PATCH v25 0/3] c: Add _Countof and <stdcountof.h> Joseph Myers
@ 2025-05-27 20:28       ` Jakub Jelinek
  2025-05-27 21:15         ` Alejandro Colomar
  0 siblings, 1 reply; 318+ messages in thread
From: Jakub Jelinek @ 2025-05-27 20:28 UTC (permalink / raw)
  To: Joseph Myers
  Cc: Alejandro Colomar, gcc-patches, Martin Uecker, JeanHeyd Meneide

On Tue, May 27, 2025 at 08:22:28PM +0000, Joseph Myers wrote:
> Thanks, I've committed these patches, with additional commit message 
> changes to reference PR117025 in the standard way for GCC so that Bugzilla 
> picks up the commits automatically.

--- a/gcc/c/c-parser.cc                                                                                                                                                               
+++ b/gcc/c/c-parser.cc                                                                                                                                                               
@@ -10649,6 +10649,10 @@ c_parser_sizeof_or_countof_expression (c_parser *parser, enum rid rid)                                                                                       
                                                                                                                                                                                      
   start = c_parser_peek_token (parser)->location;                                                                                                                                    
                                                                                                                                                                                      
+  if (rid == RID_COUNTOF)                                                                                                                                                            
+    pedwarn_c23 (start, OPT_Wpedantic,                                                                                                                                               
+                "ISO C does not support %qs before C23", op_name);                                                                                                                   
+                                                                                                                                                                                     
   c_parser_consume_token (parser);                                                                                                                                                   
   c_inhibit_evaluation_warnings++;                                                                                                                                                   
   if (rid == RID_COUNTOF)                                                                                                                                                            

The C23 in there looks like pasto, should be C2Y.

	Jakub


^ permalink raw reply	[flat|nested] 318+ messages in thread

* Re: [PATCH v25 0/3] c: Add _Countof and <stdcountof.h>
  2025-05-27 20:28       ` Jakub Jelinek
@ 2025-05-27 21:15         ` Alejandro Colomar
  2025-05-27 21:29           ` Jakub Jelinek
  0 siblings, 1 reply; 318+ messages in thread
From: Alejandro Colomar @ 2025-05-27 21:15 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: Joseph Myers, gcc-patches, Martin Uecker, JeanHeyd Meneide

[-- Attachment #1: Type: text/plain, Size: 2998 bytes --]

Hi Jakub, Joseph,

On Tue, May 27, 2025 at 10:28:23PM +0200, Jakub Jelinek wrote:
> On Tue, May 27, 2025 at 08:22:28PM +0000, Joseph Myers wrote:
> > Thanks, I've committed these patches, with additional commit message 
> > changes to reference PR117025 in the standard way for GCC so that Bugzilla 
> > picks up the commits automatically.

Thanks a lot!!!  :-)

> --- a/gcc/c/c-parser.cc                                                                                                                                                               
> +++ b/gcc/c/c-parser.cc                                                                                                                                                               
> @@ -10649,6 +10649,10 @@ c_parser_sizeof_or_countof_expression (c_parser *parser, enum rid rid)                                                                                       
>                                                                                                                                                                                       
>    start = c_parser_peek_token (parser)->location;                                                                                                                                    
>                                                                                                                                                                                       
> +  if (rid == RID_COUNTOF)                                                                                                                                                            
> +    pedwarn_c23 (start, OPT_Wpedantic,                                                                                                                                               
> +                "ISO C does not support %qs before C23", op_name);                                                                                                                   
> +                                                                                                                                                                                     
>    c_parser_consume_token (parser);                                                                                                                                                   
>    c_inhibit_evaluation_warnings++;                                                                                                                                                   
>    if (rid == RID_COUNTOF)                                                                                                                                                            
> 
> The C23 in there looks like pasto, should be C2Y.

Oopsy!  Sorry!  Please fix, yep, it's a pasto.  :)


Have a lovely night!
Alex

> 
> 	Jakub
> 

-- 
<https://www.alejandro-colomar.es/>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 318+ messages in thread

* Re: [PATCH v25 0/3] c: Add _Countof and <stdcountof.h>
  2025-05-27 21:15         ` Alejandro Colomar
@ 2025-05-27 21:29           ` Jakub Jelinek
  0 siblings, 0 replies; 318+ messages in thread
From: Jakub Jelinek @ 2025-05-27 21:29 UTC (permalink / raw)
  To: Alejandro Colomar
  Cc: Joseph Myers, gcc-patches, Martin Uecker, JeanHeyd Meneide

On Tue, May 27, 2025 at 11:15:14PM +0200, Alejandro Colomar wrote:
> Oopsy!  Sorry!  Please fix, yep, it's a pasto.  :)

Committed as obvious to trunk:

2025-05-27  Jakub Jelinek  <jakub@redhat.com>

	PR c/117025
	* c-parser.cc (c_parser_sizeof_or_countof_expression): Use
	C2Y rather than C23 in pedwarn_c23.

--- gcc/c/c-parser.cc.jj	2025-05-27 23:08:37.907727004 +0200
+++ gcc/c/c-parser.cc	2025-05-27 23:25:51.540844741 +0200
@@ -10651,7 +10651,7 @@ c_parser_sizeof_or_countof_expression (c
 
   if (rid == RID_COUNTOF)
     pedwarn_c23 (start, OPT_Wpedantic,
-		 "ISO C does not support %qs before C23", op_name);
+		 "ISO C does not support %qs before C2Y", op_name);
 
   c_parser_consume_token (parser);
   c_inhibit_evaluation_warnings++;

	Jakub


^ permalink raw reply	[flat|nested] 318+ messages in thread

* Re: [PATCH v25 1/3] c: Add _Countof operator
  2025-05-21 23:15     ` [PATCH v25 1/3] c: Add _Countof operator Alejandro Colomar
@ 2025-05-28  9:35       ` Sam James
  2025-05-28 10:21         ` [PATCH v1] testsuite: Remove spurious comments [PR117025] Alejandro Colomar
  0 siblings, 1 reply; 318+ messages in thread
From: Sam James @ 2025-05-28  9:35 UTC (permalink / raw)
  To: Alejandro Colomar
  Cc: gcc-patches, Martin Uecker, JeanHeyd Meneide, Joseph Myers,
	Jakub Jelinek, Xavier Del Campo Romero, James K. Lowden

Alejandro Colomar <alx@kernel.org> writes:

> [...]
> diff --git a/gcc/testsuite/gcc.dg/countof-vla.c b/gcc/testsuite/gcc.dg/countof-vla.c
> new file mode 100644
> index 000000000000..cc225df20689
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/countof-vla.c
> @@ -0,0 +1,35 @@
> +/* { dg-do compile } */
> +/* { dg-options "-std=c2y -pedantic-errors -Wvla-parameter" } */
> +
> +void fix_fix (int i,
> +	      char (*a)[3][5],
> +	      int (*x)[_Countof (*a)],
> +	      short (*)[_Generic(x, int (*)[3]: 1)]);
> +void fix_var (int i,
> +	      char (*a)[3][i], /* dg-warn "variable" */

'dg-warn' is not a valid dg directive. It should be 'dg-warning', but it
needs to be surrounded by braces too, i.e.

{ dg-warning "variable" }

^ permalink raw reply	[flat|nested] 318+ messages in thread

* [PATCH v1] testsuite: Remove spurious comments [PR117025]
  2025-05-28  9:35       ` Sam James
@ 2025-05-28 10:21         ` Alejandro Colomar
  0 siblings, 0 replies; 318+ messages in thread
From: Alejandro Colomar @ 2025-05-28 10:21 UTC (permalink / raw)
  To: gcc-patches, Sam James
  Cc: Alejandro Colomar, Martin Uecker, JeanHeyd Meneide, Joseph Myers,
	Jakub Jelinek, Xavier Del Campo Romero, James K. Lowden

	PR c/117025

gcc/testsuite/ChangeLog:

	* gcc.dg/countof-vla.c: Remove spurious comments.
	* gcc.dg/countof-zero-compile.c: Remove spurious comments.

Fixes: 517c9487f8fd (2025-05-27; "c: Add _Countof operator [PR117025]")
Reported-by: Sam James <sam@gentoo.org>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
---

Hi Sam,

Thanks for catching that!  Here's a fix.  We can just drop those
comments.


Have a lovely day!
Alex


 gcc/testsuite/gcc.dg/countof-vla.c          | 16 ++++++++--------
 gcc/testsuite/gcc.dg/countof-zero-compile.c |  2 +-
 2 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/gcc/testsuite/gcc.dg/countof-vla.c b/gcc/testsuite/gcc.dg/countof-vla.c
index cc225df20689..68e650c4c844 100644
--- a/gcc/testsuite/gcc.dg/countof-vla.c
+++ b/gcc/testsuite/gcc.dg/countof-vla.c
@@ -6,7 +6,7 @@ void fix_fix (int i,
 	      int (*x)[_Countof (*a)],
 	      short (*)[_Generic(x, int (*)[3]: 1)]);
 void fix_var (int i,
-	      char (*a)[3][i], /* dg-warn "variable" */
+	      char (*a)[3][i],
 	      int (*x)[_Countof (*a)],
 	      short (*)[_Generic(x, int (*)[3]: 1)]);
 void fix_uns (int i,
@@ -15,20 +15,20 @@ void fix_uns (int i,
 	      short (*)[_Generic(x, int (*)[3]: 1)]);
 
 void var_fix (int i,
-	      char (*a)[i][5], /* dg-warn "variable" */
-	      int (*x)[_Countof (*a)]); /* dg-warn "variable" */
+	      char (*a)[i][5],
+	      int (*x)[_Countof (*a)]);
 void var_var (int i,
-	      char (*a)[i][i], /* dg-warn "variable" */
-	      int (*x)[_Countof (*a)]); /* dg-warn "variable" */
+	      char (*a)[i][i],
+	      int (*x)[_Countof (*a)]);
 void var_uns (int i,
-	      char (*a)[i][*], /* dg-warn "variable" */
-	      int (*x)[_Countof (*a)]); /* dg-warn "variable" */
+	      char (*a)[i][*],
+	      int (*x)[_Countof (*a)]);
 
 void uns_fix (int i,
 	      char (*a)[*][5],
 	      int (*x)[_Countof (*a)]);
 void uns_var (int i,
-	      char (*a)[*][i], /* dg-warn "variable" */
+	      char (*a)[*][i],
 	      int (*x)[_Countof (*a)]);
 void uns_uns (int i,
 	      char (*a)[*][*],
diff --git a/gcc/testsuite/gcc.dg/countof-zero-compile.c b/gcc/testsuite/gcc.dg/countof-zero-compile.c
index b561186166c3..bae9cb6969d3 100644
--- a/gcc/testsuite/gcc.dg/countof-zero-compile.c
+++ b/gcc/testsuite/gcc.dg/countof-zero-compile.c
@@ -19,7 +19,7 @@ void zro_fix (int i,
 	      int (*x)[_Countof (*a)],
 	      short (*)[_Generic(x, int (*)[0]: 1)]);
 void zro_var (int i,
-	      char (*a)[0][i], /* dg-warn "variable" */
+	      char (*a)[0][i],
 	      int (*x)[_Countof (*a)],
 	      short (*)[_Generic(x, int (*)[0]: 1)]);
 void zro_uns (int i,

Range-diff against v0:
-:  ------------ > 1:  567a0c44c1ea testsuite: Remove spurious comments [PR117025]
-- 
2.49.0


^ permalink raw reply	[flat|nested] 318+ messages in thread

end of thread, other threads:[~2025-05-28 10:22 UTC | newest]

Thread overview: 318+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-10-16 12:09 [PATCH v16b 0/4] c: Add __countof__ operator Alejandro Colomar
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-29  8:27     ` Richard Biener
2024-07-29  8:55       ` Alejandro Colomar
2024-07-29  9:08         ` Richard Biener
2024-07-28 14:16   ` [RFC v1 2/2] c: Add _Lengthof() operator Alejandro Colomar
2024-07-28 14:42   ` [RFC v1 0/2] c: Add _Lengthof operator Martin Uecker
2024-07-28 15:19     ` Alejandro Colomar
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     ` [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
2024-08-03 22:59     ` Alejandro Colomar
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     ` [RFC v3 3/3] c: Add __lengthof__() operator Alejandro Colomar
2024-08-04  5:38       ` Martin Uecker
2024-08-04  8:25         ` Alejandro Colomar
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:49                 ` Alejandro Colomar
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
2024-08-05  9:50                         ` Jakub Jelinek
2024-08-05 10:33                           ` Martin Uecker
2024-08-05 20:10                             ` Qing Zhao
2024-08-05 20:41                               ` Martin Uecker
2024-08-05 20:59                                 ` Alejandro Colomar
2024-08-06 15:23                                   ` Qing Zhao
2024-08-04 17:28               ` Martin Uecker
2024-08-05 11:55             ` Alejandro Colomar
2024-08-05 11:57               ` Alejandro Colomar
2024-08-05 11:58                 ` Alejandro Colomar
2024-08-05 11:59                   ` Alejandro Colomar
2024-08-05 13:35                     ` Martin Uecker
2024-08-05 15:27                       ` Alejandro Colomar
2024-08-05 16:05                         ` Martin Uecker
2024-08-05 17:47                           ` Alejandro Colomar
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     ` [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
2024-08-06 20:41           ` Alejandro Colomar
2024-08-06 12:22     ` [RFC v4 4/4] testsuite: Add tests for __lengthof__ Alejandro Colomar
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 14:43         ` Martin Uecker
2024-08-06 15:40           ` Alejandro Colomar
2024-08-06 21:46           ` Alejandro Colomar
2024-08-06 15:59     ` Qing Zhao
2024-08-06 16:48       ` Alejandro Colomar
2024-08-06 17:38     ` Joseph Myers
2024-08-06 20:22       ` Alejandro Colomar
2024-08-06 20:50         ` Joseph Myers
2024-08-06 21:09           ` Alejandro Colomar
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     ` [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 10:07           ` Martin Uecker
2024-08-07 22:09             ` Alejandro Colomar
2024-08-08  7:39               ` Martin Uecker
2024-08-08  8:42                 ` Alejandro Colomar
2024-08-08  9:23                   ` Martin Uecker
2024-08-08  9:36                     ` Alejandro Colomar
2024-08-07 15:05       ` Joseph Myers
2024-08-07 15:30         ` Jens Gustedt
2024-08-07 22:44           ` Alejandro Colomar
2024-08-08  5:35             ` Jₑₙₛ Gustedt
2024-08-08  8:26               ` Alejandro Colomar
2024-08-08  9:13                 ` Jens Gustedt
2024-08-08  9:25                   ` Alejandro Colomar
2024-08-08 11:28                     ` Joseph Myers
2024-08-08 14:56                       ` Jens Gustedt
2024-08-08 15:42                         ` Martin Uecker
2024-08-08 15:56                           ` Jens Gustedt
2024-08-08 16:08                             ` Joseph Myers
2024-08-08 16:23                               ` Jens Gustedt
2024-08-08 16:30                                 ` Martin Uecker
2024-08-08 17:01                                   ` Alejandro Colomar
2024-08-08 17:31                                     ` Joseph Myers
2024-08-08 18:04                                       ` Alejandro Colomar
2024-08-08 18:16                                         ` Martin Uecker
2024-08-08 18:30                                           ` Alejandro Colomar
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
2024-08-08 22:48                                         ` Jakub Jelinek
2024-08-10  8:57                                         ` [committed] testsuite: Fix up sse3-addsubps.c Jakub Jelinek
2024-08-12 23:43                                           ` Alejandro Colomar
2024-08-08 17:21                   ` [PATCH v5 3/3] c: Add __lengthof__ operator David Brown
2024-08-08 18:19                     ` Jens Gustedt
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>
2024-08-07  8:30         ` Alejandro Colomar
2024-08-08 22:41     ` Internal Compiler Error (was: [PATCH v5 0/3] c: Add __lengthof__ operator) Alejandro Colomar
2024-08-09 13:58   ` [PATCH v6 0/3] c: Add __lengthof__ operator Alejandro Colomar
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   ` [PATCH v6 2/3] Merge definitions of array_type_nelts_top() Alejandro Colomar
2024-08-09 13:59   ` [PATCH v6 3/3] c: Add __lengthof__ operator Alejandro Colomar
2024-08-09 15:51     ` Alejandro Colomar
2024-08-10 20:54   ` [PATCH v7 0/3] " Alejandro Colomar
2024-08-10 20:54     ` [PATCH v7 1/3] gcc/: Rename array_type_nelts() => array_type_nelts_minus_one() Alejandro Colomar
2024-08-10 20:54     ` [PATCH v7 2/3] Merge definitions of array_type_nelts_top() Alejandro Colomar
2024-08-10 20:54     ` [PATCH v7 3/3] c: Add __lengthof__ operator Alejandro Colomar
2024-08-11 23:46   ` [PATCH v8 0/3] " Alejandro Colomar
2024-08-11 23:46     ` [PATCH v8 1/3] gcc/: Rename array_type_nelts() => array_type_nelts_minus_one() Alejandro Colomar
2024-08-11 23:46     ` [PATCH v8 2/3] Merge definitions of array_type_nelts_top() Alejandro Colomar
2024-08-11 23:46     ` [PATCH v8 3/3] c: Add __lengthof__ operator Alejandro Colomar
2024-08-12 23:34     ` [WG14] Request for document number; _Lengthof Alejandro Colomar
2024-08-13  7:33       ` Alejandro Colomar
2024-08-13 15:02       ` v2.1 Draft for a lengthof paper Alejandro Colomar
2024-08-13 22:38         ` Xavier Del Campo Romero
2024-08-13 23:27           ` Alejandro Colomar
2024-08-14  6:11             ` Jens Gustedt
2024-08-14  8:41               ` Alejandro Colomar
2024-08-14 11:31               ` Ballman, Aaron
2024-08-14 12:17                 ` Jens Gustedt
2024-08-14 12:40                   ` Ballman, Aaron
2024-08-14 13:13                     ` Alejandro Colomar
2024-08-14 13:24                     ` Jens Gustedt
2024-08-14 13:59                       ` Ballman, Aaron
2024-08-14 14:31                         ` Alejandro Colomar
2024-08-14 13:50                     ` Martin Uecker
2024-08-14 14:12                       ` Alejandro Colomar
2024-08-14 14:37                         ` Martin Uecker
2024-08-14 12:58                   ` Alejandro Colomar
2024-08-14 13:21                     ` Ballman, Aaron
2024-08-14 14:00                       ` Alejandro Colomar
2024-08-14 14:07                         ` Ballman, Aaron
2024-08-14 15:01                           ` Alejandro Colomar
2024-08-14 13:50                     ` Jens Gustedt
2024-08-14 14:47                       ` Alejandro Colomar
2024-08-14 14:52                         ` Ballman, Aaron
2024-08-14 15:01                           ` Martin Uecker
2024-08-14 15:44                         ` Jens Gustedt
2024-09-01  9:10                           ` VLA is a misnomer (rebuttal to n3187) Alejandro Colomar
2024-09-01  9:51                             ` Martin Uecker
2024-08-14  5:58           ` v2.1 Draft for a lengthof paper Jens Gustedt
2024-08-14 20:58   ` [PATCH v9 0/3] c: Add __elementsof__ operator Alejandro Colomar
2024-08-14 20:58     ` [PATCH v9 1/3] gcc/: Rename array_type_nelts() => array_type_nelts_minus_one() Alejandro Colomar
2024-08-14 20:58     ` [PATCH v9 2/3] Merge definitions of array_type_nelts_top() Alejandro Colomar
2024-08-14 20:58     ` [PATCH v9 3/3] c: Add __elementsof__ operator Alejandro Colomar
2024-08-19 10:58   ` [PATCH v10 0/3] c: Add __nelementsof__ operator Alejandro Colomar
2024-08-19 10:58     ` [PATCH v10 1/3] gcc/: Rename array_type_nelts() => array_type_nelts_minus_one() Alejandro Colomar
2024-08-19 16:46       ` Jason Merrill
2024-08-20 18:09         ` Alejandro Colomar
2024-08-19 10:58     ` [PATCH v10 2/3] Merge definitions of array_type_nelts_top() Alejandro Colomar
2024-08-19 10:58     ` [PATCH v10 3/3] c: Add __nelementsof__ operator Alejandro Colomar
2024-08-20 18:41   ` [PATCH v11 0/4] " Alejandro Colomar
2024-08-20 18:41     ` [PATCH v11 1/4] contrib/: Add support for Cc: and Link: tags Alejandro Colomar
2024-08-20 18:49       ` Alejandro Colomar
2024-08-20 18:41     ` [PATCH v11 2/4] gcc/: Rename array_type_nelts() => array_type_nelts_minus_one() Alejandro Colomar
2024-08-20 18:41     ` [PATCH v11 3/4] Merge definitions of array_type_nelts_top() Alejandro Colomar
2024-08-20 18:41     ` [PATCH v11 4/4] c: Add __nelementsof__ operator Alejandro Colomar
2024-08-31 14:56   ` [PATCH v12 0/4] " Alejandro Colomar
2024-08-31 14:56     ` [PATCH v12 1/4] contrib/: Add support for Cc: and Link: tags Alejandro Colomar
2024-08-31 14:56     ` [PATCH v12 2/4] gcc/: Rename array_type_nelts() => array_type_nelts_minus_one() Alejandro Colomar
2024-08-31 14:56     ` [PATCH v12 3/4] Merge definitions of array_type_nelts_top() Alejandro Colomar
2024-08-31 14:56     ` [PATCH v12 4/4] c: Add __nelementsof__ operator Alejandro Colomar
2024-10-02  8:34     ` [PATCH v12 0/4] " Alejandro Colomar
2024-10-02  9:41   ` [PATCH v13 0/4] c: Add __lengthof__ operator Alejandro Colomar
2024-10-02  9:41     ` [PATCH v13 1/4] contrib/: Add support for Cc: and Link: tags Alejandro Colomar
2024-10-02  9:41     ` [PATCH v13 2/4] gcc/: Rename array_type_nelts() => array_type_nelts_minus_one() Alejandro Colomar
2024-10-02  9:41     ` [PATCH v13 3/4] Merge definitions of array_type_nelts_top() Alejandro Colomar
2024-10-02  9:41     ` [PATCH v13 4/4] c: Add __lengthof__ operator Alejandro Colomar
2024-10-07 17:35     ` [PATCH v13 0/4] " Joseph Myers
2024-10-08  0:04       ` Alejandro Colomar
2024-10-08  0:09         ` Alejandro Colomar
2024-10-08  6:45           ` Jakub Jelinek
2024-10-08  8:11             ` Alejandro Colomar
2024-10-08 13:19         ` Joseph Myers
2024-10-08 13:28           ` Alejandro Colomar
2024-10-08 13:40             ` Jakub Jelinek
2024-10-08 14:49               ` Alejandro Colomar
2024-10-08 15:13                 ` Chris Bazley
2024-10-09 12:11                   ` Alejandro Colomar
2024-10-09 17:05                     ` Joseph Myers
2024-10-09 18:48                       ` Alejandro Colomar
2024-10-09 19:31                         ` Joseph Myers
2024-10-09 20:25                           ` Alejandro Colomar
2024-10-09 21:11                             ` Joseph Myers
2024-10-09 21:20                               ` Alejandro Colomar
2024-10-10  4:13                                 ` Xavier Del Campo Romero
2024-10-15 10:03                               ` Alejandro Colomar
2024-10-09 19:40                         ` Meaning of "length", "size", and "count" Jakub Łukasiewicz
2024-10-09 20:31                           ` Alejandro Colomar
2024-10-08 14:04             ` [PATCH v13 0/4] c: Add __lengthof__ operator Joseph Myers
2024-10-08 14:59               ` Alejandro Colomar
2024-10-08 15:13                 ` Joseph Myers
2024-10-08 15:21                   ` Chris Bazley
2024-10-08 15:54                     ` Jₑₙₛ Gustedt
2024-10-08 19:14                   ` Alejandro Colomar
2024-10-08  8:25       ` Jakub Łukasiewicz
2024-10-08  8:33         ` Alejandro Colomar
2024-10-08  8:59           ` Jakub Łukasiewicz
2024-10-08 13:23           ` Joseph Myers
2024-10-08  9:11   ` [PATCH v14 0/4] c: Add __countof__ operator Alejandro Colomar
2024-10-08  9:11     ` [PATCH v14 1/4] contrib/: Add support for Cc: and Link: tags Alejandro Colomar
2024-10-08  9:11     ` [PATCH v14 2/4] gcc/: Rename array_type_nelts() => array_type_nelts_minus_one() Alejandro Colomar
2024-10-08  9:11     ` [PATCH v14 3/4] Merge definitions of array_type_nelts_top() Alejandro Colomar
2024-10-08  9:11     ` [PATCH v14 4/4] c: Add __countof__ operator Alejandro Colomar
2024-10-16 10:13   ` [PATCH v15 0/4] " Alejandro Colomar
2024-10-16 10:13     ` [PATCH v15 1/4] contrib/: Add support for Cc: and Link: tags Alejandro Colomar
2024-10-16 10:13     ` [PATCH v15 2/4] gcc/: Rename array_type_nelts() => array_type_nelts_minus_one() Alejandro Colomar
2024-10-16 10:34       ` Joseph Myers
2024-10-16 10:45         ` Alejandro Colomar
2024-10-16 10:53         ` Alejandro Colomar
2024-10-16 11:08           ` Joseph Myers
2024-10-16 10:13     ` [PATCH v15 3/4] Merge definitions of array_type_nelts_top() Alejandro Colomar
2024-10-16 10:13     ` [PATCH v15 4/4] c: Add __countof__ operator Alejandro Colomar
2024-10-16 10:30       ` Joseph Myers
2024-10-16 10:46         ` Alejandro Colomar
2024-10-22 18:48   ` [PATCH v17 0/2] " Alejandro Colomar
2024-10-22 18:48     ` [PATCH v17 1/2] contrib/: Add support for Cc: and Link: tags Alejandro Colomar
2024-10-22 18:48     ` [PATCH v17 2/2] c: Add __countof__ operator Alejandro Colomar
2024-10-25 20:44       ` Joseph Myers
2024-10-25 22:10         ` Alejandro Colomar
2024-11-08 14:00           ` Alejandro Colomar
2024-11-08 15:51             ` Joseph Myers
2024-10-22 18:52     ` [PATCH v17 0/2] " Alejandro Colomar
2024-11-10 10:32   ` [PATCH v18 " Alejandro Colomar
2024-11-10 10:32     ` [PATCH v18 1/2] contrib/: Add support for Cc: and Link: tags Alejandro Colomar
2024-11-10 10:32     ` [PATCH v18 2/2] c: Add __countof__ operator Alejandro Colomar
2024-11-10 10:34     ` [PATCH v18 0/2] " Alejandro Colomar
2024-11-10 13:47     ` Martin Uecker
2025-05-11 14:11   ` [PATCH v20 0/4] c: Add _Countof and <stdcountof.h> Alejandro Colomar
2025-05-11 14:11     ` [PATCH v20 1/4] contrib/: Add support for Link: tags Alejandro Colomar
2025-05-11 14:12     ` [PATCH v20 2/4] c: Add _Countof operator Alejandro Colomar
2025-05-12 10:54       ` Joseph Myers
2025-05-12 15:14         ` Alejandro Colomar
2025-05-11 14:12     ` [PATCH v20 3/4] c: Add <stdcountof.h> Alejandro Colomar
2025-05-12 10:54       ` Joseph Myers
2025-05-12 14:50         ` Alejandro Colomar
2025-05-11 14:12     ` [PATCH v20 4/4] c: Add -Wpedantic diagnostic for _Countof Alejandro Colomar
2025-05-12 10:49     ` [PATCH v20 0/4] c: Add _Countof and <stdcountof.h> Joseph Myers
2025-05-12 15:53   ` [PATCH v21 0/3] " Alejandro Colomar
2025-05-12 15:53     ` [PATCH v21 1/3] c: Add _Countof operator Alejandro Colomar
2025-05-12 17:11       ` Jonathan Wakely
2025-05-12 22:15         ` Alejandro Colomar
2025-05-13  9:39           ` Jonathan Wakely
2025-05-13 10:13             ` Alejandro Colomar
2025-05-13 10:56               ` Jonathan Wakely
2025-05-12 15:55     ` [PATCH v21 2/3] c: Add <stdcountof.h> Alejandro Colomar
2025-05-12 16:43       ` Joseph Myers
2025-05-12 22:04         ` Alejandro Colomar
2025-05-12 15:55     ` [PATCH v21 3/3] c: Add -Wpedantic diagnostic for _Countof Alejandro Colomar
2025-05-15 22:37   ` [PATCH v22 0/3] c: Add _Countof and <stdcountof.h> Alejandro Colomar
2025-05-15 22:37     ` [PATCH v22 1/3] c: Add _Countof operator Alejandro Colomar
2025-05-15 22:37     ` [PATCH v22 2/3] c: Add <stdcountof.h> Alejandro Colomar
2025-05-15 22:37     ` [PATCH v22 3/3] c: Add -Wpedantic diagnostic for _Countof Alejandro Colomar
2025-05-15 22:44     ` [PATCH v22 0/3] c: Add _Countof and <stdcountof.h> Alejandro Colomar
2025-05-16 12:25     ` Joseph Myers
2025-05-16 16:56       ` Alejandro Colomar
2025-05-16 17:01         ` Joseph Myers
2025-05-16 17:13           ` Alejandro Colomar
2025-05-20 12:33             ` Alejandro Colomar
2025-05-20 14:43               ` Joseph Myers
2025-05-20 15:15                 ` Alejandro Colomar
2025-05-20 15:25                   ` Jakub Jelinek
2025-05-20 21:12                     ` Alejandro Colomar
2025-05-20 21:20                       ` Jakub Jelinek
2025-05-20 21:44                         ` Alejandro Colomar
2025-05-20 22:04                           ` Jakub Jelinek
2025-05-21  0:17   ` [PATCH v23 " Alejandro Colomar
2025-05-21  0:18     ` [PATCH v23 1/3] c: Add _Countof operator Alejandro Colomar
2025-05-21 16:26       ` Joseph Myers
2025-05-21 17:01         ` Alejandro Colomar
2025-05-21 17:48           ` Joseph Myers
2025-05-21  0:18     ` [PATCH v23 2/3] c: Add <stdcountof.h> Alejandro Colomar
2025-05-21  0:18     ` [PATCH v23 3/3] c: Add -Wpedantic diagnostic for _Countof Alejandro Colomar
2025-05-21  8:56     ` [PATCH v23 0/3] c: Add _Countof and <stdcountof.h> Alejandro Colomar
2025-05-21 21:01   ` [PATCH v24 " Alejandro Colomar
2025-05-21 21:01     ` [PATCH v24 1/3] c: Add _Countof operator Alejandro Colomar
2025-05-21 21:12       ` Jakub Jelinek
2025-05-21 21:31         ` Alejandro Colomar
2025-05-21 21:41           ` Jakub Jelinek
2025-05-21 21:44           ` Alejandro Colomar
2025-05-21 21:47             ` Jakub Jelinek
2025-05-21 21:56               ` Alejandro Colomar
2025-05-21 21:36         ` Alejandro Colomar
2025-05-21 21:37           ` Alejandro Colomar
2025-05-21 21:01     ` [PATCH v24 2/3] c: Add <stdcountof.h> Alejandro Colomar
2025-05-21 21:06       ` Jakub Jelinek
2025-05-21 21:01     ` [PATCH v24 3/3] c: Add -Wpedantic diagnostic for _Countof Alejandro Colomar
2025-05-21 21:12       ` Jakub Jelinek
2025-05-21 23:15   ` [PATCH v25 0/3] c: Add _Countof and <stdcountof.h> Alejandro Colomar
2025-05-21 23:15     ` [PATCH v25 1/3] c: Add _Countof operator Alejandro Colomar
2025-05-28  9:35       ` Sam James
2025-05-28 10:21         ` [PATCH v1] testsuite: Remove spurious comments [PR117025] Alejandro Colomar
2025-05-21 23:15     ` [PATCH v25 2/3] c: Add <stdcountof.h> Alejandro Colomar
2025-05-21 23:15     ` [PATCH v25 3/3] c: Add -Wpedantic diagnostic for _Countof Alejandro Colomar
2025-05-27 20:22     ` [PATCH v25 0/3] c: Add _Countof and <stdcountof.h> Joseph Myers
2025-05-27 20:28       ` Jakub Jelinek
2025-05-27 21:15         ` Alejandro Colomar
2025-05-27 21:29           ` Jakub Jelinek
2024-10-16 12:10 ` [PATCH v16b 0/4] c: Add __countof__ operator Alejandro Colomar
2024-10-16 12:10 ` [PATCH v16b 1/4] contrib/: Add support for Cc: and Link: tags Alejandro Colomar
2024-10-16 12:10 ` [PATCH v16b 2/4] gcc/: Rename array_type_nelts => array_type_nelts_minus_one Alejandro Colomar
2024-10-16 17:21   ` Joseph Myers
2024-10-16 18:02     ` Alejandro Colomar
2024-10-18  8:25       ` Alejandro Colomar
2024-10-18 11:22         ` Alejandro Colomar
2024-10-16 12:10 ` [PATCH v16b 3/4] gcc/: Merge definitions of array_type_nelts_top Alejandro Colomar
2024-10-18 22:43   ` Joseph Myers
2024-10-16 12:10 ` [PATCH v16b 4/4] c: Add __countof__ operator Alejandro Colomar

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).