Hi Daniel,

Here's a revised version of the WG14 paper, with all issues addressed.

Have a lovely day!
Alex

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.
> 
> 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/>

Attachment: n3365.pdf
Description: Adobe PDF document

Attachment: signature.asc
Description: PGP signature

Reply via email to