From patchwork Tue Oct 22 18:48:11 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alejandro Colomar X-Patchwork-Id: 99348 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id E6574385841E for ; Tue, 22 Oct 2024 18:49:06 +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 A69F13858D28 for ; Tue, 22 Oct 2024 18:48:14 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org A69F13858D28 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 A69F13858D28 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=1729622897; cv=none; b=H9NvPKHo99I7t9FqzYRg6XLEmVD8TP28SymdRD8g0Yw9hO0vwJgOzVfzSM40V/5b0nWPDFOGqlY9UFeyGAn0HTH7WoUeYGKf2t2MuoAZOf8y8jETyeO6ZknFgyRlG1iwzXCGue7DZmZBnWj9IoMd/H2wqGmAQnPrCpV1emio3wM= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1729622897; c=relaxed/simple; bh=zdFbFJCxDtDTUSy7z7FCVU0RFhA7jMXxZlemfWR9f4U=; h=DKIM-Signature:Date:From:To:Subject:Message-ID:MIME-Version; b=DmXxLDAAbJyVh3O/pUio2g+KiRw7jmMytPhCW75rAWpHgf6xQseoTWEhpc5Ct4YRcy4WdnEDxgkspdo3oKvXb7f+4VxyPTptVebf7l5NNanWt3fCAaN3xMSjsEP1AJh9DcFI2Mpl8ZL7aD3e7AsQbN5fstWctTJYeH4+eKdTigA= 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 A2C625C5E01; Tue, 22 Oct 2024 18:48:09 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id C7457C4CEC3; Tue, 22 Oct 2024 18:48:12 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1729622893; bh=zdFbFJCxDtDTUSy7z7FCVU0RFhA7jMXxZlemfWR9f4U=; h=Date:From:To:Cc:Subject:References:In-Reply-To:From; b=D+qJixs6luEc5VMldPy1GslV+VV0iikbhULF5Lile/+jf/iEVvYVubxAO8p2JnnQ4 hLXVdGFviWI4WXWsUZE/TIqUhX/dbuuv/yYk7iuFidTsMY8iPqDxIyEBG0SQluk8oT cA+VUG+8Mi1lokgOvNJLj3r1ttjKNt/tiACZx7V4RW3OFN6yDmiombVJYTq3QOGyuT YH9MmoXkA/YpQNYMDCVSggfHxpz7J7bcSF52gTTq/DirQ37oWTZILsoNFKPpHQPOl+ 0iy2xXABHHH093fvDpHwsuBMZ7N9o0goFzY5vGLB66I3fRqMl0B041fJgk0nPB2rB4 zA4bb0v6oeRPQ== Date: Tue, 22 Oct 2024 20:48:11 +0200 From: Alejandro Colomar To: gcc-patches@gcc.gnu.org, josmyers@redhat.com Cc: Alejandro Colomar Subject: [PATCH v17 1/2] contrib/: Add support for Cc: and Link: tags Message-ID: X-Mailer: git-send-email 2.45.2 References: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: X-Spam-Status: No, score=-10.2 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, 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~patchwork=sourceware.org@gcc.gnu.org contrib/ChangeLog: * gcc-changelog/git_commit.py (GitCommit): Add support for 'Cc: ' and 'Link: ' tags. Cc: Jason Merrill Signed-off-by: Alejandro Colomar --- contrib/gcc-changelog/git_commit.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/contrib/gcc-changelog/git_commit.py b/contrib/gcc-changelog/git_commit.py index 87ecb9e1a17..64fb986b74c 100755 --- a/contrib/gcc-changelog/git_commit.py +++ b/contrib/gcc-changelog/git_commit.py @@ -182,7 +182,8 @@ CO_AUTHORED_BY_PREFIX = 'co-authored-by: ' REVIEW_PREFIXES = ('reviewed-by: ', 'reviewed-on: ', 'signed-off-by: ', 'acked-by: ', 'tested-by: ', 'reported-by: ', - 'suggested-by: ') + 'suggested-by: ', 'cc: ') +LINK_PREFIXES = ('link: ') DATE_FORMAT = '%Y-%m-%d' @@ -524,6 +525,8 @@ class GitCommit: continue elif lowered_line.startswith(REVIEW_PREFIXES): continue + elif lowered_line.startswith(LINK_PREFIXES): + continue else: m = cherry_pick_regex.search(line) if m: From patchwork Tue Oct 22 18:48:14 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Alejandro Colomar X-Patchwork-Id: 99349 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 070193858C60 for ; Tue, 22 Oct 2024 18:49:08 +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 [139.178.84.217]) by sourceware.org (Postfix) with ESMTPS id 8D6173858D33 for ; Tue, 22 Oct 2024 18:48:17 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 8D6173858D33 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 8D6173858D33 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=139.178.84.217 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1729622901; cv=none; b=vhj4n5C5VgkfpkS8snEhl2cYUWk5ebyfup/MkiUOTgfqZE3GSZLOqlHvcQlDP7u/mjOy2cSj+X1trCjJcPeB6EQhsoxVQ3cwUf4S1Zv+vnwul1OuHbJumnvKTGZRAF6BwI3vnEt4+a5XvtLf93TbSaimpzhCtnzEpUswS+WqCzw= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1729622901; c=relaxed/simple; bh=dPSo2D+t2uOS9JxonwrZj59HgQTqxdgndnr0Ykjlco4=; h=DKIM-Signature:Date:From:To:Subject:Message-ID:MIME-Version; b=w0YseZbElbfUQxBqEb9VgntbbOK1aEjaE4bGDZ5nwMynqUyE07gmQt0xRLhetOmrBUs6UqTcwc4jRwuKToTLf6Eejy6Sv2Lt/WwAHGB9dg6ulRpkGF+0xv7d+2zu8K+mqh0REudUED0XkTP+SckpsaMrz5kHYuE3jh8xN+un6RM= 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 77FAA5C593F; Tue, 22 Oct 2024 18:48:12 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id BB7EEC4CEC3; Tue, 22 Oct 2024 18:48:15 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1729622896; bh=dPSo2D+t2uOS9JxonwrZj59HgQTqxdgndnr0Ykjlco4=; h=Date:From:To:Cc:Subject:References:In-Reply-To:From; b=vP+I7Xk+kdd6ZIy0UFX8SrtPcY3G6kJsIv/ks6PfocLcvKi3BpXSq3+R3JVeMlycb Y6OudD0hVpWhMJ6qDzMcn7l/zwfjZHomivOL1iDAx/zxW8UPB7rIkCfJ4n39GZ7Wpd RmPYXMwayVv+woP13n0ZxfUwd/4CfsekhI6c5DTexBAnddnUgr8V2onanrtMBKEg7x 5p1cx4S80byC8w8ChLJ9cSIc6SiYefoygvdrzHMcpM+eIaSREs9095no1xsqdGPP7l XKyd4bSKCvfjiCuUNT/iADvewfB3EAb/Ab4/cHDKNX5L7t8kKO7+NQp/HwikOOS/9f Y6GqaTTrAnS9w== Date: Tue, 22 Oct 2024 20:48:14 +0200 From: Alejandro Colomar To: gcc-patches@gcc.gnu.org, josmyers@redhat.com Cc: Alejandro Colomar Subject: [PATCH v17 2/2] c: Add __countof__ operator Message-ID: <936f7945fae5ce7b5ca705a968af7c87474cc64c.1729622352.git.alx@kernel.org> X-Mailer: git-send-email 2.45.2 References: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: X-Spam-Status: No, score=-10.2 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, 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~patchwork=sourceware.org@gcc.gnu.org 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. - Fix support for [0]. gcc/ChangeLog: * doc/extend.texi: Document __countof__ operator. gcc/c-family/ChangeLog: * c-common.h * c-common.def * c-common.cc (c_countof_type): Add __countof__ operator. gcc/c/ChangeLog: * c-tree.h (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_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_countof_expr, c_expr_countof_type): Add __countof__ operator. gcc/testsuite/ChangeLog: * gcc.dg/countof-compile.c * gcc.dg/countof-vla.c * gcc.dg/countof.c: Add tests for __countof__ operator. Link: Link: Link: Link: Link: Link: Link: Link: Suggested-by: Xavier Del Campo Romero Co-authored-by: Martin Uecker Acked-by: "James K. Lowden" Cc: Joseph Myers Cc: Gabriel Ravier Cc: Jakub Jelinek Cc: Kees Cook Cc: Qing Zhao Cc: Jens Gustedt Cc: David Brown Cc: Florian Weimer Cc: Andreas Schwab Cc: Timm Baeder Cc: Daniel Plakosh Cc: "A. Jiang" 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 Cc: Douglas McIlroy Cc: Jason Merrill Cc: "Gustavo A. R. Silva" Cc: Patrizia Kaye Cc: Ori Bernstein Cc: Robert Seacord Cc: Marek Polacek Cc: Sam James Cc: Richard Biener Signed-off-by: Alejandro Colomar --- 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 | 62 +++++++--- gcc/c/c-tree.h | 4 + gcc/c/c-typeck.cc | 118 ++++++++++++++++++- gcc/doc/extend.texi | 30 +++++ gcc/testsuite/gcc.dg/countof-compile.c | 127 +++++++++++++++++++++ gcc/testsuite/gcc.dg/countof-vla.c | 46 ++++++++ gcc/testsuite/gcc.dg/countof.c | 150 +++++++++++++++++++++++++ 11 files changed, 566 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.c diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc index 7494a2dac0a..9f48fea6543 100644 --- a/gcc/c-family/c-common.cc +++ b/gcc/c-family/c-common.cc @@ -466,6 +466,7 @@ const struct c_common_resword c_common_reswords[] = { "__inline", RID_INLINE, 0 }, { "__inline__", RID_INLINE, 0 }, { "__label__", RID_LABEL, 0 }, + { "__countof__", RID_COUNTOF, 0 }, { "__null", RID_NULL, 0 }, { "__real", RID_REALPART, 0 }, { "__real__", RID_REALPART, 0 }, @@ -4071,6 +4072,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 dc49ad09e2f..f2ae784cefe 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 1e80939d379..6c6ee08925e 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_VA_ARG, RID_EXTENSION, RID_IMAGPART, RID_REALPART, RID_LABEL, RID_CHOOSE_EXPR, RID_TYPES_COMPATIBLE_P, RID_BUILTIN_COMPLEX, RID_BUILTIN_SHUFFLE, @@ -889,6 +890,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 3733ecfc13f..23c620bbea7 100644 --- a/gcc/c/c-decl.cc +++ b/gcc/c/c-decl.cc @@ -9005,12 +9005,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__")))); if (in_underspecified_init) error_at (loc, "%qT defined in underspecified object initializer", ref); @@ -9974,7 +9979,7 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes, struct_types. */ if (warn_cxx_compat && struct_parse_info != NULL - && !in_sizeof && !in_typeof && !in_alignof) + && !in_sizeof && !in_typeof && !in_alignof && !in_countof) struct_parse_info->struct_types.safe_push (t); } @@ -10148,12 +10153,17 @@ start_enum (location_t loc, struct c_enum_contents *the_enum, tree name, /* FIXME: This will issue a warning for a use of a type defined 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_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__")))); if (in_underspecified_init) error_at (loc, "%qT defined in underspecified object initializer", @@ -10347,7 +10357,7 @@ finish_enum (tree enumtype, tree values, tree attributes) struct_types. */ if (warn_cxx_compat && struct_parse_info != NULL - && !in_sizeof && !in_typeof && !in_alignof) + && !in_sizeof && !in_typeof && !in_alignof && !in_countof) struct_parse_info->struct_types.safe_push (enumtype); /* Check for consistency with previous definition */ diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc index 090ab1cbc08..73e419ea7ee 100644 --- a/gcc/c/c-parser.cc +++ b/gcc/c/c-parser.cc @@ -74,7 +74,17 @@ along with GCC; see the file COPYING3. If not see #include "bitmap.h" #include "analyzer/analyzer-language.h" #include "toplev.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) \ +) + /* We need to walk over decls with incomplete struct/union/enum types after parsing the whole translation unit. In finish_decl(), if the decl is static, has incomplete @@ -1695,7 +1705,8 @@ static struct c_expr c_parser_binary_expression (c_parser *, struct c_expr *, tree); 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_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 *, @@ -10196,6 +10207,8 @@ c_parser_unary_expression (c_parser *parser) case CPP_KEYWORD: switch (c_parser_peek_token (parser)->keyword) { + case RID_COUNTOF: + return c_parser_countof_expression (parser); case RID_SIZEOF: return c_parser_sizeof_expression (parser); case RID_ALIGNOF: @@ -10235,12 +10248,13 @@ c_parser_unary_expression (c_parser *parser) /* Parse a sizeof expression. */ static struct c_expr -c_parser_sizeof_expression (c_parser *parser) +c_parser_sizeof_or_countof_expression (c_parser *parser, enum rid rid) { + const char *op_name = (rid == RID_COUNTOF) ? "__countof__" : "sizeof"; struct c_expr expr; struct c_expr result; location_t expr_loc; - gcc_assert (c_parser_next_token_is_keyword (parser, RID_SIZEOF)); + gcc_assert (c_parser_next_token_is_keyword (parser, rid)); location_t start; location_t finish = UNKNOWN_LOCATION; @@ -10249,7 +10263,10 @@ c_parser_sizeof_expression (c_parser *parser) c_parser_consume_token (parser); c_inhibit_evaluation_warnings++; - in_sizeof++; + if (rid == RID_COUNTOF) + in_countof++; + else + in_sizeof++; if (c_parser_next_token_is (parser, CPP_OPEN_PAREN) && c_token_starts_compound_literal (c_parser_peek_2nd_token (parser))) { @@ -10268,7 +10285,10 @@ c_parser_sizeof_expression (c_parser *parser) { struct c_expr ret; c_inhibit_evaluation_warnings--; - in_sizeof--; + if (rid == RID_COUNTOF) + in_countof--; + else + in_sizeof--; ret.set_error (); ret.original_code = ERROR_MARK; ret.original_type = NULL; @@ -10280,31 +10300,45 @@ c_parser_sizeof_expression (c_parser *parser) type_name, expr_loc); finish = expr.get_finish (); - goto sizeof_expr; + goto Xof_expr; } /* sizeof ( type-name ). */ if (scspecs) - error_at (expr_loc, "storage class specifier in %"); + error_at (expr_loc, "storage class specifier in %qs", op_name); if (type_name->specs->alignas_p) error_at (type_name->specs->locations[cdw_alignas], - "alignment specified for type name in %"); + "alignment specified for type name in %qs", op_name); c_inhibit_evaluation_warnings--; - in_sizeof--; - result = c_expr_sizeof_type (expr_loc, type_name); + if (rid == RID_COUNTOF) + { + in_countof--; + result = c_expr_countof_type (expr_loc, type_name); + } + else + { + in_sizeof--; + result = c_expr_sizeof_type (expr_loc, type_name); + } } else { expr_loc = c_parser_peek_token (parser)->location; expr = c_parser_unary_expression (parser); finish = expr.get_finish (); - sizeof_expr: + Xof_expr: c_inhibit_evaluation_warnings--; - in_sizeof--; + if (rid == RID_COUNTOF) + in_countof--; + else + in_sizeof--; mark_exp_read (expr.value); if (TREE_CODE (expr.value) == COMPONENT_REF && DECL_C_BIT_FIELD (TREE_OPERAND (expr.value, 1))) - 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_COUNTOF) + result = c_expr_countof_expr (expr_loc, expr); + else + result = c_expr_sizeof_expr (expr_loc, expr); } if (finish == UNKNOWN_LOCATION) finish = start; diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h index a1435e7cb0c..9bdce690374 100644 --- a/gcc/c/c-tree.h +++ b/gcc/c/c-tree.h @@ -764,6 +764,7 @@ extern int c_type_dwarf_attribute (const_tree, int); /* in c-typeck.cc */ extern int in_alignof; extern int in_sizeof; +extern int in_countof; extern int in_typeof; extern bool c_in_omp_for; extern bool c_omp_array_section_p; @@ -815,6 +816,9 @@ 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_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, diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc index 108ea5ca3e8..14313e9d649 100644 --- a/gcc/c/c-typeck.cc +++ b/gcc/c/c-typeck.cc @@ -71,6 +71,9 @@ int in_alignof; /* The level of nesting inside "sizeof". */ int in_sizeof; +/* The level of nesting inside "countof". */ +int in_countof; + /* The level of nesting inside "typeof". */ int in_typeof; @@ -3273,7 +3276,7 @@ build_external_ref (location_t loc, tree id, bool fun, tree *type) if (TREE_CODE (ref) == FUNCTION_DECL && !in_alignof) { - if (!in_sizeof && !in_typeof) + if (!in_sizeof && !in_typeof && !in_countof) C_DECL_USED (ref) = 1; else if (DECL_INITIAL (ref) == NULL_TREE && DECL_EXTERNAL (ref) @@ -3329,7 +3332,7 @@ 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_countof). */ int level; /* The next one at this level or above, or NULL. */ struct maybe_used_decl *next; @@ -3347,7 +3350,7 @@ 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_countof; t->next = maybe_used_decls; maybe_used_decls = t; } @@ -3361,7 +3364,7 @@ void pop_maybe_used (bool used) { struct maybe_used_decl *p = maybe_used_decls; - int cur_level = in_sizeof + in_typeof; + int cur_level = in_sizeof + in_typeof + in_countof; while (p && p->level > cur_level) { if (used) @@ -3471,6 +3474,113 @@ c_expr_sizeof_type (location_t loc, struct c_type_name *t) return ret; } +static bool +is_top_array_vla (tree type) +{ + bool zero, star, var; + tree d; + + if (TREE_CODE (type) != ARRAY_TYPE) + return false; + if (!COMPLETE_TYPE_P (type)) + return false; + + d = TYPE_DOMAIN (type); + zero = !TYPE_MAX_VALUE (d); + star = (zero && C_TYPE_VARIABLE_SIZE (type)); + if (star) + return true; + if (zero) + return false; + + var = (TREE_CODE (TYPE_MIN_VALUE (d)) != INTEGER_CST + || TREE_CODE (TYPE_MAX_VALUE (d)) != INTEGER_CST); + return var; +} + +/* Return the result of countof applied to EXPR. */ + +struct c_expr +c_expr_countof_expr (location_t loc, struct c_expr expr) +{ + struct c_expr ret; + if (expr.value == error_mark_node) + { + ret.value = error_mark_node; + ret.original_code = ERROR_MARK; + ret.original_type = NULL; + ret.m_decimal = 0; + pop_maybe_used (false); + } + else + { + bool expr_const_operands = true; + + tree folded_expr = c_fully_fold (expr.value, require_constant_value, + &expr_const_operands); + ret.value = c_countof_type (loc, TREE_TYPE (folded_expr)); + c_last_sizeof_arg = expr.value; + c_last_sizeof_loc = loc; + ret.original_code = COUNTOF_EXPR; + ret.original_type = NULL; + ret.m_decimal = 0; + if (is_top_array_vla (TREE_TYPE (folded_expr))) + { + /* 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; + SET_EXPR_LOCATION (ret.value, loc); + } + pop_maybe_used (is_top_array_vla (TREE_TYPE (folded_expr))); + } + return ret; +} + +/* 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_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_countof_type (loc, type); + c_last_sizeof_arg = type; + c_last_sizeof_loc = loc; + ret.original_code = COUNTOF_EXPR; + ret.original_type = NULL; + ret.m_decimal = 0; + if (type == error_mark_node) + { + ret.value = error_mark_node; + ret.original_code = ERROR_MARK; + } + else + if ((type_expr || TREE_CODE (ret.value) == INTEGER_CST) + && is_top_array_vla (type)) + { + /* 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 countof does not get folded to a constant by + c_fully_fold, because if the number of elements is evaluated + the result is not constant and so + constraints on zero or negative size arrays must not be applied + when this countof call is inside another array declarator. */ + if (!type_expr) + type_expr = integer_zero_node; + ret.value = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (ret.value), + type_expr, ret.value); + C_MAYBE_CONST_EXPR_NON_CONST (ret.value) = !type_expr_const; + } + pop_maybe_used (type != error_mark_node ? is_top_array_vla (type) : false); + return ret; +} + /* Build a function call to function FUNCTION with parameters PARAMS. The function call is at LOC. PARAMS is a list--a chain of TREE_LIST nodes--in which the diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index 42bd567119d..4bd1f637657 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -10555,6 +10555,36 @@ 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 __countof__ +@section Determining the Number of Elements of Arrays +@cindex __countof__ +@cindex number of elements + +The keyword @code{__countof__} determines +the number of elements of an array operand. +Its syntax is similar to @code{sizeof}. +The operand must be +a parenthesized complete array type name +or an expression of such a type. +For example: + +@smallexample +int a[n]; +__countof__ (a); // returns n +__countof__ (int [7][3]); // returns 7 +@end smallexample + +The result of this operator is an integer constant expression, +unless the array has a variable number of elements. +The operand is only evaluated +if the array has a variable number of elements. +For example: + +@smallexample +__countof__ (int [7][n++]); // integer constant expression +__countof__ (int [n++][7]); // run-time value; n++ is evaluated +@end smallexample + @node Inline @section An Inline Function is As Fast As a Macro @cindex inline functions diff --git a/gcc/testsuite/gcc.dg/countof-compile.c b/gcc/testsuite/gcc.dg/countof-compile.c new file mode 100644 index 00000000000..bfb51109496 --- /dev/null +++ b/gcc/testsuite/gcc.dg/countof-compile.c @@ -0,0 +1,127 @@ +/* { dg-do compile } */ +/* { dg-options "-Wno-declaration-after-statement -Wno-pedantic -Wno-vla" } */ + +extern int x[]; + +static int w[] = {1, 2, 3}; + +static int z[0]; +static int y[__countof__(z)]; + +void +completed (void) +{ + int i = 42; + int a[] = {1, 2, i}; + + _Static_assert(__countof__ (w) == 3); + __countof__ (a); +} + +void +incomplete (int p[]) +{ + __countof__ (x); /* { dg-error "incomplete" } */ + + /* We want to support array parameters in the future, + which should change this from "invalid" to "incomplete". */ + __countof__ (p); /* { dg-error "invalid" } */ +} + +void +fam (void) +{ + struct { + int x; + int fam[]; + } s; + + __countof__ (s.fam); /* { dg-error "incomplete" } */ +} + +void +param (int n, int p[n]) +{ + /* We want to support array parameters in the future, + which would make this work. */ + __countof__ (p); /* { dg-error "invalid" } */ +} + +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) +{ + int i3[3]; + int i5[5]; + char c35[3][5]; + + fix_fix (5, &c35, &i3); + fix_fix (5, &c35, &i5); /* { dg-error "incompatible-pointer-types" } */ + + fix_var (5, &c35, &i3); + fix_var (5, &c35, &i5); /* { dg-error "incompatible-pointer-types" } */ + + fix_uns (5, &c35, &i3); + fix_uns (5, &c35, &i5); /* { dg-error "incompatible-pointer-types" } */ +} + +void +non_arr(void) +{ + int x; + int *p; + struct s { + int x[3]; + } s; + + __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(); +static int f2(); /* { dg-warning "never defined" } */ +int a[10][10]; +int n; + +void +syms(void) +{ + int b[n][n]; + + __countof__ (a[f1()]); + __countof__ (b[f2()]); +} + +void +no_parens(void) +{ + __countof__ a; + __countof__ *a; + __countof__ (int [3]) {}; + + __countof__ int [3]; /* { dg-error "expected expression before" } */ +} + +void +const_expr(void) +{ + int n = 7; + + _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: countof(int [0][n]) should result in a constant expression. */ + _Static_assert (__countof__ (int [0][n]) == 0); /* { dg-error "not constant" } */ +} diff --git a/gcc/testsuite/gcc.dg/countof-vla.c b/gcc/testsuite/gcc.dg/countof-vla.c new file mode 100644 index 00000000000..5a82aeed782 --- /dev/null +++ b/gcc/testsuite/gcc.dg/countof-vla.c @@ -0,0 +1,46 @@ +/* { dg-do compile } */ +/* { dg-options "-Wno-pedantic -Wvla-parameter" } */ + +void fix_fix (int i, + char (*a)[3][5], + int (*x)[__countof__ (*a)]); +void fix_var (int i, + char (*a)[3][i], /* dg-warn "variable" */ + int (*x)[__countof__ (*a)]); +void fix_uns (int i, + char (*a)[3][*], + int (*x)[__countof__ (*a)]); + +void zro_fix (int i, + char (*a)[0][5], + int (*x)[__countof__ (*a)]); +void zro_var (int i, + char (*a)[0][i], /* dg-warn "variable" */ + int (*x)[__countof__ (*a)]); +void zro_uns (int i, + char (*a)[0][*], + int (*x)[__countof__ (*a)]); + +void var_fix (int i, + char (*a)[i][5], /* dg-warn "variable" */ + int (*x)[__countof__ (*a)]); /* dg-warn "variable" */ +void var_var (int i, + char (*a)[i][i], /* dg-warn "variable" */ + int (*x)[__countof__ (*a)]); /* dg-warn "variable" */ +void var_uns (int i, + char (*a)[i][*], /* dg-warn "variable" */ + int (*x)[__countof__ (*a)]); /* dg-warn "variable" */ + +void uns_fix (int i, + char (*a)[*][5], + int (*x)[__countof__ (*a)]); +void uns_var (int i, + char (*a)[*][i], /* dg-warn "variable" */ + int (*x)[__countof__ (*a)]); +void uns_uns (int i, + char (*a)[*][*], + int (*x)[__countof__ (*a)]); + +// Can't test due to bug: +//static int z2[0]; +//static int y2[__countof__(z2)]; diff --git a/gcc/testsuite/gcc.dg/countof.c b/gcc/testsuite/gcc.dg/countof.c new file mode 100644 index 00000000000..063a207fb6b --- /dev/null +++ b/gcc/testsuite/gcc.dg/countof.c @@ -0,0 +1,150 @@ +/* { dg-do run } */ +/* { dg-options "-Wno-declaration-after-statement -Wno-pedantic -Wno-vla" } */ + +#undef NDEBUG +#include + +void +array (void) +{ + short a[7]; + + static_assert (__countof__ (a) == 7); + static_assert (__countof__ (long [0]) == 0); + static_assert (__countof__ (unsigned [99]) == 99); +} + +void +automatic(void) +{ + int a[] = {1, 2, 3}; + int z[] = {}; + + static_assert (__countof__ (a) == 3); + static_assert (__countof__ (z) == 0); +} + +void +vla (void) +{ + unsigned n; + + n = 99; + assert (__countof__ (short [n - 10]) == 99 - 10); + + int v[n / 2]; + assert (__countof__ (v) == 99 / 2); + + n = 0; + int z[n]; + assert (__countof__ (z) == 0); +} + +void +member (void) +{ + struct { + int a[8]; + } s; + + static_assert (__countof__ (s.a) == 8); +} + +void +vla_eval (void) +{ + int i; + + i = 7; + assert (__countof__ (struct {int x;}[i++]) == 7); + assert (i == 7 + 1); + + int v[i]; + int (*p)[i]; + p = &v; + assert (__countof__ (*p++) == i); + assert (p - 1 == &v); +} + +void +inner_vla_noeval (void) +{ + int i; + + i = 3; + static_assert (__countof__ (struct {int x[i++];}[3]) == 3); + assert (i == 3); +} + +void +array_noeval (void) +{ + long a[5]; + long (*p)[__countof__ (a)]; + + p = &a; + static_assert (__countof__ (*p++) == 5); + assert (p == &a); +} + +void +matrix_zero (void) +{ + int i; + + static_assert (__countof__ (int [0][4]) == 0); + i = 3; + assert (__countof__ (int [0][i]) == 0); +} + +void +matrix_fixed (void) +{ + int i; + + static_assert (__countof__ (int [7][4]) == 7); + i = 3; + static_assert (__countof__ (int [7][i]) == 7); +} + +void +matrix_vla (void) +{ + int i, j; + + i = 7; + assert (__countof__ (int [i++][4]) == 7); + assert (i == 7 + 1); + + i = 9; + j = 3; + assert (__countof__ (int [i++][j]) == 9); + assert (i == 9 + 1); +} + +void +no_parens(void) +{ + int n = 3; + int a[7]; + int v[n]; + + static_assert (__countof__ a == 7); + assert (__countof__ v == 3); +} + +int +main (void) +{ + array (); + automatic (); + vla (); + member (); + vla_eval (); + inner_vla_noeval (); + array_noeval (); + matrix_zero (); + matrix_fixed (); + matrix_vla (); + no_parens (); +}