From patchwork Tue Oct 8 09:11:20 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alejandro Colomar X-Patchwork-Id: 1994140 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=kernel.org header.i=@kernel.org header.a=rsa-sha256 header.s=k20201202 header.b=ZsfzjHG8; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=8.43.85.97; helo=server2.sourceware.org; envelope-from=gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=patchwork.ozlabs.org) Received: from server2.sourceware.org (server2.sourceware.org [8.43.85.97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4XN9JV0Bf7z1xsn for ; Tue, 8 Oct 2024 20:12:08 +1100 (AEDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id B003C386182F for ; Tue, 8 Oct 2024 09:12:06 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from nyc.source.kernel.org (nyc.source.kernel.org [147.75.193.91]) by sourceware.org (Postfix) with ESMTPS id BA26D3858D29 for ; Tue, 8 Oct 2024 09:11:30 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org BA26D3858D29 Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=kernel.org Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=kernel.org ARC-Filter: OpenARC Filter v1.0.0 sourceware.org BA26D3858D29 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=147.75.193.91 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1728378695; cv=none; b=fhl5uPmLJ4lhSfF8JgLUw2rMBzvDIIa+PEEreIFMXMyQl7J0BmiqyL/GvwLWvU0SkUEI0jTKv/OoBzgB+jnDFQp2OeEwpOygnQxzmChtcqanRZUDxhYKQz84GI/zT+whnb85iU676O1gQmgLBLiVhUkeX7bjLiYp+Jyz0LLbDqQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1728378695; c=relaxed/simple; bh=vlxfVKDXXwiPgGdQJSmPu1ceSnJvZaI5oAPY3kxKH4s=; h=DKIM-Signature:Date:From:To:Subject:Message-ID:MIME-Version; b=SzLVFXV0j37cUHkk8INc6W203EsCTLoq7pX4IzpX7BxAvkOttV40JVqxnxgzeZ8uprgisKnR9Djhjl8C6ud93NVseitkAg61Z/DJIVb8sIxb+csBc3+WgNQiEeODW85+ADVVdU2NPcjBshqr+5n5DGPBgWBmpMEo8QnXMqlhrr8= ARC-Authentication-Results: i=1; server2.sourceware.org Received: from smtp.kernel.org (transwarp.subspace.kernel.org [100.75.92.58]) by nyc.source.kernel.org (Postfix) with ESMTP id 037AEA433EC; Tue, 8 Oct 2024 09:11:21 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 48A23C4CEC7; Tue, 8 Oct 2024 09:11:22 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1728378689; bh=vlxfVKDXXwiPgGdQJSmPu1ceSnJvZaI5oAPY3kxKH4s=; h=Date:From:To:Cc:Subject:References:In-Reply-To:From; b=ZsfzjHG87FLvUuPaGaVl6dKO7SgdxF6d8QZi2I9C2iDvl0GcW64X7nyfoImjlhrER 3vxw7/T8A6ghq2ol9rIMO/CKrdfzza7af8TzfodqgnDmq8goyn4MXuSTPW1qt1RD7P d0NTicJspkh2iYYKfTf3z9Rwd6r4rpucDeAQyTyeMk5pCc8zw6aBI3tRmJT9+RTrlv W+6LXUjY+Bkfe9SLZSJ1KpAYMckclG08IbFMTyT9h4Wri6357uicLVPa1yDa/vVWQ4 pr5FdzoAAfPG3fYYcCytxzwJ29469WUK04edvAcacGU+fBCUgWvOyNF17wv5eCU2nq NgROmjAvtvdEg== Date: Tue, 8 Oct 2024 11:11:20 +0200 From: Alejandro Colomar To: gcc-patches@gcc.gnu.org Cc: Alejandro Colomar , Gabriel Ravier , Jakub Jelinek , Kees Cook , Qing Zhao , Jens Gustedt , David Brown , Florian Weimer , Andreas Schwab , Timm Baeder , Daniel Plakosh , "A. Jiang" , Eugene Zelenko , Aaron Ballman , Paul Koning , Daniel Lundin , Nikolaos Strimpas , JeanHeyd Meneide , Fernando Borretti , Jonathan Protzenko , Chris Bazley , Ville Voutilainen , Alex Celeste , Jakub =?utf-8?q?=C5=81ukasiewicz?= , Douglas McIlroy , Jason Merrill , Xavier Del Campo Romero , Siddhesh Poyarekar , DJ Delorie , Carlos O'Donell , Stephen@debian, Coady@debian, Joseph Myers , Martin Uecker , "Gustavo A. R. Silva" , Patrizia Kaye , Ori Bernstein , Robert Seacord Subject: [PATCH v14 0/4] c: Add __countof__ operator Message-ID: X-Mailer: git-send-email 2.45.2 References: <20240728141547.302478-1-alx@kernel.org> MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: <20240728141547.302478-1-alx@kernel.org> X-Spam-Status: No, score=-4.0 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, KAM_SHORT, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org Hi! Here's v14 with some changes: A) Rename s/__lengthof__/__countof__/ (rationale(s) below). B) Remove the concept "top-level array" from the docs (rationale below). At the bottom of this email is a range diff comparing to v13. A.1) WG14 had only weak consensus for prefering lengthof over nelementsof or countof. And it didn't really address my concerns of overloading the term length. "length" is currently exclusively used in C to refer to the number of non-zero characters in a string; at least in a consistent manner. In uses in the wild, 'len' rarely appears in a variable name that refers to the number of elements of an array. In ISO C, one may be led to think that VLA uses the term length to refer to the number of elements of the array; but it actually refers to the size[1]. There are a few residual uses of length to inconsistently refer to the number of elements of an array, but they are only colloquial uses with no major relevance. [1]: On the other hand, there's a consistent use of 'n' as a name of a variable to refer to the *n*umber of elements of an array. A novel overload of the term length to refer to the number of elements of an array would be dangerous, as it would naturally promote the use of 'len' as a variable name for holding the number of elements, which would cause confusion with the length of strings contained in such arrays, and cause off-by-one bugs, which would in turn result in buffer overflows. This is a security issue that must be addressed. lengthof cannot be a name for this operator. A.2) Another argument that was used in favour of length is that other widely used languages like Python use length to refer to the number of elements of an array, and for consistency with those languages we should follow. That omits the fact that those languages don't use null-terminated strings, and thus they don't have the security problem that C would have by overloading length. In Python, it would seem natural to have length mean the number of elements of , be it number of elements of an array, or number of elements of a string. It won't result in off-by-one bugs and buffer overflows, as would in C. A.3) While nelementsof() was considered too long of a name by some, we can use countof(), which is even shorter than lengthof() (by one byte), and cannot be confused with anything else that currently exists in the language. Also, countof() is consistent with the similar __counted_by() attribute. B) C does not have multi-dimensional arrays. It has a very generic way of composing aggregate types that allows one to think of multidimensional arrays, but they're not a distinct concept in the language. I've changed the manual to use language that is simpler, and more consistent with how C really is. I will present a new paper to WG14 for the next meeting, proposing countof(). This proposal uses double underscores because C2y is too far, and even if we used the same name as WG14 wants, we would prefer to have a name that is under our control, in case WG14 changes anything before the release of C2y. Have a lovely day! Alex Alejandro Colomar (4): contrib/: Add support for Cc: and Link: tags gcc/: Rename array_type_nelts() => array_type_nelts_minus_one() Merge definitions of array_type_nelts_top() c: Add __countof__ operator contrib/gcc-changelog/git_commit.py | 5 +- gcc/c-family/c-common.cc | 26 +++++ gcc/c-family/c-common.def | 3 + gcc/c-family/c-common.h | 2 + gcc/c/c-decl.cc | 32 ++++-- gcc/c/c-fold.cc | 7 +- gcc/c/c-parser.cc | 62 +++++++--- gcc/c/c-tree.h | 4 + gcc/c/c-typeck.cc | 118 ++++++++++++++++++- gcc/config/aarch64/aarch64.cc | 2 +- gcc/config/i386/i386.cc | 2 +- gcc/cp/cp-tree.h | 1 - gcc/cp/decl.cc | 2 +- gcc/cp/init.cc | 8 +- gcc/cp/lambda.cc | 3 +- gcc/cp/operators.def | 1 + gcc/cp/tree.cc | 13 --- gcc/doc/extend.texi | 30 +++++ gcc/expr.cc | 8 +- gcc/fortran/trans-array.cc | 2 +- gcc/fortran/trans-openmp.cc | 4 +- gcc/rust/backend/rust-tree.cc | 13 --- gcc/rust/backend/rust-tree.h | 2 - gcc/target.h | 3 + gcc/testsuite/gcc.dg/countof-compile.c | 115 +++++++++++++++++++ gcc/testsuite/gcc.dg/countof-vla.c | 46 ++++++++ gcc/testsuite/gcc.dg/countof.c | 150 +++++++++++++++++++++++++ gcc/tree.cc | 17 ++- gcc/tree.h | 3 +- 29 files changed, 604 insertions(+), 80 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/countof-compile.c create mode 100644 gcc/testsuite/gcc.dg/countof-vla.c create mode 100644 gcc/testsuite/gcc.dg/countof.c Range-diff against v13: 1: d7fca49888a = 1: d7fca49888a contrib/: Add support for Cc: and Link: tags 2: e65245ac294 = 2: e65245ac294 gcc/: Rename array_type_nelts() => array_type_nelts_minus_one() 3: 03de2d67bb1 = 3: 03de2d67bb1 Merge definitions of array_type_nelts_top() 4: f635871da1f ! 4: 6714852dd93 c: Add __lengthof__ operator @@ Metadata Author: Alejandro Colomar ## Commit message ## - c: Add __lengthof__ operator + c: Add __countof__ operator This operator is similar to sizeof but can only be applied to an array, and returns its number of elements. @@ Commit message gcc/ChangeLog: - * doc/extend.texi: Document __lengthof__ operator. - * target.h (enum type_context_kind): Add __lengthof__ operator. + * doc/extend.texi: Document __countof__ operator. + * target.h (enum type_context_kind): Add __countof__ operator. gcc/c-family/ChangeLog: * c-common.h * c-common.def: - * c-common.cc (c_lengthof_type): Add __lengthof__ operator. + * c-common.cc (c_countof_type): Add __countof__ operator. gcc/c/ChangeLog: * c-tree.h - (c_expr_lengthof_expr, c_expr_lengthof_type) + (c_expr_countof_expr, c_expr_countof_type) * c-decl.cc (start_struct, finish_struct) (start_enum, finish_enum) * c-parser.cc (c_parser_sizeof_expression) - (c_parser_lengthof_expression) - (c_parser_sizeof_or_lengthof_expression) + (c_parser_countof_expression) + (c_parser_sizeof_or_countof_expression) (c_parser_unary_expression) * c-typeck.cc (build_external_ref) (record_maybe_used_decl, pop_maybe_used) (is_top_array_vla) - (c_expr_lengthof_expr, c_expr_lengthof_type): - Add __lengthof__operator. + (c_expr_countof_expr, c_expr_countof_type): + Add __countof__operator. gcc/cp/ChangeLog: - * operators.def: Add __lengthof__ operator. + * operators.def: Add __countof__ operator. gcc/testsuite/ChangeLog: - * gcc.dg/lengthof-compile.c - * gcc.dg/lengthof-vla.c - * gcc.dg/lengthof.c: Add tests for __lengthof__ operator. + * gcc.dg/countof-compile.c + * gcc.dg/countof-vla.c + * gcc.dg/countof.c: Add tests for __countof__ operator. Link: + Link: + Link: Link: Link: Cc: Joseph Myers @@ gcc/c-family/c-common.cc: const struct c_common_resword c_common_reswords[] = { "__inline", RID_INLINE, 0 }, { "__inline__", RID_INLINE, 0 }, { "__label__", RID_LABEL, 0 }, -+ { "__lengthof__", RID_LENGTHOF, 0 }, ++ { "__countof__", RID_COUNTOF, 0 }, { "__null", RID_NULL, 0 }, { "__real", RID_REALPART, 0 }, { "__real__", RID_REALPART, 0 }, @@ gcc/c-family/c-common.cc: c_alignof_expr (location_t loc, tree expr) + Return the number of elements of an array. */ + +tree -+c_lengthof_type (location_t loc, tree type) ++c_countof_type (location_t loc, tree type) +{ + enum tree_code type_code; + + type_code = TREE_CODE (type); + if (type_code != ARRAY_TYPE) + { -+ error_at (loc, "invalid application of % to type %qT", type); ++ error_at (loc, "invalid application of % to type %qT", type); + return error_mark_node; + } + if (!COMPLETE_TYPE_P (type)) + { + error_at (loc, -+ "invalid application of % to incomplete type %qT", ++ "invalid application of % to incomplete type %qT", + type); + return error_mark_node; + } @@ gcc/c-family/c-common.def: DEFTREECODE (EXCESS_PRECISION_EXPR, "excess_precision number. */ DEFTREECODE (USERDEF_LITERAL, "userdef_literal", tcc_exceptional, 3) -+/* Represents a 'lengthof' expression. */ -+DEFTREECODE (LENGTHOF_EXPR, "lengthof_expr", tcc_expression, 1) ++/* Represents a 'countof' expression. */ ++DEFTREECODE (COUNTOF_EXPR, "countof_expr", tcc_expression, 1) + /* Represents a 'sizeof' expression during C++ template expansion, or for the purpose of -Wsizeof-pointer-memaccess warning. */ @@ gcc/c-family/c-common.h: enum rid /* C extensions */ RID_ASM, RID_TYPEOF, RID_TYPEOF_UNQUAL, RID_ALIGNOF, RID_ATTRIBUTE, -+ RID_LENGTHOF, ++ RID_COUNTOF, RID_VA_ARG, RID_EXTENSION, RID_IMAGPART, RID_REALPART, RID_LABEL, RID_CHOOSE_EXPR, RID_TYPES_COMPATIBLE_P, RID_BUILTIN_COMPLEX, RID_BUILTIN_SHUFFLE, @@ gcc/c-family/c-common.h: extern tree c_common_truthvalue_conversion (location_t, extern void c_apply_type_quals_to_decl (int, tree); extern tree c_sizeof_or_alignof_type (location_t, tree, bool, bool, int); extern tree c_alignof_expr (location_t, tree); -+extern tree c_lengthof_type (location_t, tree); ++extern tree c_countof_type (location_t, tree); /* Print an error message for invalid operands to arith operation CODE. NOP_EXPR is used as a special case (see truthvalue_conversion). */ extern void binary_op_error (rich_location *, enum tree_code, tree, tree); @@ gcc/c/c-decl.cc: start_struct (location_t loc, enum tree_code code, tree name, sizeof anyhow. */ - if (warn_cxx_compat && (in_sizeof || in_typeof || in_alignof)) + if (warn_cxx_compat -+ && (in_sizeof || in_typeof || in_alignof || in_lengthof)) ++ && (in_sizeof || in_typeof || in_alignof || in_countof)) warning_at (loc, OPT_Wc___compat, "defining type in %qs expression is invalid in C++", (in_sizeof @@ gcc/c/c-decl.cc: start_struct (location_t loc, enum tree_code code, tree name, + ? "typeof" + : (in_alignof + ? "alignof" -+ : "lengthof")))); ++ : "countof")))); if (in_underspecified_init) error_at (loc, "%qT defined in underspecified object initializer", ref); @@ gcc/c/c-decl.cc: finish_struct (location_t loc, tree t, tree fieldlist, tree att if (warn_cxx_compat && struct_parse_info != NULL - && !in_sizeof && !in_typeof && !in_alignof) -+ && !in_sizeof && !in_typeof && !in_alignof && !in_lengthof) ++ && !in_sizeof && !in_typeof && !in_alignof && !in_countof) struct_parse_info->struct_types.safe_push (t); } @@ gcc/c/c-decl.cc: start_enum (location_t loc, struct c_enum_contents *the_enum, t as C++ doesn't permit statement exprs within sizeof anyhow. */ - if (warn_cxx_compat && (in_sizeof || in_typeof || in_alignof)) + if (warn_cxx_compat -+ && (in_sizeof || in_typeof || in_alignof || in_lengthof)) ++ && (in_sizeof || in_typeof || in_alignof || in_countof)) warning_at (loc, OPT_Wc___compat, "defining type in %qs expression is invalid in C++", (in_sizeof @@ gcc/c/c-decl.cc: start_enum (location_t loc, struct c_enum_contents *the_enum, t + ? "typeof" + : (in_alignof + ? "alignof" -+ : "lengthof")))); ++ : "countof")))); if (in_underspecified_init) error_at (loc, "%qT defined in underspecified object initializer", @@ gcc/c/c-decl.cc: finish_enum (tree enumtype, tree values, tree attributes) if (warn_cxx_compat && struct_parse_info != NULL - && !in_sizeof && !in_typeof && !in_alignof) -+ && !in_sizeof && !in_typeof && !in_alignof && !in_lengthof) ++ && !in_sizeof && !in_typeof && !in_alignof && !in_countof) struct_parse_info->struct_types.safe_push (enumtype); /* Check for consistency with previous definition */ @@ gcc/c/c-parser.cc: along with GCC; see the file COPYING3. If not see + +#define c_parser_sizeof_expression(parser) \ +( \ -+ c_parser_sizeof_or_lengthof_expression (parser, RID_SIZEOF) \ ++ c_parser_sizeof_or_countof_expression (parser, RID_SIZEOF) \ +) -+#define c_parser_lengthof_expression(parser) \ ++#define c_parser_countof_expression(parser) \ +( \ -+ c_parser_sizeof_or_lengthof_expression (parser, RID_LENGTHOF) \ ++ c_parser_sizeof_or_countof_expression (parser, RID_COUNTOF) \ +) + /* We need to walk over decls with incomplete struct/union/enum types @@ gcc/c/c-parser.cc: static struct c_expr c_parser_binary_expression (c_parser *, static struct c_expr c_parser_cast_expression (c_parser *, struct c_expr *); static struct c_expr c_parser_unary_expression (c_parser *); -static struct c_expr c_parser_sizeof_expression (c_parser *); -+static struct c_expr c_parser_sizeof_or_lengthof_expression (c_parser *, -+ enum rid); ++static struct c_expr c_parser_sizeof_or_countof_expression (c_parser *, ++ enum rid); static struct c_expr c_parser_alignof_expression (c_parser *); static struct c_expr c_parser_postfix_expression (c_parser *); static struct c_expr c_parser_postfix_expression_after_paren_type (c_parser *, @@ gcc/c/c-parser.cc: c_parser_unary_expression (c_parser *parser) case CPP_KEYWORD: switch (c_parser_peek_token (parser)->keyword) { -+ case RID_LENGTHOF: -+ return c_parser_lengthof_expression (parser); ++ case RID_COUNTOF: ++ return c_parser_countof_expression (parser); case RID_SIZEOF: return c_parser_sizeof_expression (parser); case RID_ALIGNOF: @@ gcc/c/c-parser.cc: c_parser_unary_expression (c_parser *parser) static struct c_expr -c_parser_sizeof_expression (c_parser *parser) -+c_parser_sizeof_or_lengthof_expression (c_parser *parser, enum rid rid) ++c_parser_sizeof_or_countof_expression (c_parser *parser, enum rid rid) { -+ const char *op_name = (rid == RID_LENGTHOF) ? "lengthof" : "sizeof"; ++ const char *op_name = (rid == RID_COUNTOF) ? "countof" : "sizeof"; struct c_expr expr; struct c_expr result; location_t expr_loc; @@ gcc/c/c-parser.cc: c_parser_sizeof_expression (c_parser *parser) c_parser_consume_token (parser); c_inhibit_evaluation_warnings++; - in_sizeof++; -+ if (rid == RID_LENGTHOF) -+ in_lengthof++; ++ if (rid == RID_COUNTOF) ++ in_countof++; + else + in_sizeof++; if (c_parser_next_token_is (parser, CPP_OPEN_PAREN) @@ gcc/c/c-parser.cc: c_parser_sizeof_expression (c_parser *parser) struct c_expr ret; c_inhibit_evaluation_warnings--; - in_sizeof--; -+ if (rid == RID_LENGTHOF) -+ in_lengthof--; ++ if (rid == RID_COUNTOF) ++ in_countof--; + else + in_sizeof--; ret.set_error (); @@ gcc/c/c-parser.cc: c_parser_sizeof_expression (c_parser *parser) c_inhibit_evaluation_warnings--; - in_sizeof--; - result = c_expr_sizeof_type (expr_loc, type_name); -+ if (rid == RID_LENGTHOF) ++ if (rid == RID_COUNTOF) + { -+ in_lengthof--; -+ result = c_expr_lengthof_type (expr_loc, type_name); ++ in_countof--; ++ result = c_expr_countof_type (expr_loc, type_name); + } + else + { @@ gcc/c/c-parser.cc: c_parser_sizeof_expression (c_parser *parser) + Xof_expr: c_inhibit_evaluation_warnings--; - in_sizeof--; -+ if (rid == RID_LENGTHOF) -+ in_lengthof--; ++ if (rid == RID_COUNTOF) ++ in_countof--; + else + in_sizeof--; mark_exp_read (expr.value); @@ gcc/c/c-parser.cc: c_parser_sizeof_expression (c_parser *parser) - error_at (expr_loc, "% applied to a bit-field"); - result = c_expr_sizeof_expr (expr_loc, expr); + error_at (expr_loc, "%qs applied to a bit-field", op_name); -+ if (rid == RID_LENGTHOF) -+ result = c_expr_lengthof_expr (expr_loc, expr); ++ if (rid == RID_COUNTOF) ++ result = c_expr_countof_expr (expr_loc, expr); + else + result = c_expr_sizeof_expr (expr_loc, expr); } @@ gcc/c/c-tree.h: extern int c_type_dwarf_attribute (const_tree, int); /* in c-typeck.cc */ extern int in_alignof; extern int in_sizeof; -+extern int in_lengthof; ++extern int in_countof; extern int in_typeof; extern bool c_in_omp_for; extern bool c_omp_array_section_p; @@ gcc/c/c-tree.h: extern tree build_external_ref (location_t, tree, bool, tree *); extern void pop_maybe_used (bool); extern struct c_expr c_expr_sizeof_expr (location_t, struct c_expr); extern struct c_expr c_expr_sizeof_type (location_t, struct c_type_name *); -+extern struct c_expr c_expr_lengthof_expr (location_t, struct c_expr); -+extern struct c_expr c_expr_lengthof_type (location_t loc, -+ struct c_type_name *); ++extern struct c_expr c_expr_countof_expr (location_t, struct c_expr); ++extern struct c_expr c_expr_countof_type (location_t loc, ++ struct c_type_name *); extern struct c_expr parser_build_unary_op (location_t, enum tree_code, struct c_expr); extern struct c_expr parser_build_binary_op (location_t, @@ gcc/c/c-typeck.cc: int in_alignof; /* The level of nesting inside "sizeof". */ int in_sizeof; -+/* The level of nesting inside "lengthof". */ -+int in_lengthof; ++/* The level of nesting inside "countof". */ ++int in_countof; + /* The level of nesting inside "typeof". */ int in_typeof; @@ gcc/c/c-typeck.cc: build_external_ref (location_t loc, tree id, bool fun, tree * if (TREE_CODE (ref) == FUNCTION_DECL && !in_alignof) { - if (!in_sizeof && !in_typeof) -+ if (!in_sizeof && !in_typeof && !in_lengthof) ++ if (!in_sizeof && !in_typeof && !in_countof) C_DECL_USED (ref) = 1; else if (DECL_INITIAL (ref) == NULL_TREE && DECL_EXTERNAL (ref) @@ gcc/c/c-typeck.cc: struct maybe_used_decl /* The decl. */ tree decl; - /* The level seen at (in_sizeof + in_typeof). */ -+ /* The level seen at (in_sizeof + in_typeof + in_lengthof). */ ++ /* The level seen at (in_sizeof + in_typeof + in_countof). */ int level; /* The next one at this level or above, or NULL. */ struct maybe_used_decl *next; @@ gcc/c/c-typeck.cc: record_maybe_used_decl (tree decl) struct maybe_used_decl *t = XOBNEW (&parser_obstack, struct maybe_used_decl); t->decl = decl; - t->level = in_sizeof + in_typeof; -+ t->level = in_sizeof + in_typeof + in_lengthof; ++ t->level = in_sizeof + in_typeof + in_countof; t->next = maybe_used_decls; maybe_used_decls = t; } @@ gcc/c/c-typeck.cc: void { struct maybe_used_decl *p = maybe_used_decls; - int cur_level = in_sizeof + in_typeof; -+ int cur_level = in_sizeof + in_typeof + in_lengthof; ++ int cur_level = in_sizeof + in_typeof + in_countof; while (p && p->level > cur_level) { if (used) @@ gcc/c/c-typeck.cc: c_expr_sizeof_type (location_t loc, struct c_type_name *t) + return var; +} + -+/* Return the result of lengthof applied to EXPR. */ ++/* Return the result of countof applied to EXPR. */ + +struct c_expr -+c_expr_lengthof_expr (location_t loc, struct c_expr expr) ++c_expr_countof_expr (location_t loc, struct c_expr expr) +{ + struct c_expr ret; + if (expr.value == error_mark_node) @@ gcc/c/c-typeck.cc: c_expr_sizeof_type (location_t loc, struct c_type_name *t) + + tree folded_expr = c_fully_fold (expr.value, require_constant_value, + &expr_const_operands); -+ ret.value = c_lengthof_type (loc, TREE_TYPE (folded_expr)); ++ ret.value = c_countof_type (loc, TREE_TYPE (folded_expr)); + c_last_sizeof_arg = expr.value; + c_last_sizeof_loc = loc; -+ ret.original_code = LENGTHOF_EXPR; ++ ret.original_code = COUNTOF_EXPR; + ret.original_type = NULL; + ret.m_decimal = 0; + if (is_top_array_vla (TREE_TYPE (folded_expr))) + { -+ /* lengthof is evaluated when given a vla. */ ++ /* countof is evaluated when given a vla. */ + ret.value = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (ret.value), + folded_expr, ret.value); + C_MAYBE_CONST_EXPR_NON_CONST (ret.value) = !expr_const_operands; @@ gcc/c/c-typeck.cc: c_expr_sizeof_type (location_t loc, struct c_type_name *t) + return ret; +} + -+/* Return the result of lengthof applied to T, a structure for the type -+ name passed to lengthof (rather than the type itself). LOC is the ++/* Return the result of countof applied to T, a structure for the type ++ name passed to countof (rather than the type itself). LOC is the + location of the original expression. */ + +struct c_expr -+c_expr_lengthof_type (location_t loc, struct c_type_name *t) ++c_expr_countof_type (location_t loc, struct c_type_name *t) +{ + tree type; + struct c_expr ret; + tree type_expr = NULL_TREE; + bool type_expr_const = true; + type = groktypename (t, &type_expr, &type_expr_const); -+ ret.value = c_lengthof_type (loc, type); ++ ret.value = c_countof_type (loc, type); + c_last_sizeof_arg = type; + c_last_sizeof_loc = loc; -+ ret.original_code = LENGTHOF_EXPR; ++ ret.original_code = COUNTOF_EXPR; + ret.original_type = NULL; + ret.m_decimal = 0; + if (type == error_mark_node) @@ gcc/c/c-typeck.cc: c_expr_sizeof_type (location_t loc, struct c_type_name *t) + { + /* If the type is a [*] array, it is a VLA but is represented as + having a size of zero. In such a case we must ensure that -+ the result of lengthof does not get folded to a constant by ++ the result of countof does not get folded to a constant by + c_fully_fold, because if the length is evaluated the result is + not constant and so constraints on zero or negative size -+ arrays must not be applied when this lengthof call is inside ++ arrays must not be applied when this countof call is inside + another array declarator. */ + if (!type_expr) + type_expr = integer_zero_node; @@ gcc/cp/operators.def: DEF_OPERATOR ("co_await", CO_AWAIT_EXPR, "aw", OVL_OP_FLAG /* These are extensions. */ DEF_OPERATOR ("alignof", ALIGNOF_EXPR, "az", OVL_OP_FLAG_UNARY) -+DEF_OPERATOR ("__lengthof__", LENGTHOF_EXPR, "lz", OVL_OP_FLAG_UNARY) ++DEF_OPERATOR ("__countof__", COUNTOF_EXPR, "lz", OVL_OP_FLAG_UNARY) DEF_OPERATOR ("__imag__", IMAGPART_EXPR, "v18__imag__", OVL_OP_FLAG_UNARY) DEF_OPERATOR ("__real__", REALPART_EXPR, "v18__real__", OVL_OP_FLAG_UNARY) @@ gcc/doc/extend.texi: If the operand of the @code{__alignof__} expression is a fu the expression evaluates to the alignment of the function which may be specified by attribute @code{aligned} (@pxref{Common Function Attributes}). -+@node lengthof ++@node countof +@section Determining the Number of Elements of Arrays -+@cindex lengthof ++@cindex countof +@cindex number of elements + -+The keyword @code{__lengthof__} determines the length of an array operand, ++The keyword @code{__countof__} determines the length of an array operand, +that is, the number of elements in the array. +Its syntax is similar to @code{sizeof}. +The operand must be @@ gcc/doc/extend.texi: If the operand of the @code{__alignof__} expression is a fu + +@smallexample +int a[n]; -+__lengthof__ (a); // returns n -+__lengthof__ (int [7][3]); // returns 7 ++__countof__ (a); // returns n ++__countof__ (int [7][3]); // returns 7 +@end smallexample + +The result of this operator is an integer constant expression, -+unless the top-level array is a variable-length array. ++unless the array has a variable number of elements. +The operand is only evaluated -+if the top-level array is a variable-length array. ++if the array has a variable number of elements. +For example: + +@smallexample -+__lengthof__ (int [7][n++]); // integer constant expression -+__lengthof__ (int [n++][7]); // run-time value; n++ is evaluated ++__countof__ (int [7][n++]); // integer constant expression ++__countof__ (int [n++][7]); // run-time value; n++ is evaluated +@end smallexample + @node Inline @@ gcc/target.h: enum type_context_kind { TCTX_ALIGNOF, + /* Directly measuring the number of elements of array T. */ -+ TCTX_LENGTHOF, ++ TCTX_COUNTOF, + /* Creating objects of type T with static storage duration. */ TCTX_STATIC_STORAGE, - ## gcc/testsuite/gcc.dg/nelementsof-compile.c (new) ## + ## gcc/testsuite/gcc.dg/countof-compile.c (new) ## @@ +/* { dg-do compile } */ +/* { dg-options "-Wno-declaration-after-statement -Wno-pedantic -Wno-vla" } */ @@ gcc/testsuite/gcc.dg/nelementsof-compile.c (new) +static int w[] = {1, 2, 3}; + +static int z[0]; -+static int y[__lengthof__(z)]; ++static int y[__countof__(z)]; + +void +automatic(void) +{ -+ __lengthof__ (w); ++ __countof__ (w); +} + +void +incomplete (int p[]) +{ -+ __lengthof__ (x); /* { dg-error "incomplete" } */ ++ __countof__ (x); /* { dg-error "incomplete" } */ + + /* We want to support the following one in the future, + but for now it should fail. */ -+ __lengthof__ (p); /* { dg-error "invalid" } */ ++ __countof__ (p); /* { dg-error "invalid" } */ +} + +void @@ gcc/testsuite/gcc.dg/nelementsof-compile.c (new) + int fam[]; + } s; + -+ __lengthof__ (s.fam); /* { dg-error "incomplete" } */ ++ __countof__ (s.fam); /* { dg-error "incomplete" } */ +} + -+void fix_fix (int i, char (*a)[3][5], int (*x)[__lengthof__ (*a)]); -+void fix_var (int i, char (*a)[3][i], int (*x)[__lengthof__ (*a)]); -+void fix_uns (int i, char (*a)[3][*], int (*x)[__lengthof__ (*a)]); ++void fix_fix (int i, char (*a)[3][5], int (*x)[__countof__ (*a)]); ++void fix_var (int i, char (*a)[3][i], int (*x)[__countof__ (*a)]); ++void fix_uns (int i, char (*a)[3][*], int (*x)[__countof__ (*a)]); + +void +func (void) @@ gcc/testsuite/gcc.dg/nelementsof-compile.c (new) + int x[3]; + } s; + -+ __lengthof__ (x); /* { dg-error "invalid" } */ -+ __lengthof__ (int); /* { dg-error "invalid" } */ -+ __lengthof__ (s); /* { dg-error "invalid" } */ -+ __lengthof__ (struct s); /* { dg-error "invalid" } */ -+ __lengthof__ (&x); /* { dg-error "invalid" } */ -+ __lengthof__ (p); /* { dg-error "invalid" } */ -+ __lengthof__ (int *); /* { dg-error "invalid" } */ -+ __lengthof__ (&s.x); /* { dg-error "invalid" } */ -+ __lengthof__ (int (*)[3]); /* { dg-error "invalid" } */ ++ __countof__ (x); /* { dg-error "invalid" } */ ++ __countof__ (int); /* { dg-error "invalid" } */ ++ __countof__ (s); /* { dg-error "invalid" } */ ++ __countof__ (struct s); /* { dg-error "invalid" } */ ++ __countof__ (&x); /* { dg-error "invalid" } */ ++ __countof__ (p); /* { dg-error "invalid" } */ ++ __countof__ (int *); /* { dg-error "invalid" } */ ++ __countof__ (&s.x); /* { dg-error "invalid" } */ ++ __countof__ (int (*)[3]); /* { dg-error "invalid" } */ +} + +static int f1(); @@ gcc/testsuite/gcc.dg/nelementsof-compile.c (new) +{ + int b[n][n]; + -+ __lengthof__ (a[f1()]); -+ __lengthof__ (b[f2()]); ++ __countof__ (a[f1()]); ++ __countof__ (b[f2()]); +} + +void +no_parens(void) +{ -+ __lengthof__ a; -+ __lengthof__ *a; -+ __lengthof__ (int [3]) {}; ++ __countof__ a; ++ __countof__ *a; ++ __countof__ (int [3]) {}; + -+ __lengthof__ int [3]; /* { dg-error "expected expression before" } */ ++ __countof__ int [3]; /* { dg-error "expected expression before" } */ +} + +void @@ gcc/testsuite/gcc.dg/nelementsof-compile.c (new) +{ + int n = 7; + -+ _Static_assert (__lengthof__ (int [3][n]) == 3); -+ _Static_assert (__lengthof__ (int [n][3]) == 7); /* { dg-error "not constant" } */ -+ _Static_assert (__lengthof__ (int [0][3]) == 0); -+ _Static_assert (__lengthof__ (int [0]) == 0); ++ _Static_assert (__countof__ (int [3][n]) == 3); ++ _Static_assert (__countof__ (int [n][3]) == 7); /* { dg-error "not constant" } */ ++ _Static_assert (__countof__ (int [0][3]) == 0); ++ _Static_assert (__countof__ (int [0]) == 0); + -+ /* FIXME: lengthof(int [0][n]) should result in a constant expression. */ -+ _Static_assert (__lengthof__ (int [0][n]) == 0); /* { dg-error "not constant" } */ ++ /* FIXME: countof(int [0][n]) should result in a constant expression. */ ++ _Static_assert (__countof__ (int [0][n]) == 0); /* { dg-error "not constant" } */ +} - ## gcc/testsuite/gcc.dg/nelementsof-vla.c (new) ## + ## gcc/testsuite/gcc.dg/countof-vla.c (new) ## @@ +/* { dg-do compile } */ +/* { dg-options "-Wno-pedantic -Wvla-parameter" } */ + +void fix_fix (int i, + char (*a)[3][5], -+ int (*x)[__lengthof__ (*a)]); ++ int (*x)[__countof__ (*a)]); +void fix_var (int i, + char (*a)[3][i], /* dg-warn "variable" */ -+ int (*x)[__lengthof__ (*a)]); ++ int (*x)[__countof__ (*a)]); +void fix_uns (int i, + char (*a)[3][*], -+ int (*x)[__lengthof__ (*a)]); ++ int (*x)[__countof__ (*a)]); + +void zro_fix (int i, + char (*a)[0][5], -+ int (*x)[__lengthof__ (*a)]); ++ int (*x)[__countof__ (*a)]); +void zro_var (int i, + char (*a)[0][i], /* dg-warn "variable" */ -+ int (*x)[__lengthof__ (*a)]); ++ int (*x)[__countof__ (*a)]); +void zro_uns (int i, + char (*a)[0][*], -+ int (*x)[__lengthof__ (*a)]); ++ int (*x)[__countof__ (*a)]); + +void var_fix (int i, + char (*a)[i][5], /* dg-warn "variable" */ -+ int (*x)[__lengthof__ (*a)]); /* dg-warn "variable" */ ++ int (*x)[__countof__ (*a)]); /* dg-warn "variable" */ +void var_var (int i, + char (*a)[i][i], /* dg-warn "variable" */ -+ int (*x)[__lengthof__ (*a)]); /* dg-warn "variable" */ ++ int (*x)[__countof__ (*a)]); /* dg-warn "variable" */ +void var_uns (int i, + char (*a)[i][*], /* dg-warn "variable" */ -+ int (*x)[__lengthof__ (*a)]); /* dg-warn "variable" */ ++ int (*x)[__countof__ (*a)]); /* dg-warn "variable" */ + +void uns_fix (int i, + char (*a)[*][5], -+ int (*x)[__lengthof__ (*a)]); ++ int (*x)[__countof__ (*a)]); +void uns_var (int i, + char (*a)[*][i], /* dg-warn "variable" */ -+ int (*x)[__lengthof__ (*a)]); ++ int (*x)[__countof__ (*a)]); +void uns_uns (int i, + char (*a)[*][*], -+ int (*x)[__lengthof__ (*a)]); ++ int (*x)[__countof__ (*a)]); + +// Can't test due to bug: +//static int z2[0]; -+//static int y2[__lengthof__(z2)]; ++//static int y2[__countof__(z2)]; - ## gcc/testsuite/gcc.dg/nelementsof.c (new) ## + ## gcc/testsuite/gcc.dg/countof.c (new) ## @@ +/* { dg-do run } */ +/* { dg-options "-Wno-declaration-after-statement -Wno-pedantic -Wno-vla" } */ @@ gcc/testsuite/gcc.dg/nelementsof.c (new) +{ + short a[7]; + -+ static_assert (__lengthof__ (a) == 7); -+ static_assert (__lengthof__ (long [0]) == 0); -+ static_assert (__lengthof__ (unsigned [99]) == 99); ++ static_assert (__countof__ (a) == 7); ++ static_assert (__countof__ (long [0]) == 0); ++ static_assert (__countof__ (unsigned [99]) == 99); +} + +void @@ gcc/testsuite/gcc.dg/nelementsof.c (new) + int a[] = {1, 2, 3}; + int z[] = {}; + -+ static_assert (__lengthof__ (a) == 3); -+ static_assert (__lengthof__ (z) == 0); ++ static_assert (__countof__ (a) == 3); ++ static_assert (__countof__ (z) == 0); +} + +void @@ gcc/testsuite/gcc.dg/nelementsof.c (new) + unsigned n; + + n = 99; -+ assert (__lengthof__ (short [n - 10]) == 99 - 10); ++ assert (__countof__ (short [n - 10]) == 99 - 10); + + int v[n / 2]; -+ assert (__lengthof__ (v) == 99 / 2); ++ assert (__countof__ (v) == 99 / 2); + + n = 0; + int z[n]; -+ assert (__lengthof__ (z) == 0); ++ assert (__countof__ (z) == 0); +} + +void @@ gcc/testsuite/gcc.dg/nelementsof.c (new) + int a[8]; + } s; + -+ static_assert (__lengthof__ (s.a) == 8); ++ static_assert (__countof__ (s.a) == 8); +} + +void @@ gcc/testsuite/gcc.dg/nelementsof.c (new) + int i; + + i = 7; -+ assert (__lengthof__ (struct {int x;}[i++]) == 7); ++ assert (__countof__ (struct {int x;}[i++]) == 7); + assert (i == 7 + 1); + + int v[i]; + int (*p)[i]; + p = &v; -+ assert (__lengthof__ (*p++) == i); ++ assert (__countof__ (*p++) == i); + assert (p - 1 == &v); +} + @@ gcc/testsuite/gcc.dg/nelementsof.c (new) + int i; + + i = 3; -+ static_assert (__lengthof__ (struct {int x[i++];}[3]) == 3); ++ static_assert (__countof__ (struct {int x[i++];}[3]) == 3); + assert (i == 3); +} + @@ gcc/testsuite/gcc.dg/nelementsof.c (new) +array_noeval (void) +{ + long a[5]; -+ long (*p)[__lengthof__ (a)]; ++ long (*p)[__countof__ (a)]; + + p = &a; -+ static_assert (__lengthof__ (*p++) == 5); ++ static_assert (__countof__ (*p++) == 5); + assert (p == &a); +} + @@ gcc/testsuite/gcc.dg/nelementsof.c (new) +{ + int i; + -+ static_assert (__lengthof__ (int [0][4]) == 0); ++ static_assert (__countof__ (int [0][4]) == 0); + i = 3; -+ assert (__lengthof__ (int [0][i]) == 0); ++ assert (__countof__ (int [0][i]) == 0); +} + +void @@ gcc/testsuite/gcc.dg/nelementsof.c (new) +{ + int i; + -+ static_assert (__lengthof__ (int [7][4]) == 7); ++ static_assert (__countof__ (int [7][4]) == 7); + i = 3; -+ static_assert (__lengthof__ (int [7][i]) == 7); ++ static_assert (__countof__ (int [7][i]) == 7); +} + +void @@ gcc/testsuite/gcc.dg/nelementsof.c (new) + int i, j; + + i = 7; -+ assert (__lengthof__ (int [i++][4]) == 7); ++ assert (__countof__ (int [i++][4]) == 7); + assert (i == 7 + 1); + + i = 9; + j = 3; -+ assert (__lengthof__ (int [i++][j]) == 9); ++ assert (__countof__ (int [i++][j]) == 9); + assert (i == 9 + 1); +} + @@ gcc/testsuite/gcc.dg/nelementsof.c (new) + int a[7]; + int v[n]; + -+ static_assert (__lengthof__ a == 7); -+ assert (__lengthof__ v == 3); ++ static_assert (__countof__ a == 7); ++ assert (__countof__ v == 3); +} + +int