Hi all,

On Wed, Oct 02, 2024 at 08:29:26PM GMT, Alejandro Colomar wrote:
> > On Wed, Oct 02, 2024 at 11:41:20AM +0200, Alejandro Colomar wrote:
> > > 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.

FYI, this has been merged into C2y today, as _Lengthof.
The paper that was merged was
<https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3369.pdf> with some
trivial/editorial wording cosmetic changes amended on top of it.

Have a lovely day!
Alex

> > > 
> > > 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 <a...@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--...@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
> > >      +
> > >      +#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)     
> > >           \
> > >      +)
> > >      +
> > >       /* 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
> > > 
> > 
> > 
> > 
> > -- 
> > <https://www.alejandro-colomar.es/>
> 
> 
> 
> 
> 
> -- 
> <https://www.alejandro-colomar.es/>





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

Attachment: signature.asc
Description: PGP signature

Reply via email to