From patchwork Sat Aug 3 23:17:06 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alejandro Colomar X-Patchwork-Id: 1968758 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=LE7S1Xzz; 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 4WbzBX0WvSz1yYD for ; Sun, 4 Aug 2024 09:17:40 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id A7D703858431 for ; Sat, 3 Aug 2024 23:17:37 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from dfw.source.kernel.org (dfw.source.kernel.org [IPv6:2604:1380:4641:c500::1]) by sourceware.org (Postfix) with ESMTPS id F13BE3858D29 for ; Sat, 3 Aug 2024 23:17:09 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org F13BE3858D29 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 F13BE3858D29 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=2604:1380:4641:c500::1 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1722727032; cv=none; b=HoiyCkAThGm5RZrnw5C72VUsxJ5vVvM3ju+NmLAS2joX5nt7eVkkqHtBvylCrnj5Z5i8j/JvsYHr4GwsbmXTQWbhiDvk05ETAaOL4En/mrqpz1Dx0U041VfJwCpOA21PB38HGzhtZ2fVOWzTJiTZxJvrnaJoDsajtyxIEwFpt7Y= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1722727032; c=relaxed/simple; bh=8YFMTUR6mMwIy8xxBppoVDa+VywpYSkuySJuGIPQpR0=; h=DKIM-Signature:Date:From:To:Subject:Message-ID:MIME-Version; b=AeDJmknbvgWRTLjCdAyinEOnQwtdNTW1elSXAztE/mblpYoy8j1DUkUkoy8jjYV1hh9PENspxu5d6y+eS3qqwm5EyrNF/rdtHZNg9u20rRTlY8TO1CJVQcZjpA9l4kk7ytzrYNG4j21kr9SoPQ7TuQ3JtqpnPS3Nc1Dhhhq/y8Q= ARC-Authentication-Results: i=1; server2.sourceware.org Received: from smtp.kernel.org (transwarp.subspace.kernel.org [100.75.92.58]) by dfw.source.kernel.org (Postfix) with ESMTP id 82AD660A39; Sat, 3 Aug 2024 23:17:09 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id BB8A3C116B1; Sat, 3 Aug 2024 23:17:07 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1722727029; bh=8YFMTUR6mMwIy8xxBppoVDa+VywpYSkuySJuGIPQpR0=; h=Date:From:To:Cc:Subject:References:In-Reply-To:From; b=LE7S1XzzcEwfS67UJcfVE6daZf2eogHEsxtwXPmhpEMdIbKSnL1qbpVJeSpDGbggC HZtpl16FEQ6mRFKYXhw1raAA3Tu/avMQ/ImRJwVAr87HRbKzNhLD6O8/ClKvPmmrQC 4jtuh/nEaDm3PpPK0VDumnkdQBkZy7oZrOnPREsOBBumCPdI5eS+LHixntsu9bLsbv wUop8LOjBlF51+DHtZI56vMYXf/FXLmGHHrZAkDJ26SBu4ECyZlQHeo+p8leAolzkg kKBEO5kskHjR47cTNbtdbCt4wm/K07GYpix+OjOai7SDZl+SblTxD2Zf4aQ7/Jps4A dwsxIeEAE0/QA== Date: Sun, 4 Aug 2024 01:17:06 +0200 From: Alejandro Colomar To: gcc-patches@gcc.gnu.org Cc: Alejandro Colomar , Xavier Del Campo Romero , Gabriel Ravier , Martin Uecker , Joseph Myers , Jakub Jelinek Subject: [RFC v3 0/3] c: Add __lengthof__ operator Message-ID: <20240803231702.89150-1-alx@kernel.org> 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, 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, v3: - Add some documentation. - Reject incomplete types. - Rename array_type_nelts()=>array_type_nelts_minus_one(). (However, I included that patch in this set only for completeness purposes; that patch is also sent standalone, and I would like it to be merged in the separate discussion for it.) (Below is a range diff against v2.) Below is a test program I'm using for implementing this feature: $ cat len.c #include #include #define memberof(T, member) ((T){}.member) struct s { int x; int y[8]; int z[]; }; extern int x[]; int main(int argc, char *argv[argc + 1]) { short a[42]; size_t n; (void) argv; // Wishlist: //n = __lengthof__(argv); //printf("lengthof(argv) == %zu\n", n); n = __lengthof__(a); printf("lengthof(a):\t %zu\n", n); // Expected error: //n = __lengthof__(x); //printf("lengthof(x):\t %zu\n", n); n = __lengthof__(long [0]); printf("lengthof(long [0]):\t %zu\n", n); n = __lengthof__(long [99]); printf("lengthof(long [99]):\t %zu\n", n); n = __lengthof__(short [n - 10]); printf("lengthof(short [n - 10]):\t %zu\n", n); int b[n / 2]; n = __lengthof__(b); printf("lengthof(b):\t %zu\n", n); puts(""); // X(memberof(struct s, y)) n = __lengthof__(memberof(struct s, y)); printf("lengthof(memberof(struct s, y)):\t %zu\n", n); n = sizeof(memberof(struct s, y)); printf("sizeof(memberof(struct s, y)):\t %zu\n", n); n = alignof(memberof(struct s, y)); printf("alignof(memberof(struct s, y)):\t %zu\n", n); puts(""); // X(memberof(struct s, z)) // Expected error: //n = __lengthof__(memberof(struct s, z)); //printf("lengthof(memberof(struct s, z)):\t %zu\n", n); // Expected error: //n = sizeof(memberof(struct s, z)); //printf("sizeof(memberof(struct s, z)):\t %zu\n", n); n = alignof(memberof(struct s, z)); printf("alignof(memberof(struct s, z)):\t %zu\n", n); puts(""); // X(struct {int x;}[i++]) int i = 4; n = __lengthof__(struct {int x;}[i++]); printf("lengthof(struct {int x;}[i++]):\t %zu; i: %d\n", n, i); i = 4; n = sizeof(struct {int x;}[i++]); printf("sizeof(struct {int x;}[i++]):\t %zu; i: %d\n", n, i); i = 4; n = alignof(struct {int x;}[i++]); printf("alignof(struct {int x;}[i++]):\t %zu; i: %d\n", n, i); i = 4; typeof(struct {int x;}[i++]) z1; printf("typeof(struct {int x;}[i++]);\t i: %d\n", i); puts(""); // X(struct {int x[i++];}[3]) i = 4; n = __lengthof__(struct {int x[i++];}[3]); printf("lengthof(struct {int x[i++];}[3]):\t %zu; i: %d\n", n, i); i = 4; n = sizeof(struct {int x[i++];}[3]); printf("sizeof(struct {int x[i++];}[3]):\t %zu; i: %d\n", n, i); i = 4; n = alignof(struct {int x[i++];}[3]); printf("alignof(struct {int x[i++];}[3]):\t %zu; i: %d\n", n, i); i = 4; typeof(struct {int x[i++];}[3]) z2; printf("typeof(struct {int x[i++];}[3]);\t i: %d\n", i); puts(""); // X(struct {int x[(i++, 2)];}[3]) i = 4; n = __lengthof__(struct {int x[(i++, 2)];}[3]); printf("lengthof(struct {int x[(i++, 2)];}[3]):\t %zu; i: %d\n", n, i); i = 4; n = sizeof(struct {int x[(i++, 2)];}[3]); printf("sizeof(struct {int x[(i++, 2)];}[3]):\t %zu; i: %d\n", n, i); i = 4; n = alignof(struct {int x[(i++, 2)];}[3]); printf("alignof(struct {int x[(i++, 2)];}[3]):\t %zu; i: %d\n", n, i); i = 4; typeof(struct {int x[(i++, 2)];}[3]) z3; printf("typeof(struct {int x[(i++, 2)];}[3]);\t i: %d\n", i); puts(""); // X(*p++) short (*p)[42]; p = &a; n = __lengthof__(*p++); printf("lengthof(*p++):\t %zu; p: %p\n", n, p); p = &a; n = sizeof(*p++); printf("lengthof(*p++):\t %zu; p: %p\n", n, p); p = &a; n = alignof(*p++); printf("alignof(*p++):\t %zu; p: %p\n", n, p); p = &a; typeof(*p++) z4; printf("typeof(*p++);\t p: %p\n", p); puts(""); // X(*q++) short (*q)[__lengthof__(b)]; q = &a; n = __lengthof__(*q++); printf("lengthof(*q++):\t %zu; p: %p\n", n, q); q = &a; n = sizeof(*q++); printf("lengthof(*q++):\t %zu; p: %p\n", n, q); q = &a; n = alignof(*q++); printf("alignof(*q++):\t %zu; p: %p\n", n, q); q = &a; typeof(*q++) z5; printf("typeof(*q++);\t p: %p\n", q); } $ /opt/local/gnu/gcc/lengthof/bin/gcc len.c $ ./a.out lengthof(a): 42 lengthof(long [0]): 0 lengthof(long [99]): 99 lengthof(short [n - 10]): 89 lengthof(b): 44 lengthof(memberof(struct s, y)): 8 sizeof(memberof(struct s, y)): 32 alignof(memberof(struct s, y)): 4 alignof(memberof(struct s, z)): 4 lengthof(struct {int x;}[i++]): 4; i: 5 sizeof(struct {int x;}[i++]): 16; i: 5 alignof(struct {int x;}[i++]): 4; i: 4 typeof(struct {int x;}[i++]); i: 5 lengthof(struct {int x[i++];}[3]): 3; i: 5 sizeof(struct {int x[i++];}[3]): 48; i: 5 alignof(struct {int x[i++];}[3]): 4; i: 4 typeof(struct {int x[i++];}[3]); i: 5 lengthof(struct {int x[(i++, 2)];}[3]): 3; i: 5 sizeof(struct {int x[(i++, 2)];}[3]): 24; i: 5 alignof(struct {int x[(i++, 2)];}[3]): 4; i: 4 typeof(struct {int x[(i++, 2)];}[3]); i: 5 lengthof(*p++): 42; p: 0x7fffe52379f0 lengthof(*p++): 84; p: 0x7fffe52379f0 alignof(*p++): 2; p: 0x7fffe52379f0 typeof(*p++); p: 0x7fffe52379f0 lengthof(*q++): 44; p: 0x7fffe5237a48 lengthof(*q++): 88; p: 0x7fffe5237a48 alignof(*q++): 2; p: 0x7fffe52379f0 typeof(*q++); p: 0x7fffe5237a48 There are some things to consider: - Error handling could be incomplete; there are a few things I still don't understand. - I'd like to implement it so that only top-level VLAs trigger evaluation, but I still don't understand that well. Other than that, it starts looking good. Have a lovely night! Alex Alejandro Colomar (3): gcc/: Rename array_type_nelts() => array_type_nelts_minus_one() Merge definitions of array_type_nelts_top() c: Add __lengthof__() 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 | 30 +++++++---- gcc/c/c-fold.cc | 7 +-- gcc/c/c-parser.cc | 61 ++++++++++++++++------ gcc/c/c-tree.h | 4 ++ gcc/c/c-typeck.cc | 95 +++++++++++++++++++++++++++++++++-- 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 | 12 +++++ 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/tree.cc | 17 ++++++- gcc/tree.h | 3 +- 25 files changed, 245 insertions(+), 79 deletions(-) Range-diff against v2: -: ----------- > 1: 73010cb4af6 gcc/: Rename array_type_nelts() => array_type_nelts_minus_one() 1: 507f5a51e17 ! 2: 2bb966a0a89 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 _Lengthof(). Merge them, and + where they are needed for implementing __lengthof__(). Merge them, and provide the single definition in gcc/tree.{h,cc}, where it's available - for _Lengthof(). + for __lengthof__(). Signed-off-by: Alejandro Colomar @@ gcc/cp/tree.cc: cxx_print_statistics (void) -{ - return fold_build2_loc (input_location, - PLUS_EXPR, sizetype, -- array_type_nelts (type), +- array_type_nelts_minus_one (type), - size_one_node); -} - @@ gcc/rust/backend/rust-tree.cc: is_empty_class (tree type) -array_type_nelts_top (tree type) -{ - return fold_build2_loc (input_location, PLUS_EXPR, sizetype, -- array_type_nelts (type), size_one_node); +- array_type_nelts_minus_one (type), size_one_node); -} - // forked from gcc/cp/tree.cc builtin_valid_in_constant_expr_p @@ gcc/rust/backend/rust-tree.h: extern location_t rs_expr_location (const_tree); ## gcc/tree.cc ## -@@ gcc/tree.cc: array_type_nelts (const_tree type) +@@ gcc/tree.cc: array_type_nelts_minus_one (const_tree type) ? max : fold_build2 (MINUS_EXPR, TREE_TYPE (max), max, min)); } @@ gcc/tree.cc: array_type_nelts (const_tree type) +{ + return fold_build2_loc (input_location, + PLUS_EXPR, sizetype, -+ array_type_nelts (type), ++ array_type_nelts_minus_one (type), + size_one_node); +} @@ gcc/tree.h @@ gcc/tree.h: extern tree build_method_type (tree, tree); extern tree build_offset_type (tree, tree); extern tree build_complex_type (tree, bool named = false); - extern tree array_type_nelts (const_tree); + extern tree array_type_nelts_minus_one (const_tree); +extern tree array_type_nelts_top (tree); extern tree value_member (tree, tree); 2: 6b48d48ecdd ! 3: d22b5e1c015 c: Add __lengthof__() operator @@ Commit message This operator is similar to sizeof() but can only be applied to an array, and returns its length (number of elements). + TO BE DECIDED BEFORE MERGING: + + It would be better to not evaluate the operand if the top-level + array is not a VLA. + FUTURE DIRECTIONS: We could make it work with array parameters to functions, and @@ Commit message regardless of it being really a pointer. Link: + Cc: Xavier Del Campo Romero Cc: Gabriel Ravier Cc: Martin Uecker Cc: Joseph Myers + Cc: Jakub Jelinek Signed-off-by: Alejandro Colomar ## gcc/c-family/c-common.cc ## @@ gcc/c-family/c-common.cc: c_alignof_expr (location_t loc, tree expr) + enum tree_code type_code; + + type_code = TREE_CODE (type); ++ if (!COMPLETE_TYPE_P (type)) ++ { ++ error_at (loc, ++ "invalid application of % to incomplete type %qT", ++ type); ++ return error_mark_node; ++ } + if (type_code != ARRAY_TYPE) + { + error_at (loc, "invalid application of % to type %qT", type); @@ gcc/cp/operators.def: DEF_OPERATOR ("co_await", CO_AWAIT_EXPR, "aw", OVL_OP_FLAG DEF_OPERATOR ("__real__", REALPART_EXPR, "v18__real__", OVL_OP_FLAG_UNARY) + ## gcc/doc/extend.texi ## +@@ gcc/doc/extend.texi: If the operand of the @code{__alignof__} expression is a function, + the expression evaluates to the alignment of the function which may + be specified by attribute @code{aligned} (@pxref{Common Function Attributes}). + ++@node Length ++@section Determining the Length of Arrays ++@cindex length ++@cindex array length ++ ++The keyword @code{__lengthof__} determines the length of an array operand, ++that is, the number of elements in the array. ++Its syntax is just like @code{sizeof}, ++and the operand is evaluated following the same rules. ++(TODO: We probably want to restrict evaluation to top-level VLAs only. ++ This documentation describes the current implementation.) ++ + @node Inline + @section An Inline Function is As Fast As a Macro + @cindex inline functions + ## gcc/target.h ## @@ gcc/target.h: enum type_context_kind { /* Directly measuring the alignment of T. */