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--...@tutanota.com/T/>
> Link: 
> <https://inbox.sourceware.org/gcc-patches/20240728141547.302478-1-...@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....@tutanota.com>
> Co-authored-by: Martin Uecker <uec...@tugraz.at>
> Acked-by: "James K. Lowden" <jklow...@schemamania.org>
> Signed-off-by: Alejandro Colomar <a...@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);
> +}
>  
>  /* 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"
> +
> +#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

Reply via email to