From patchwork Mon Aug 19 10:58:23 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Alejandro Colomar X-Patchwork-Id: 1973807 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=f6fOxElP; 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 4WnV3F12B5z1yg2 for ; Mon, 19 Aug 2024 20:59:17 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 8B0F1384AB4D for ; Mon, 19 Aug 2024 10:59:15 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from sin.source.kernel.org (sin.source.kernel.org [IPv6:2604:1380:40e1:4800::1]) by sourceware.org (Postfix) with ESMTPS id 2FC443858408; Mon, 19 Aug 2024 10:58:35 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 2FC443858408 Authentication-Results: sourceware.org; dmarc=pass (p=none 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 2FC443858408 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=2604:1380:40e1:4800::1 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1724065120; cv=none; b=iIYQT0/lnZ/67EBvwnfHu4z/RQd5IE0Qs2zV7jLOpV6FONCiTg3Yd8dCdbQRIiVvKMJAetlRIP7C6Bcy65ioKqtRD2Ow4E9W7Vy6VoNn5BeuicRUBayWj0LTLGjLj1KeBmaN0rSu6AWMDTScValaBfGdrEb8DjWLZlahNDMp5t8= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1724065120; c=relaxed/simple; bh=qQuWr+sBbQK3VWNx5/7HHLeMCU/chx+KNbSk6ASq8Wg=; h=DKIM-Signature:Date:From:To:Subject:Message-ID:MIME-Version; b=e072unKkgGsXI4bD0tcHMPf/01p3UharrhgBP1tOhOny5XRZB0+6+IxrpK/U+fgj7gpzujEFRUmgxD+phBRvtv4Xodcyda2v1ClM4Np3CCXKx2FGAzTWwlVwB7pn7AAH93t4SRg5U+oILc0kRcHdIRE4lMT92niRgmdHiioTGpw= ARC-Authentication-Results: i=1; server2.sourceware.org Received: from smtp.kernel.org (transwarp.subspace.kernel.org [100.75.92.58]) by sin.source.kernel.org (Postfix) with ESMTP id 44AB7CE0A51; Mon, 19 Aug 2024 10:58:31 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 3FE80C32782; Mon, 19 Aug 2024 10:58:25 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1724065110; bh=qQuWr+sBbQK3VWNx5/7HHLeMCU/chx+KNbSk6ASq8Wg=; h=Date:From:To:Cc:Subject:In-Reply-To:From; b=f6fOxElPyBDwLKJGN7ROroEdmIlvk0vLKBzCGweh27s2c4wT+M4SbHUu/glqfx6lC xywOzmao/OrJpM4Xnl+QZZRlNo8W3qCRbuO+pJePg2BMstRcCDEziYASkUpyE8RFTU yhqykDIHfLDvquA1ekoEqB3X6TBzcCpzLg54bRW6lKJa+KdnpptLwO0bwUNLwlQN2q tCX9HoLOQKm0kFGBEkYA/oOhiPY2q11iXUbk/5xBGo7o6995+QtTDkEcKbksjAAtWm Ice7RQBakZ00XpBEg5XC7QomLhkAnJLr2wWVsKYOL/S1ibcx+/oa/iomT4gkv07nmH E9IiECtT+HU6Q== Date: Mon, 19 Aug 2024 12:58:23 +0200 From: Alejandro Colomar To: gcc-patches@gcc.gnu.org Cc: Alejandro Colomar , gcc@gcc.gnu.org, Xavier Del Campo Romero , Martin Uecker , Joseph Myers , 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?= Subject: [PATCH v10 0/3] c: Add __nelementsof__ operator Message-ID: X-Mailer: git-send-email 2.45.2 MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: <20240728141547.302478-1-alx@kernel.org> X-Spam-Status: No, score=-3.9 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, T_SCC_BODY_TEXT_LINE 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! This is v10 of this patch set; hopefully, we're close to an end. I've already submitted a proposal for C2y to WG14, as n3313: For those who haven't been following since the start, the entire thread of patch set revisions and their discussions can be found here: It also contains drafts of the n3313 proposal. Changes since v9: - Rename s/__elementsof__/__nelementsof__/ elementsof() doesn't mean in English something compatible with its programming semantics. While there's existing uses of it in programming, that's an abuse of English, which could cause confusion, or maybe preclude a more appropriate use of that name in the future. nelementsof() is just one more byte, and is much more appropriate, by being a contraction of "_n_umber (of) elements of". Also, there's only one use of nelementsof() in the wild, which makes backwards compatibility much less of a concern. That use is semantically compatible with this proposed operator. And we could just notify that project the existence of a new standard operator with that name, if we finally settle on this name. - Rebase on top of git HEAD. - CC += Daniel Lundin, Nikolaos, JeanHeyd, Fernando, Jonathan, Chris, Ville, Alex Celeste, Jakub Łukasiewicz I have a draft for an updated proposal to WG14 (more recent than n3313). It has some changes to the documentation of prior art, some typo fixes, etc., and renames elementsof()=>nelementsof(), but the meat of the proposal is the same. I've also rebased it on top of the latest draft for C2y, which is n3301. I'll send it as a reply to this subthread. This cover letter is sent to both gcc-patches@ and gcc@. The patches are only sent to gcc-patches@, and the draft for WG14 is only sent to gcc@. If anyone wants to add an `Acked-by:` (or `Reviewed-by:`), please do it explicitly. There've been some informal ones, but I prefer to pick them from explicit ones. Have a lovely day! Alex Alejandro Colomar (3): gcc/: Rename array_type_nelts() => array_type_nelts_minus_one() Merge definitions of array_type_nelts_top() c: Add __nelementsof__ operator 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 +- 28 files changed, 600 insertions(+), 79 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 v9: 1: a6aa38c9013 = 1: ab72c4cee8f gcc/: Rename array_type_nelts() => array_type_nelts_minus_one() 2: 4ce16ee4dfe ! 2: 27852be4ac0 Merge definitions of array_type_nelts_top() @@ Commit message Merge definitions of array_type_nelts_top() There were two identical definitions, and none of them are available - where they are needed for implementing __elementsof__. Merge them, and + where they are needed for implementing __nelementsof__. Merge them, and provide the single definition in gcc/tree.{h,cc}, where it's available - for __elementsof__, which will be added in the following commit. + for __nelementsof__, which will be added in the following commit. gcc/ChangeLog: 3: caae5dbecb3 ! 3: 9c78ce1f66d c: Add __elementsof__ operator @@ Metadata Author: Alejandro Colomar ## Commit message ## - c: Add __elementsof__ operator + c: Add __nelementsof__ operator This operator is similar to sizeof but can only be applied to an array, and returns its number of elements. @@ Commit message Cc: Eugene Zelenko Cc: Aaron Ballman Cc: Paul Koning + Cc: Daniel Lundin + Cc: Nikolaos Strimpas + Cc: JeanHeyd Meneide + Cc: Fernando Borretti + Cc: Jonathan Protzenko + Cc: Chris Bazley + Cc: Ville Voutilainen + Cc: Alex Celeste + Cc: Jakub Łukasiewicz gcc/ChangeLog: - * doc/extend.texi: Document __elementsof__ operator. - * target.h (enum type_context_kind): Add __elementsof__ operator. + * doc/extend.texi: Document __nelementsof__ operator. + * target.h (enum type_context_kind): Add __nelementsof__ operator. gcc/c-family/ChangeLog: * c-common.h: * c-common.def: - * c-common.cc (c_elementsof_type): Add __elementsof__ operator. + * c-common.cc (c_nelementsof_type): Add __nelementsof__ operator. gcc/c/ChangeLog: * c-tree.h - (c_expr_elementsof_expr, c_expr_elementsof_type): + (c_expr_nelementsof_expr, c_expr_nelementsof_type): * c-decl.cc (start_struct, finish_struct): (start_enum, finish_enum): * c-parser.cc (c_parser_sizeof_expression): - (c_parser_elementsof_expression): - (c_parser_sizeof_or_elementsof_expression): + (c_parser_nelementsof_expression): + (c_parser_sizeof_or_nelementsof_expression): (c_parser_unary_expression): * c-typeck.cc (build_external_ref): (record_maybe_used_decl, pop_maybe_used): (is_top_array_vla): - (c_expr_elementsof_expr, c_expr_elementsof_type): - Add __elementsof__operator. + (c_expr_nelementsof_expr, c_expr_nelementsof_type): + Add __nelementsof__operator. gcc/cp/ChangeLog: - * operators.def: Add __elementsof__ operator. + * operators.def: Add __nelementsof__ operator. gcc/testsuite/ChangeLog: - * gcc.dg/elementsof-compile.c: - * gcc.dg/elementsof-vla.c: - * gcc.dg/elementsof.c: Add tests for __elementsof__ operator. + * gcc.dg/nelementsof-compile.c: + * gcc.dg/nelementsof-vla.c: + * gcc.dg/nelementsof.c: Add tests for __nelementsof__ operator. - Link: https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2529.pdf + Link: https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3313.pdf Link: https://inbox.sourceware.org/gcc/M8S4oQy--3-2@tutanota.com/T/ Link: https://github.com/llvm/llvm-project/issues/102836 Suggested-by: Xavier Del Campo Romero @@ 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 }, -+ { "__elementsof__", RID_ELEMENTSOF, 0 }, ++ { "__nelementsof__", RID_NELEMENTSOF, 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_elementsof_type (location_t loc, tree type) ++c_nelementsof_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 'elementsof' expression. */ -+DEFTREECODE (ELEMENTSOF_EXPR, "elementsof_expr", tcc_expression, 1) ++/* Represents a 'nelementsof' expression. */ ++DEFTREECODE (NELEMENTSOF_EXPR, "nelementsof_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_ELEMENTSOF, ++ RID_NELEMENTSOF, 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_elementsof_type (location_t, tree); ++extern tree c_nelementsof_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_elementsof)) ++ && (in_sizeof || in_typeof || in_alignof || in_nelementsof)) 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" -+ : "elementsof")))); ++ : "nelementsof")))); 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_elementsof) ++ && !in_sizeof && !in_typeof && !in_alignof && !in_nelementsof) 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 within sizeof in a statement expr. 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_elementsof)) ++ if (warn_cxx_compat ++ && (in_sizeof || in_typeof || in_alignof || in_nelementsof)) 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" -+ : "elementsof")))); ++ : "nelementsof")))); 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_elementsof) ++ && !in_sizeof && !in_typeof && !in_alignof && !in_nelementsof) 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_elementsof_expression (parser, RID_SIZEOF) \ ++ c_parser_sizeof_or_nelementsof_expression (parser, RID_SIZEOF) \ +) -+#define c_parser_elementsof_expression(parser) \ ++#define c_parser_nelementsof_expression(parser) \ +( \ -+ c_parser_sizeof_or_elementsof_expression (parser, RID_ELEMENTSOF) \ ++ c_parser_sizeof_or_nelementsof_expression (parser, RID_NELEMENTSOF) \ +) + /* 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_elementsof_expression (c_parser *, -+ enum rid); ++static struct c_expr c_parser_sizeof_or_nelementsof_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_ELEMENTSOF: -+ return c_parser_elementsof_expression (parser); ++ case RID_NELEMENTSOF: ++ return c_parser_nelementsof_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_elementsof_expression (c_parser *parser, enum rid rid) ++c_parser_sizeof_or_nelementsof_expression (c_parser *parser, enum rid rid) { -+ const char *op_name = (rid == RID_ELEMENTSOF) ? "elementsof" : "sizeof"; ++ const char *op_name = (rid == RID_NELEMENTSOF) ? "nelementsof" : "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_ELEMENTSOF) -+ in_elementsof++; ++ if (rid == RID_NELEMENTSOF) ++ in_nelementsof++; + 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_ELEMENTSOF) -+ in_elementsof--; ++ if (rid == RID_NELEMENTSOF) ++ in_nelementsof--; + 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_ELEMENTSOF) ++ if (rid == RID_NELEMENTSOF) + { -+ in_elementsof--; -+ result = c_expr_elementsof_type (expr_loc, type_name); ++ in_nelementsof--; ++ result = c_expr_nelementsof_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_ELEMENTSOF) -+ in_elementsof--; ++ if (rid == RID_NELEMENTSOF) ++ in_nelementsof--; + 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_ELEMENTSOF) -+ result = c_expr_elementsof_expr (expr_loc, expr); ++ if (rid == RID_NELEMENTSOF) ++ result = c_expr_nelementsof_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_elementsof; ++extern int in_nelementsof; 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_elementsof_expr (location_t, struct c_expr); -+extern struct c_expr c_expr_elementsof_type (location_t loc, -+ 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, ++ 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 "elementsof". */ -+int in_elementsof; ++/* The level of nesting inside "nelementsof". */ ++int in_nelementsof; + /* 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_elementsof) ++ if (!in_sizeof && !in_typeof && !in_nelementsof) 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_elementsof). */ ++ /* The level seen at (in_sizeof + in_typeof + in_nelementsof). */ 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_elementsof; ++ t->level = in_sizeof + in_typeof + in_nelementsof; 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_elementsof; ++ int cur_level = in_sizeof + in_typeof + in_nelementsof; 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 elementsof applied to EXPR. */ ++/* Return the result of nelementsof applied to EXPR. */ + +struct c_expr -+c_expr_elementsof_expr (location_t loc, struct c_expr expr) ++c_expr_nelementsof_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_elementsof_type (loc, TREE_TYPE (folded_expr)); ++ ret.value = c_nelementsof_type (loc, TREE_TYPE (folded_expr)); + c_last_sizeof_arg = expr.value; + c_last_sizeof_loc = loc; -+ ret.original_code = ELEMENTSOF_EXPR; ++ ret.original_code = NELEMENTSOF_EXPR; + ret.original_type = NULL; + ret.m_decimal = 0; + if (is_top_array_vla (TREE_TYPE (folded_expr))) + { -+ /* elementsof is evaluated when given a vla. */ ++ /* nelementsof 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 elementsof applied to T, a structure for the type -+ name passed to elementsof (rather than the type itself). LOC is the ++/* 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 + location of the original expression. */ + +struct c_expr -+c_expr_elementsof_type (location_t loc, struct c_type_name *t) ++c_expr_nelementsof_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_elementsof_type (loc, type); ++ ret.value = c_nelementsof_type (loc, type); + c_last_sizeof_arg = type; + c_last_sizeof_loc = loc; -+ ret.original_code = ELEMENTSOF_EXPR; ++ ret.original_code = NELEMENTSOF_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 elementsof does not get folded to a constant by ++ the result of nelementsof 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 elementsof call is inside ++ arrays must not be applied when this nelementsof 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 ("__elementsof__", ELEMENTSOF_EXPR, "lz", OVL_OP_FLAG_UNARY) ++DEF_OPERATOR ("__nelementsof__", NELEMENTSOF_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 elementsof ++@node nelementsof +@section Determining the Number of Elements of Arrays -+@cindex elementsof ++@cindex nelementsof +@cindex number of elements + +The keyword @code{__elemetsf__} determines the length of an array operand, @@ gcc/target.h: enum type_context_kind { TCTX_ALIGNOF, + /* Directly measuring the number of elements of array T. */ -+ TCTX_ELEMENTSOF, ++ TCTX_NELEMENTSOF, + /* Creating objects of type T with static storage duration. */ TCTX_STATIC_STORAGE, - ## gcc/testsuite/gcc.dg/elementsof-compile.c (new) ## + ## gcc/testsuite/gcc.dg/nelementsof-compile.c (new) ## @@ +/* { dg-do compile } */ +/* { dg-options "-Wno-declaration-after-statement -Wno-pedantic -Wno-vla" } */ @@ gcc/testsuite/gcc.dg/elementsof-compile.c (new) +static int w[] = {1, 2, 3}; + +static int z[0]; -+static int y[__elementsof__(z)]; ++static int y[__nelementsof__(z)]; + +void +automatic(void) +{ -+ __elementsof__ (w); ++ __nelementsof__ (w); +} + +void +incomplete (int p[]) +{ -+ __elementsof__ (x); /* { dg-error "incomplete" } */ ++ __nelementsof__ (x); /* { dg-error "incomplete" } */ + + /* We want to support the following one in the future, + but for now it should fail. */ -+ __elementsof__ (p); /* { dg-error "invalid" } */ ++ __nelementsof__ (p); /* { dg-error "invalid" } */ +} + +void @@ gcc/testsuite/gcc.dg/elementsof-compile.c (new) + int fam[]; + } s; + -+ __elementsof__ (s.fam); /* { dg-error "incomplete" } */ ++ __nelementsof__ (s.fam); /* { dg-error "incomplete" } */ +} + -+void fix_fix (int i, char (*a)[3][5], int (*x)[__elementsof__ (*a)]); -+void fix_var (int i, char (*a)[3][i], int (*x)[__elementsof__ (*a)]); -+void fix_uns (int i, char (*a)[3][*], int (*x)[__elementsof__ (*a)]); ++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 +func (void) @@ gcc/testsuite/gcc.dg/elementsof-compile.c (new) + int x[3]; + } s; + -+ __elementsof__ (x); /* { dg-error "invalid" } */ -+ __elementsof__ (int); /* { dg-error "invalid" } */ -+ __elementsof__ (s); /* { dg-error "invalid" } */ -+ __elementsof__ (struct s); /* { dg-error "invalid" } */ -+ __elementsof__ (&x); /* { dg-error "invalid" } */ -+ __elementsof__ (p); /* { dg-error "invalid" } */ -+ __elementsof__ (int *); /* { dg-error "invalid" } */ -+ __elementsof__ (&s.x); /* { dg-error "invalid" } */ -+ __elementsof__ (int (*)[3]); /* { dg-error "invalid" } */ ++ __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" } */ +} + +static int f1(); @@ gcc/testsuite/gcc.dg/elementsof-compile.c (new) +{ + int b[n][n]; + -+ __elementsof__ (a[f1()]); -+ __elementsof__ (b[f2()]); ++ __nelementsof__ (a[f1()]); ++ __nelementsof__ (b[f2()]); +} + +void +no_parens(void) +{ -+ __elementsof__ a; -+ __elementsof__ *a; -+ __elementsof__ (int [3]) {}; ++ __nelementsof__ a; ++ __nelementsof__ *a; ++ __nelementsof__ (int [3]) {}; + -+ __elementsof__ int [3]; /* { dg-error "expected expression before" } */ ++ __nelementsof__ int [3]; /* { dg-error "expected expression before" } */ +} + +void @@ gcc/testsuite/gcc.dg/elementsof-compile.c (new) +{ + int n = 7; + -+ _Static_assert (__elementsof__ (int [3][n]) == 3); -+ _Static_assert (__elementsof__ (int [n][3]) == 7); /* { dg-error "not constant" } */ -+ _Static_assert (__elementsof__ (int [0][3]) == 0); -+ _Static_assert (__elementsof__ (int [0]) == 0); ++ _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); + -+ /* FIXME: elementsof(int [0][n]) should result in a constant expression. */ -+ _Static_assert (__elementsof__ (int [0][n]) == 0); /* { dg-error "not constant" } */ ++ /* FIXME: nelementsof(int [0][n]) should result in a constant expression. */ ++ _Static_assert (__nelementsof__ (int [0][n]) == 0); /* { dg-error "not constant" } */ +} - ## gcc/testsuite/gcc.dg/elementsof-vla.c (new) ## + ## gcc/testsuite/gcc.dg/nelementsof-vla.c (new) ## @@ +/* { dg-do compile } */ +/* { dg-options "-Wno-pedantic -Wvla-parameter" } */ + +void fix_fix (int i, + char (*a)[3][5], -+ int (*x)[__elementsof__ (*a)]); ++ int (*x)[__nelementsof__ (*a)]); +void fix_var (int i, + char (*a)[3][i], /* dg-warn "variable" */ -+ int (*x)[__elementsof__ (*a)]); ++ int (*x)[__nelementsof__ (*a)]); +void fix_uns (int i, + char (*a)[3][*], -+ int (*x)[__elementsof__ (*a)]); ++ int (*x)[__nelementsof__ (*a)]); + +void zro_fix (int i, + char (*a)[0][5], -+ int (*x)[__elementsof__ (*a)]); ++ int (*x)[__nelementsof__ (*a)]); +void zro_var (int i, + char (*a)[0][i], /* dg-warn "variable" */ -+ int (*x)[__elementsof__ (*a)]); ++ int (*x)[__nelementsof__ (*a)]); +void zro_uns (int i, + char (*a)[0][*], -+ int (*x)[__elementsof__ (*a)]); ++ int (*x)[__nelementsof__ (*a)]); + +void var_fix (int i, + char (*a)[i][5], /* dg-warn "variable" */ -+ int (*x)[__elementsof__ (*a)]); /* dg-warn "variable" */ ++ int (*x)[__nelementsof__ (*a)]); /* dg-warn "variable" */ +void var_var (int i, + char (*a)[i][i], /* dg-warn "variable" */ -+ int (*x)[__elementsof__ (*a)]); /* dg-warn "variable" */ ++ int (*x)[__nelementsof__ (*a)]); /* dg-warn "variable" */ +void var_uns (int i, + char (*a)[i][*], /* dg-warn "variable" */ -+ int (*x)[__elementsof__ (*a)]); /* dg-warn "variable" */ ++ int (*x)[__nelementsof__ (*a)]); /* dg-warn "variable" */ + +void uns_fix (int i, + char (*a)[*][5], -+ int (*x)[__elementsof__ (*a)]); ++ int (*x)[__nelementsof__ (*a)]); +void uns_var (int i, + char (*a)[*][i], /* dg-warn "variable" */ -+ int (*x)[__elementsof__ (*a)]); ++ int (*x)[__nelementsof__ (*a)]); +void uns_uns (int i, + char (*a)[*][*], -+ int (*x)[__elementsof__ (*a)]); ++ int (*x)[__nelementsof__ (*a)]); + +// Can't test due to bug: +//static int z2[0]; -+//static int y2[__elementsof__(z2)]; ++//static int y2[__nelementsof__(z2)]; - ## gcc/testsuite/gcc.dg/elementsof.c (new) ## + ## gcc/testsuite/gcc.dg/nelementsof.c (new) ## @@ +/* { dg-do run } */ +/* { dg-options "-Wno-declaration-after-statement -Wno-pedantic -Wno-vla" } */ @@ gcc/testsuite/gcc.dg/elementsof.c (new) +{ + short a[7]; + -+ static_assert (__elementsof__ (a) == 7); -+ static_assert (__elementsof__ (long [0]) == 0); -+ static_assert (__elementsof__ (unsigned [99]) == 99); ++ static_assert (__nelementsof__ (a) == 7); ++ static_assert (__nelementsof__ (long [0]) == 0); ++ static_assert (__nelementsof__ (unsigned [99]) == 99); +} + +void @@ gcc/testsuite/gcc.dg/elementsof.c (new) + int a[] = {1, 2, 3}; + int z[] = {}; + -+ static_assert (__elementsof__ (a) == 3); -+ static_assert (__elementsof__ (z) == 0); ++ static_assert (__nelementsof__ (a) == 3); ++ static_assert (__nelementsof__ (z) == 0); +} + +void @@ gcc/testsuite/gcc.dg/elementsof.c (new) + unsigned n; + + n = 99; -+ assert (__elementsof__ (short [n - 10]) == 99 - 10); ++ assert (__nelementsof__ (short [n - 10]) == 99 - 10); + + int v[n / 2]; -+ assert (__elementsof__ (v) == 99 / 2); ++ assert (__nelementsof__ (v) == 99 / 2); + + n = 0; + int z[n]; -+ assert (__elementsof__ (z) == 0); ++ assert (__nelementsof__ (z) == 0); +} + +void @@ gcc/testsuite/gcc.dg/elementsof.c (new) + int a[8]; + } s; + -+ static_assert (__elementsof__ (s.a) == 8); ++ static_assert (__nelementsof__ (s.a) == 8); +} + +void @@ gcc/testsuite/gcc.dg/elementsof.c (new) + int i; + + i = 7; -+ assert (__elementsof__ (struct {int x;}[i++]) == 7); ++ assert (__nelementsof__ (struct {int x;}[i++]) == 7); + assert (i == 7 + 1); + + int v[i]; + int (*p)[i]; + p = &v; -+ assert (__elementsof__ (*p++) == i); ++ assert (__nelementsof__ (*p++) == i); + assert (p - 1 == &v); +} + @@ gcc/testsuite/gcc.dg/elementsof.c (new) + int i; + + i = 3; -+ static_assert (__elementsof__ (struct {int x[i++];}[3]) == 3); ++ static_assert (__nelementsof__ (struct {int x[i++];}[3]) == 3); + assert (i == 3); +} + @@ gcc/testsuite/gcc.dg/elementsof.c (new) +array_noeval (void) +{ + long a[5]; -+ long (*p)[__elementsof__ (a)]; ++ long (*p)[__nelementsof__ (a)]; + + p = &a; -+ static_assert (__elementsof__ (*p++) == 5); ++ static_assert (__nelementsof__ (*p++) == 5); + assert (p == &a); +} + @@ gcc/testsuite/gcc.dg/elementsof.c (new) +{ + int i; + -+ static_assert (__elementsof__ (int [0][4]) == 0); ++ static_assert (__nelementsof__ (int [0][4]) == 0); + i = 3; -+ assert (__elementsof__ (int [0][i]) == 0); ++ assert (__nelementsof__ (int [0][i]) == 0); +} + +void @@ gcc/testsuite/gcc.dg/elementsof.c (new) +{ + int i; + -+ static_assert (__elementsof__ (int [7][4]) == 7); ++ static_assert (__nelementsof__ (int [7][4]) == 7); + i = 3; -+ static_assert (__elementsof__ (int [7][i]) == 7); ++ static_assert (__nelementsof__ (int [7][i]) == 7); +} + +void @@ gcc/testsuite/gcc.dg/elementsof.c (new) + int i, j; + + i = 7; -+ assert (__elementsof__ (int [i++][4]) == 7); ++ assert (__nelementsof__ (int [i++][4]) == 7); + assert (i == 7 + 1); + + i = 9; + j = 3; -+ assert (__elementsof__ (int [i++][j]) == 9); ++ assert (__nelementsof__ (int [i++][j]) == 9); + assert (i == 9 + 1); +} + @@ gcc/testsuite/gcc.dg/elementsof.c (new) + int a[7]; + int v[n]; + -+ static_assert (__elementsof__ a == 7); -+ assert (__elementsof__ v == 3); ++ static_assert (__nelementsof__ a == 7); ++ assert (__nelementsof__ v == 3); +} + +int base-commit: 4d44f3fc387815eb232d7757352857993a1d21d9