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