From patchwork Mon Nov 4 23:26:47 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marek Polacek X-Patchwork-Id: 2006579 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=K5T5N3NN; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=2620:52:3:1:0:246e:9693:128c; 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 [IPv6:2620:52:3:1:0:246e:9693:128c]) (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 4Xj70q5Qvkz1xyM for ; Tue, 5 Nov 2024 10:27:23 +1100 (AEDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 663A13857706 for ; Mon, 4 Nov 2024 23:27:21 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by sourceware.org (Postfix) with ESMTP id 3D08E3858C2B for ; Mon, 4 Nov 2024 23:26:58 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 3D08E3858C2B Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 3D08E3858C2B Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1730762823; cv=none; b=dwV/aLxZHZsbdqEF8VtvCGPlgMagxv1BvtDJymc+/6hA2deDIz0eBHdxZelOem5ouleIRtl6tsbsgXmq8rb73r35mo3EPzkpikxEE07xQQ+7eF1nHeCEGpCz5COve9BJX6mNNnOe6QYfgjEo8XkA3iu0steLX19jn697rIpVl8k= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1730762823; c=relaxed/simple; bh=AVb0cG7ln8IaYWNYHUPGObxHFJNqjnmUCykukBPe2uI=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=k1lBKcUsNau+HRRFyzL0vDUB18GFHa1bUBdEOcmXcqkDdHF68SHZ9X3CHx9KBcAVfbaesnZWJ+9xjn0OKnmAN6MFpLaJUBEjcCE9M8Tqyn9GJTjWaXTFf7EDru9mh62ESA5bKHwqB1D+WnjoBoEW30jZ//KLXktSjGPi6e36jSE= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1730762817; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=/FugMFB0znxcuZekiXC4/54ZS21o0MFRzGPQKJ1OXVA=; b=K5T5N3NNfMm2jJotIEEZehiiEhh9IqXV4g0wirpGC1x+i160bdcWaoMH2aRlpOPFuF3qYd OKLrTb5ycjmC4LunPlImGuxXxHE2KWmy+EUAJUMJigfrbUgws2sficWRy5FkoxthbssxKN 8vHgLdNCDJUuHEhL/NyHCSZHVCfjBio= Received: from mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-495-8mgejqgsMEmMkMqKL1CDjQ-1; Mon, 04 Nov 2024 18:26:55 -0500 X-MC-Unique: 8mgejqgsMEmMkMqKL1CDjQ-1 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 376B719560B1; Mon, 4 Nov 2024 23:26:54 +0000 (UTC) Received: from pdp-11.lan (unknown [10.22.81.168]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 3D2A419560A2; Mon, 4 Nov 2024 23:26:52 +0000 (UTC) From: Marek Polacek To: GCC Patches , Joseph Myers Subject: [PATCH] c: Implement C2y N3356, if declarations [PR117019] Date: Mon, 4 Nov 2024 18:26:47 -0500 Message-ID: <20241104232647.142859-1-polacek@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.12 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com 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 Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk? -- >8 -- This patch implements C2y N3356, if declarations as described at . This feature is cognate with C++17 Selection statements with initializer , but they are not the same yet. For example, C++17 allows if (lock (); int i = getval ()) whereas C2y does not. The proposal adds new grammar productions. selection-header is handled in c_parser_selection_header which is the gist of the patch. simple-declaration is handled by c_parser_declaration_or_fndef, which gets a new parameter. PR c/117019 gcc/c/ChangeLog: * c-parser.cc (c_parser_declaration_or_fndef): Adjust declaration. (c_parser_external_declaration): Adjust a call to c_parser_declaration_or_fndef. (c_parser_declaration_or_fndef): New bool parameter. Return a tree instead of void. Add an error. Adjust for N3356. Adjust a call to c_parser_declaration_or_fndef. (c_parser_compound_statement_nostart): Adjust calls to c_parser_declaration_or_fndef. (c_parser_selection_header): New. (c_parser_paren_selection_header): New. (c_parser_if_statement): Call c_parser_paren_selection_header instead of c_parser_paren_condition. (c_parser_switch_statement): Call c_parser_selection_header instead of c_parser_expression. (c_parser_for_statement): Adjust calls to c_parser_declaration_or_fndef. (c_parser_objc_methodprotolist): Likewise. (c_parser_oacc_routine): Likewise. (c_parser_omp_loop_nest): Likewise. (c_parser_omp_declare_simd): Likewise. gcc/testsuite/ChangeLog: * gcc.dg/c23-if-decls-1.c: New test. * gcc.dg/c23-if-decls-2.c: New test. * gcc.dg/c2y-if-decls-1.c: New test. * gcc.dg/c2y-if-decls-2.c: New test. * gcc.dg/c2y-if-decls-3.c: New test. * gcc.dg/c2y-if-decls-4.c: New test. * gcc.dg/c2y-if-decls-5.c: New test. * gcc.dg/c2y-if-decls-6.c: New test. * gcc.dg/c2y-if-decls-7.c: New test. * gcc.dg/gnu2y-if-decls-1.c: New test. * gcc.dg/gnu99-if-decls-1.c: New test. * gcc.dg/gnu99-if-decls-2.c: New test. --- gcc/c/c-parser.cc | 250 ++++++++++++++++++------ gcc/testsuite/gcc.dg/c23-if-decls-1.c | 15 ++ gcc/testsuite/gcc.dg/c23-if-decls-2.c | 6 + gcc/testsuite/gcc.dg/c2y-if-decls-1.c | 154 +++++++++++++++ gcc/testsuite/gcc.dg/c2y-if-decls-2.c | 38 ++++ gcc/testsuite/gcc.dg/c2y-if-decls-3.c | 40 ++++ gcc/testsuite/gcc.dg/c2y-if-decls-4.c | 191 ++++++++++++++++++ gcc/testsuite/gcc.dg/c2y-if-decls-5.c | 35 ++++ gcc/testsuite/gcc.dg/c2y-if-decls-6.c | 27 +++ gcc/testsuite/gcc.dg/c2y-if-decls-7.c | 21 ++ gcc/testsuite/gcc.dg/gnu2y-if-decls-1.c | 15 ++ gcc/testsuite/gcc.dg/gnu99-if-decls-1.c | 15 ++ gcc/testsuite/gcc.dg/gnu99-if-decls-2.c | 15 ++ 13 files changed, 766 insertions(+), 56 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/c23-if-decls-1.c create mode 100644 gcc/testsuite/gcc.dg/c23-if-decls-2.c create mode 100644 gcc/testsuite/gcc.dg/c2y-if-decls-1.c create mode 100644 gcc/testsuite/gcc.dg/c2y-if-decls-2.c create mode 100644 gcc/testsuite/gcc.dg/c2y-if-decls-3.c create mode 100644 gcc/testsuite/gcc.dg/c2y-if-decls-4.c create mode 100644 gcc/testsuite/gcc.dg/c2y-if-decls-5.c create mode 100644 gcc/testsuite/gcc.dg/c2y-if-decls-6.c create mode 100644 gcc/testsuite/gcc.dg/c2y-if-decls-7.c create mode 100644 gcc/testsuite/gcc.dg/gnu2y-if-decls-1.c create mode 100644 gcc/testsuite/gcc.dg/gnu99-if-decls-1.c create mode 100644 gcc/testsuite/gcc.dg/gnu99-if-decls-2.c base-commit: fe97ac43e05a8da8a12fbad2208a1ebb19d2d6c9 diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc index 179c772fb76..7ed5b40cf1d 100644 --- a/gcc/c/c-parser.cc +++ b/gcc/c/c-parser.cc @@ -1634,8 +1634,8 @@ static bool c_parser_nth_token_starts_std_attributes (c_parser *, static tree c_parser_std_attribute_specifier_sequence (c_parser *); static void c_parser_external_declaration (c_parser *); static void c_parser_asm_definition (c_parser *); -static void c_parser_declaration_or_fndef (c_parser *, bool, bool, bool, - bool, bool, tree * = NULL, +static tree c_parser_declaration_or_fndef (c_parser *, bool, bool, bool, + bool, bool, bool, tree * = NULL, vec * = NULL, bool have_attrs = false, tree attrs = NULL, @@ -2060,7 +2060,8 @@ c_parser_external_declaration (c_parser *parser) an @interface or @protocol with prefix attributes). We can only tell which after parsing the declaration specifiers, if any, and the first declarator. */ - c_parser_declaration_or_fndef (parser, true, true, true, false, true); + c_parser_declaration_or_fndef (parser, true, true, true, false, true, + false); break; } } @@ -2145,7 +2146,13 @@ handle_assume_attribute (location_t here, tree attrs, bool nested) parsed in the caller (in contexts where such attributes had to be parsed to determine whether what follows is a declaration or a statement); HAVE_ATTRS says whether there were any such attributes - (even empty). + (even empty). If SIMPLE_OK, the construct can be a simple-declaration; + in that case, the ';' is not consumed (left to the caller so that it + can figure out if there was a simple-declaration or not), there must + be an initializer, and only one object may be declared. When SIMPLE_OK + is true we are called from c_parser_selection_header. + + Returns the resulting declaration, if there was any with an initializer. declaration: declaration-specifiers init-declarator-list[opt] ; @@ -2167,6 +2174,10 @@ handle_assume_attribute (location_t here, tree attrs, bool nested) declarator simple-asm-expr[opt] gnu-attributes[opt] declarator simple-asm-expr[opt] gnu-attributes[opt] = initializer + simple-declaration: + attribute-specifier-sequence[opt] declaration-specifiers declarator + = initializer + GNU extensions: nested-function-definition: @@ -2213,10 +2224,11 @@ handle_assume_attribute (location_t here, tree attrs, bool nested) declaration-specifiers[opt] __RTL (gimple-or-rtl-pass-list) declarator declaration-list[opt] compound-statement */ -static void +static tree c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, bool static_assert_ok, bool empty_ok, bool nested, bool start_attr_ok, + bool simple_ok, tree *objc_foreach_object_declaration /* = NULL */, vec *omp_declare_simd_clauses @@ -2232,6 +2244,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, tree all_prefix_attrs; bool diagnosed_no_specs = false; location_t here = c_parser_peek_token (parser)->location; + tree result = NULL_TREE; add_debug_begin_stmt (c_parser_peek_token (parser)->location); @@ -2239,7 +2252,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, && c_parser_next_token_is_keyword (parser, RID_STATIC_ASSERT)) { c_parser_static_assert_declaration (parser); - return; + return result; } specs = build_null_declspecs (); @@ -2325,13 +2338,13 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, if (parser->error) { c_parser_skip_to_end_of_block_or_statement (parser); - return; + return result; } if (nested && !specs->declspecs_seen_p) { c_parser_error (parser, "expected declaration specifiers"); c_parser_skip_to_end_of_block_or_statement (parser); - return; + return result; } finish_declspecs (specs); @@ -2366,6 +2379,10 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, break; } } + + if (simple_ok && specs->storage_class != csc_none) + error_at (here, "invalid storage class in condition"); + if (c_parser_next_token_is (parser, CPP_SEMICOLON)) { bool handled_assume = false; @@ -2383,7 +2400,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, c_parser_pragma (parser, pragma_external, NULL, NULL_TREE); } c_parser_consume_token (parser); - return; + return result; } if (specs->typespec_kind == ctsk_none && lookup_attribute ("gnu", "assume", specs->attrs)) @@ -2425,7 +2442,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, c_parser_consume_token (parser); if (oacc_routine_data) c_finish_oacc_routine (oacc_routine_data, NULL_TREE, false); - return; + return result; } /* Provide better error recovery. Note that a type name here is usually @@ -2438,7 +2455,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, c_parser_error (parser, "expected %<;%>, identifier or %<(%>"); parser->error = false; shadow_tag_warned (specs, 1); - return; + return result; } else if (c_dialect_objc () && !any_auto_type_p) { @@ -2448,7 +2465,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, case CPP_PLUS: case CPP_MINUS: if (c_parser_objc_diagnose_bad_element_prefix (parser, specs)) - return; + return result; if (specs->attrs) { warning_at (c_parser_peek_token (parser)->location, @@ -2460,7 +2477,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, c_parser_objc_method_definition (parser); else c_parser_objc_methodproto (parser); - return; + return result; break; default: break; @@ -2475,15 +2492,15 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, case RID_AT_INTERFACE: { if (c_parser_objc_diagnose_bad_element_prefix (parser, specs)) - return; + return result; c_parser_objc_class_definition (parser, specs->attrs); - return; + return result; } break; case RID_AT_IMPLEMENTATION: { if (c_parser_objc_diagnose_bad_element_prefix (parser, specs)) - return; + return result; if (specs->attrs) { warning_at (c_parser_peek_token (parser)->location, @@ -2492,15 +2509,15 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, specs->attrs = NULL_TREE; } c_parser_objc_class_definition (parser, NULL_TREE); - return; + return result; } break; case RID_AT_PROTOCOL: { if (c_parser_objc_diagnose_bad_element_prefix (parser, specs)) - return; + return result; c_parser_objc_protocol_definition (parser, specs->attrs); - return; + return result; } break; case RID_AT_ALIAS: @@ -2532,6 +2549,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, prefix_attrs = specs->attrs; all_prefix_attrs = prefix_attrs; specs->attrs = NULL_TREE; + bool more_than_one_decl = false; while (true) { struct c_declarator *declarator; @@ -2554,8 +2572,10 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, omp_declare_simd_clauses); if (oacc_routine_data) c_finish_oacc_routine (oacc_routine_data, NULL_TREE, false); - c_parser_skip_to_end_of_block_or_statement (parser); - return; + /* This check is here purely to improve the diagnostic. */ + if (!simple_ok) + c_parser_skip_to_end_of_block_or_statement (parser); + return result; } if (flag_openmp || flag_openmp_simd) { @@ -2572,7 +2592,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, "%<__auto_type%> requires a plain identifier" " as declarator"); c_parser_skip_to_end_of_block_or_statement (parser); - return; + return result; } if (std_auto_type_p) { @@ -2585,7 +2605,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, "% requires a plain identifier, possibly with" " attributes, as declarator"); c_parser_skip_to_end_of_block_or_statement (parser); - return; + return result; } underspec_name = d->u.id.id; } @@ -2626,7 +2646,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, error_at (here, "attributes should be specified before the " "declarator in a function definition"); c_parser_skip_to_end_of_block_or_statement (parser); - return; + return result; } } if (c_parser_next_token_is (parser, CPP_EQ)) @@ -2766,6 +2786,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, maybe_warn_string_init (init_loc, TREE_TYPE (d), init); finish_decl (d, init_loc, init.value, init.original_type, asm_name); + result = d; } } else @@ -2776,7 +2797,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, "%qs requires an initialized data declaration", any_auto_type_p ? auto_type_keyword : "constexpr"); c_parser_skip_to_end_of_block_or_statement (parser); - return; + return result; } location_t lastloc = UNKNOWN_LOCATION; @@ -2869,13 +2890,14 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, } if (c_parser_next_token_is (parser, CPP_COMMA)) { + more_than_one_decl = true; if (any_auto_type_p || specs->constexpr_p) { error_at (here, "%qs may only be used with a single declarator", any_auto_type_p ? auto_type_keyword : "constexpr"); c_parser_skip_to_end_of_block_or_statement (parser); - return; + return result; } c_parser_consume_token (parser); if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE)) @@ -2887,8 +2909,9 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, } else if (c_parser_next_token_is (parser, CPP_SEMICOLON)) { - c_parser_consume_token (parser); - return; + if (!simple_ok) + c_parser_consume_token (parser); + return result; } else if (c_parser_next_token_is_keyword (parser, RID_IN)) { @@ -2897,13 +2920,20 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, Objective-C foreach statement. Do not consume the token, so that the caller can use it to determine that this indeed is a foreach context. */ - return; + return result; } else { - c_parser_error (parser, "expected %<,%> or %<;%>"); - c_parser_skip_to_end_of_block_or_statement (parser); - return; + if (!simple_ok) + { + c_parser_error (parser, "expected %<,%> or %<;%>"); + c_parser_skip_to_end_of_block_or_statement (parser); + } + /* It's not valid to use if (int i = 2, j = 3). */ + else if (more_than_one_decl) + error_at (here, "declaration in condition can only declare " + "a single object"); + return result; } } else if (any_auto_type_p || specs->constexpr_p) @@ -2912,14 +2942,19 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, "%qs requires an initialized data declaration", any_auto_type_p ? auto_type_keyword : "constexpr"); c_parser_skip_to_end_of_block_or_statement (parser); - return; + return result; } else if (!fndef_ok) { - c_parser_error (parser, "expected %<=%>, %<,%>, %<;%>, " - "% or %<__attribute__%>"); - c_parser_skip_to_end_of_block_or_statement (parser); - return; + if (simple_ok && c_parser_next_token_is (parser, CPP_CLOSE_PAREN)) + /* Let c_parser_selection_header emit the error. */; + else + { + c_parser_error (parser, "expected %<=%>, %<,%>, %<;%>, " + "% or %<__attribute__%>"); + c_parser_skip_to_end_of_block_or_statement (parser); + } + return result; } /* Function definition (nested or otherwise). */ if (nested) @@ -2988,7 +3023,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, while (c_parser_next_token_is_not (parser, CPP_EOF) && c_parser_next_token_is_not (parser, CPP_OPEN_BRACE)) c_parser_declaration_or_fndef (parser, false, false, false, - true, false); + true, false, false); debug_nonbind_markers_p = save_debug_nonbind_markers_p; store_parm_decls (); if (omp_declare_simd_clauses) @@ -3018,7 +3053,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, pop_scope (); finish_function (endloc); - return; + return result; } /* If the definition was marked with __GIMPLE then parse the function body as GIMPLE. */ @@ -3059,6 +3094,8 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, break; } + + return result; } /* Parse an asm-definition (asm() outside a function body). This is a @@ -7378,7 +7415,7 @@ c_parser_compound_statement_nostart (c_parser *parser) mark_valid_location_for_stdc_pragma (false); bool fallthru_attr_p = false; c_parser_declaration_or_fndef (parser, true, !have_std_attrs, - true, true, true, NULL, + true, true, true, false, NULL, NULL, have_std_attrs, std_attrs, NULL, &fallthru_attr_p); @@ -7421,7 +7458,7 @@ c_parser_compound_statement_nostart (c_parser *parser) } mark_valid_location_for_stdc_pragma (false); c_parser_declaration_or_fndef (parser, true, true, true, true, - true); + true, false); if (in_omp_loop_block) omp_for_parse_state->want_nested_loop = want_nested_loop; /* Following the old parser, __extension__ does not @@ -8075,11 +8112,12 @@ c_parser_condition (c_parser *parser) return cond; } -/* Parse a parenthesized condition from an if, do or while statement. +/* Parse a parenthesized condition from a do or while statement. condition: ( expression ) */ + static tree c_parser_paren_condition (c_parser *parser) { @@ -8092,6 +8130,103 @@ c_parser_paren_condition (c_parser *parser) return cond; } +/* Parse a selection-header: + + selection-header: + expression + declaration expression + simple-declaration + + simple-declaration: + attribute-specifier-sequence[opt] declaration-specifiers declarator + = initializer + + SWITCH_P is true if we are called from c_parser_switch_statement; in + that case, don't perform the truthvalue conversion. */ + +static c_expr +c_parser_selection_header (c_parser *parser, bool switch_p) +{ + location_t loc = c_parser_peek_token (parser)->location; + c_expr expr; + bool parse_expr = true; + tree std_attrs; + bool have_std_attrs = c_parser_nth_token_starts_std_attributes (parser, 1); + if (have_std_attrs) + std_attrs = c_parser_std_attribute_specifier_sequence (parser); + else + std_attrs = NULL_TREE; + if (c_parser_next_tokens_start_declaration (parser)) + { + pedwarn_c23 (loc, OPT_Wpedantic, + "ISO C does not support if declarations before C2Y"); + expr.value + = c_parser_declaration_or_fndef (parser, + /*fndef_ok=*/false, + /*static_assert_ok=*/false, + /*empty_ok=*/false, + /*nested=*/true, + /*start_attr_ok=*/true, + /*simple_ok=*/true, + /*objc_foreach_object_decl=*/nullptr, + /*omp_declare_simd_clauses=*/nullptr, + have_std_attrs, + std_attrs); + if (c_parser_next_token_is (parser, CPP_SEMICOLON)) + c_parser_consume_token (parser); + else + { + /* A simple-declaration is a declaration that can appear in + place of the controlling expression of a selection statement. + In that case, there shall be an initializer. */ + if (!expr.value) + { + error_at (loc, "declaration in the controlling expression must " + "have an initializer"); + expr.original_type = error_mark_node; + expr.set_error (); + return expr; + } + parse_expr = false; + expr.original_type = TREE_TYPE (expr.value); + } + } + else if (have_std_attrs) + { + c_parser_error (parser, "expected declaration"); + expr.original_type = error_mark_node; + expr.set_error (); + return expr; + } + + if (parse_expr) + expr = c_parser_expression_conv (parser); + if (!switch_p) + { + expr.value = c_objc_common_truthvalue_conversion (loc, expr.value); + expr.value = c_fully_fold (expr.value, false, NULL); + if (warn_sequence_point) + verify_sequence_points (expr.value); + } + return expr; +} + +/* Parse a selection-header enclosed in parentheses: + + ( selection-header ) +*/ + +static tree +c_parser_paren_selection_header (c_parser *parser) +{ + matching_parens parens; + if (!parens.require_open (parser)) + return error_mark_node; + tree cond = c_parser_selection_header (parser, /*switch_p=*/false).value; + parens.skip_until_found_close (parser); + return cond; +} + /* Parse a statement which is a block in C99. IF_P is used to track whether there's a (possibly labeled) if statement @@ -8244,8 +8379,8 @@ c_parser_maybe_reclassify_token (c_parser *parser) /* Parse an if statement (C90 6.6.4, C99 6.8.4, C11 6.8.4). if-statement: - if ( expression ) statement - if ( expression ) statement else statement + if ( selection-header ) statement + if ( selection-header ) statement else statement CHAIN is a vector of if-else-if conditions. IF_P is used to track whether there's a (possibly labeled) if statement @@ -8268,7 +8403,7 @@ c_parser_if_statement (c_parser *parser, bool *if_p, vec *chain) c_parser_consume_token (parser); block = c_begin_compound_stmt (flag_isoc99); loc = c_parser_peek_token (parser)->location; - cond = c_parser_paren_condition (parser); + cond = c_parser_paren_selection_header (parser); in_if_block = parser->in_if_block; parser->in_if_block = true; first_body = c_parser_if_body (parser, &nested_if, if_tinfo); @@ -8355,7 +8490,9 @@ c_parser_switch_statement (c_parser *parser, bool *if_p, tree before_labels) if (c_parser_next_token_is (parser, CPP_OPEN_PAREN) && c_token_starts_typename (c_parser_peek_2nd_token (parser))) explicit_cast_p = true; - ce = c_parser_expression (parser); + ce = c_parser_selection_header (parser, /*switch_p=*/true); + /* The call above already performed convert_lvalue_to_rvalue, but with + read_p=false. */ ce = convert_lvalue_to_rvalue (switch_cond_loc, ce, true, true); expr = ce.value; /* ??? expr has no valid location? */ @@ -8667,7 +8804,7 @@ c_parser_for_statement (c_parser *parser, bool ivdep, unsigned short unroll, || c_parser_nth_token_starts_std_attributes (parser, 1)) { c_parser_declaration_or_fndef (parser, true, true, true, true, true, - &object_expression); + false, &object_expression); parser->objc_could_be_foreach_context = false; if (c_parser_next_token_is_keyword (parser, RID_IN)) @@ -8698,7 +8835,7 @@ c_parser_for_statement (c_parser *parser, bool ivdep, unsigned short unroll, ext = disable_extension_diagnostics (); c_parser_consume_token (parser); c_parser_declaration_or_fndef (parser, true, true, true, true, - true, &object_expression); + true, false, &object_expression); parser->objc_could_be_foreach_context = false; restore_extension_diagnostics (ext); @@ -14050,7 +14187,7 @@ c_parser_objc_methodprotolist (c_parser *parser) } else c_parser_declaration_or_fndef (parser, false, false, true, - false, true); + false, true, false); break; } } @@ -21170,12 +21307,12 @@ c_parser_oacc_routine (c_parser *parser, enum pragma_context context) while (c_parser_next_token_is (parser, CPP_KEYWORD) && c_parser_peek_token (parser)->keyword == RID_EXTENSION); c_parser_declaration_or_fndef (parser, true, true, true, false, true, - NULL, NULL, false, NULL, &data); + false, NULL, NULL, false, NULL, &data); restore_extension_diagnostics (ext); } else c_parser_declaration_or_fndef (parser, true, true, true, false, true, - NULL, NULL, false, NULL, &data); + false, NULL, NULL, false, NULL, &data); } } @@ -23136,7 +23273,8 @@ c_parser_omp_loop_nest (c_parser *parser, bool *if_p) /* This is a declaration, which must be added to the pre_body code. */ tree this_pre_body = push_stmt_list (); c_in_omp_for = true; - c_parser_declaration_or_fndef (parser, true, true, true, true, true); + c_parser_declaration_or_fndef (parser, true, true, true, true, true, + false); c_in_omp_for = false; this_pre_body = pop_stmt_list (this_pre_body); append_to_statement_list_force (this_pre_body, @@ -25378,12 +25516,12 @@ c_parser_omp_declare_simd (c_parser *parser, enum pragma_context context) while (c_parser_next_token_is (parser, CPP_KEYWORD) && c_parser_peek_token (parser)->keyword == RID_EXTENSION); c_parser_declaration_or_fndef (parser, true, true, true, false, true, - NULL, &clauses); + false, NULL, &clauses); restore_extension_diagnostics (ext); } else c_parser_declaration_or_fndef (parser, true, true, true, false, true, - NULL, &clauses); + false, NULL, &clauses); break; case pragma_struct: case pragma_param: @@ -25412,7 +25550,7 @@ c_parser_omp_declare_simd (c_parser *parser, enum pragma_context context) || c_parser_nth_token_starts_std_attributes (parser, 1)) { c_parser_declaration_or_fndef (parser, true, true, true, true, - true, NULL, &clauses, + true, false, NULL, &clauses, have_std_attrs, std_attrs); restore_extension_diagnostics (ext); break; @@ -25422,7 +25560,7 @@ c_parser_omp_declare_simd (c_parser *parser, enum pragma_context context) else if (c_parser_next_tokens_start_declaration (parser)) { c_parser_declaration_or_fndef (parser, true, true, true, true, true, - NULL, &clauses, have_std_attrs, + false, NULL, &clauses, have_std_attrs, std_attrs); break; } diff --git a/gcc/testsuite/gcc.dg/c23-if-decls-1.c b/gcc/testsuite/gcc.dg/c23-if-decls-1.c new file mode 100644 index 00000000000..ea968c67c6a --- /dev/null +++ b/gcc/testsuite/gcc.dg/c23-if-decls-1.c @@ -0,0 +1,15 @@ +/* N3356 - if declarations. */ +/* PR c/117019 */ +/* { dg-do compile } */ +/* { dg-options "-std=c23 -pedantic-errors" } */ + +void +g () +{ + if (int i = 42); /* { dg-error "ISO C does not support if declarations before C2Y" } */ + if (int i = 42; i > 10); /* { dg-error "ISO C does not support if declarations before C2Y" } */ + if (int i, j; i = 42); /* { dg-error "ISO C does not support if declarations before C2Y" } */ + switch (int i = 42); /* { dg-error "ISO C does not support if declarations before C2Y" } */ + switch (int i = 42; i); /* { dg-error "ISO C does not support if declarations before C2Y" } */ + switch (int i, j; i = 42); /* { dg-error "ISO C does not support if declarations before C2Y" } */ +} diff --git a/gcc/testsuite/gcc.dg/c23-if-decls-2.c b/gcc/testsuite/gcc.dg/c23-if-decls-2.c new file mode 100644 index 00000000000..d53db715377 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c23-if-decls-2.c @@ -0,0 +1,6 @@ +/* N3356 - if declarations. */ +/* PR c/117019 */ +/* { dg-do compile } */ +/* { dg-options "-std=c23 -pedantic-errors -Wno-c23-c2y-compat" } */ + +#include "c23-if-decls-1.c" diff --git a/gcc/testsuite/gcc.dg/c2y-if-decls-1.c b/gcc/testsuite/gcc.dg/c2y-if-decls-1.c new file mode 100644 index 00000000000..417b8052775 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2y-if-decls-1.c @@ -0,0 +1,154 @@ +/* N3356 - if declarations. */ +/* PR c/117019 */ +/* { dg-do run } */ +/* { dg-options "-std=c2y -Wc23-c2y-compat" } */ +/* Test C2Y if declarations. Valid usages. */ + +int get () { return 42; } +int foo (int i) { return i; } + +enum E { X = 1, Y }; + +void +simple () +{ + if (int i = get ()) /* { dg-warning "if declarations before C2Y" } */ + foo (i); + else + __builtin_abort (); + + if (int i = 0) /* { dg-warning "if declarations before C2Y" } */ + __builtin_abort (); + else + foo (i); + + if (auto i = get ()) /* { dg-warning "if declarations before C2Y" } */ + foo (i); + else + __builtin_abort (); + + if (__typeof__(get ()) i = get ()) /* { dg-warning "if declarations before C2Y" } */ + foo (i); + else + __builtin_abort (); + + if (auto i = 0) /* { dg-warning "if declarations before C2Y" } */ + __builtin_abort (); + else + foo (i); + + if (int (*f)(int) = foo) /* { dg-warning "if declarations before C2Y" } */ + f (1); + else + __builtin_abort (); + + if ([[maybe_unused]] int i = get ()) /* { dg-warning "if declarations before C2Y" } */ + foo (i); + else + __builtin_abort (); + + if (__attribute__((unused)) int i = get ()) /* { dg-warning "if declarations before C2Y" } */ + foo (i); + else + __builtin_abort (); + + if (enum E e = X) /* { dg-warning "if declarations before C2Y" } */ + foo (e); + else + __builtin_abort (); + + if (constexpr int i = 42) /* { dg-warning "if declarations before C2Y" } */ + foo (i); + else + __builtin_abort (); + + if (int i = 1) /* { dg-warning "if declarations before C2Y" } */ + if (int j = 2) /* { dg-warning "if declarations before C2Y" } */ + if (int k = 3) /* { dg-warning "if declarations before C2Y" } */ + foo (i + j + k); + + double i; +} + +void +expr () +{ + if (int i = get (); i == 42) /* { dg-warning "if declarations before C2Y" } */ + foo (i); + else + __builtin_abort (); + + if (int i = get (); i != 42) /* { dg-warning "if declarations before C2Y" } */ + __builtin_abort (); + else + foo (i); + + if (auto i = get (); i == 42) /* { dg-warning "if declarations before C2Y" } */ + foo (i); + else + __builtin_abort (); + + if (__typeof__(get ()) i = get (); i == 42) /* { dg-warning "if declarations before C2Y" } */ + foo (i); + else + __builtin_abort (); + + if (auto i = get (); i != 42) /* { dg-warning "if declarations before C2Y" } */ + __builtin_abort (); + else + foo (i); + + if (int (*f)(int) = foo; f (42)) /* { dg-warning "if declarations before C2Y" } */ + f (1); + else + __builtin_abort (); + + if ([[maybe_unused]] int i = get (); i == 42) /* { dg-warning "if declarations before C2Y" } */ + foo (i); + else + __builtin_abort (); + + if (__attribute__((unused)) int i = get (); i == 42) /* { dg-warning "if declarations before C2Y" } */ + foo (i); + else + __builtin_abort (); + + if (enum E e = X; e == X) /* { dg-warning "if declarations before C2Y" } */ + foo (e); + else + __builtin_abort (); + + if (constexpr int i = 42; i == 42) /* { dg-warning "if declarations before C2Y" } */ + foo (i); + else + __builtin_abort (); + + if (int i = 1; i) /* { dg-warning "if declarations before C2Y" } */ + if (int j = 2; j) /* { dg-warning "if declarations before C2Y" } */ + if (int k = 3; k) /* { dg-warning "if declarations before C2Y" } */ + foo (i + j + k); + + if (int i = 2, j = get (); i + j > 0) /* { dg-warning "if declarations before C2Y" } */ + foo (i + j); + else + __builtin_abort (); + + if (int i; i = 1) /* { dg-warning "if declarations before C2Y" } */ + foo (i); + else + __builtin_abort (); + + if (int arr[] = { 1, 2, 3}; arr[0]) /* { dg-warning "if declarations before C2Y" } */ + foo (arr[0]); + else + __builtin_abort (); + + double i; +} + +int +main () +{ + simple (); + expr (); +} diff --git a/gcc/testsuite/gcc.dg/c2y-if-decls-2.c b/gcc/testsuite/gcc.dg/c2y-if-decls-2.c new file mode 100644 index 00000000000..e06344e4fe0 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2y-if-decls-2.c @@ -0,0 +1,38 @@ +/* N3356 - if declarations. */ +/* PR c/117019 */ +/* { dg-do compile } */ +/* { dg-options "-std=c2y" } */ +/* Test C2Y if declarations. Invalid usages. */ + +void +g (int g) +{ + if (;); /* { dg-error "expected" } */ + if (int); /* { dg-error "expected|initializer" } */ + if (auto); /* { dg-error "expected|initializer" } */ + if (int;); /* { dg-error "initializer" } */ + /* { dg-warning "empty" "" { target *-*-* } .-1 } */ + if (auto;); /* { dg-error "empty|initializer" } */ + if (int i); /* { dg-error "initializer" } */ + if (int i;); /* { dg-error "expected" } */ + if (int i = 0;); /* { dg-error "expected" } */ + + if (extern int i = 0); /* { dg-error "in condition|both .extern. and initializer" } */ + if (register int i = 0); /* { dg-error "in condition" } */ + if (static int i = 0); /* { dg-error "in condition" } */ + if (thread_local int i = 0); /* { dg-error "in condition|function-scope" } */ + if (typedef int i); /* { dg-error "in condition|initializer" } */ + if (typedef int i = 0); /* { dg-error "in condition|initialized" } */ + + if (int i = 2, j = 3); /* { dg-error "only declare a single object" } */ + + if (void (*fp)(int)); /* { dg-error "initializer" } */ + if ([[maybe_unused]] g); /* { dg-error "expected" } */ + if ([[maybe_unused]] 42); /* { dg-error "expected" } */ + if ([[maybe_unused]] int); /* { dg-error "expected|initializer" } */ + if (__attribute__((unused)) g); /* { dg-error "initializer" } */ + if (__attribute__((unused)) 42); /* { dg-error "expected|initializer" } */ + if (__attribute__((unused)) int); /* { dg-error "expected|initializer" } */ + + if (int arr[] = { 1 }); /* { dg-error "scalar is required" } */ +} diff --git a/gcc/testsuite/gcc.dg/c2y-if-decls-3.c b/gcc/testsuite/gcc.dg/c2y-if-decls-3.c new file mode 100644 index 00000000000..685f826e695 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2y-if-decls-3.c @@ -0,0 +1,40 @@ +/* N3356 - if declarations. */ +/* PR c/117019 */ +/* { dg-do compile } */ +/* { dg-options "-std=c2y" } */ +/* Test C2Y if declarations. Invalid usages. */ + +void +g (int g) +{ + switch (;); /* { dg-error "expected" } */ + switch (int); /* { dg-error "expected identifier" } */ + /* { dg-error "declaration" "" { target *-*-* } .-1 } */ + switch (auto); /* { dg-error "expected identifier" } */ + /* { dg-error "declaration" "" { target *-*-* } .-1 } */ + switch (int;); /* { dg-error "declaration" } */ + /* { dg-warning "empty" "" { target *-*-* } .-1 } */ + switch (auto;); /* { dg-error "empty|initializer" } */ + switch (int i); /* { dg-error "initializer" } */ + switch (int i;); /* { dg-error "expected" } */ + switch (int i = 0;); /* { dg-error "expected" } */ + + switch (extern int i = 0); /* { dg-error "in condition|both .extern. and initializer" } */ + switch (register int i = 0); /* { dg-error "in condition" } */ + switch (static int i = 0); /* { dg-error "in condition" } */ + switch (thread_local int i = 0); /* { dg-error "in condition|function-scope" } */ + switch (typedef int i); /* { dg-error "in condition|initializer" } */ + switch (typedef int i = 0); /* { dg-error "in condition|initialized" } */ + + switch (int i = 2, j = 3); /* { dg-error "only declare a single object" } */ + + switch (void (*fp)(int)); /* { dg-error "initializer" } */ + switch ([[maybe_unused]] g); /* { dg-error "expected" } */ + switch ([[maybe_unused]] 42); /* { dg-error "expected" } */ + switch ([[maybe_unused]] int); /* { dg-error "expected|initializer" } */ + switch (__attribute__((unused)) g); /* { dg-error "initializer" } */ + switch (__attribute__((unused)) 42); /* { dg-error "expected|initializer" } */ + switch (__attribute__((unused)) int); /* { dg-error "expected|initializer" } */ + + switch (int arr[] = { 1 }); /* { dg-error "switch quantity not an integer" } */ +} diff --git a/gcc/testsuite/gcc.dg/c2y-if-decls-4.c b/gcc/testsuite/gcc.dg/c2y-if-decls-4.c new file mode 100644 index 00000000000..f518adf7dd1 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2y-if-decls-4.c @@ -0,0 +1,191 @@ +/* N3356 - if declarations. */ +/* PR c/117019 */ +/* { dg-do run } */ +/* { dg-options "-std=c2y -Wc23-c2y-compat" } */ +/* Test C2Y if declarations. Valid usages. */ + +int get () { return 42; } +int foo (int i) { return i; } + +enum E { X = 1, Y }; + +void +simple () +{ + switch (int i = get ()) /* { dg-warning "if declarations before C2Y" } */ + { + case 42: + foo (i); + break; + default: + __builtin_abort (); + } + + switch (int i = 0) /* { dg-warning "if declarations before C2Y" } */ + { + case 0: + foo (i); + break; + default: + __builtin_abort (); + } + + switch (auto i = get ()) /* { dg-warning "if declarations before C2Y" } */ + { + case 42: + foo (i); + break; + default: + __builtin_abort (); + } + + switch (__typeof__(get ()) i = get ()) /* { dg-warning "if declarations before C2Y" } */ + { + case 42: + foo (i); + break; + default: + __builtin_abort (); + } + + switch (auto i = 0) /* { dg-warning "if declarations before C2Y" } */ + { + case 0: + foo (i); + break; + default: + __builtin_abort (); + } + + switch ([[maybe_unused]] int i = get ()) /* { dg-warning "if declarations before C2Y" } */ + { + case 42: + foo (i); + break; + default: + __builtin_abort (); + } + + switch (__attribute__((unused)) int i = get ()) /* { dg-warning "if declarations before C2Y" } */ + { + case 42: + foo (i); + break; + default: + __builtin_abort (); + } + + switch (enum E e = X) /* { dg-warning "if declarations before C2Y" } */ + { + case X: + foo (X); + break; + default: + __builtin_abort (); + } + + switch (constexpr int i = 42) /* { dg-warning "if declarations before C2Y" } */ + { + case 42: + foo (i); + break; + default: + __builtin_abort (); + } + + double i; +} + +void +expr () +{ + switch (int i = get (); i) /* { dg-warning "if declarations before C2Y" } */ + { + case 42: + foo (i); + break; + default: + __builtin_abort (); + } + + switch (auto i = get (); i) /* { dg-warning "if declarations before C2Y" } */ + { + case 42: + foo (i); + break; + default: + __builtin_abort (); + } + + switch (__typeof__(get ()) i = get (); i) /* { dg-warning "if declarations before C2Y" } */ + { + case 42: + foo (i); + break; + default: + __builtin_abort (); + } + + switch (int (*f)(int) = foo; f (42)) /* { dg-warning "if declarations before C2Y" } */ + { + case 42: + foo (42); + break; + default: + __builtin_abort (); + } + + switch ([[maybe_unused]] int i = get (); i) /* { dg-warning "if declarations before C2Y" } */ + { + case 42: + foo (i); + break; + default: + __builtin_abort (); + } + + switch (__attribute__((unused)) int i = get (); i) /* { dg-warning "if declarations before C2Y" } */ + { + case 42: + foo (i); + break; + default: + __builtin_abort (); + } + + switch (enum E e = X; e) /* { dg-warning "if declarations before C2Y" } */ + { + case X: + foo (X); + break; + default: + __builtin_abort (); + } + + switch (constexpr int i = 42; i) /* { dg-warning "if declarations before C2Y" } */ + { + case 42: + foo (i); + break; + default: + __builtin_abort (); + } + + switch (int arr[] = { 1, 2, 3}; arr[0]) /* { dg-warning "if declarations before C2Y" } */ + { + case 1: + foo (arr[0]); + break; + default: + __builtin_abort (); + } + + double i; +} + +int +main () +{ + simple (); + expr (); +} diff --git a/gcc/testsuite/gcc.dg/c2y-if-decls-5.c b/gcc/testsuite/gcc.dg/c2y-if-decls-5.c new file mode 100644 index 00000000000..dfab357c312 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2y-if-decls-5.c @@ -0,0 +1,35 @@ +/* N3356 - if declarations. */ +/* PR c/117019 */ +/* { dg-do run } */ +/* { dg-options "-std=c2y" } */ + +int g; +int get () { ++g; return 42; } + +struct S { int i; }; + +int +main () +{ + if (auto x = get (); get (), x); + if (g != 2) + __builtin_abort (); + + switch (auto x = get (); get (), x); + if (g != 4) + __builtin_abort (); + + if (struct S s = { 42 }; s.i != 42) + __builtin_abort (); + + if (int i = 42) + { + i = 0; + if (int j = 42) + j = 0; + else + j = 42; + } + else + i = 42; +} diff --git a/gcc/testsuite/gcc.dg/c2y-if-decls-6.c b/gcc/testsuite/gcc.dg/c2y-if-decls-6.c new file mode 100644 index 00000000000..57dd9e01bde --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2y-if-decls-6.c @@ -0,0 +1,27 @@ +/* N3356 - if declarations. */ +/* PR c/117019 */ +/* { dg-do run } */ +/* { dg-options "-std=c2y -Wall -Wextra" } */ +/* Test VLAs. */ + +void foo (int) { } + +int +main () +{ + int i = 3; + + if (int arr[i] = { }; !arr[0]) + foo (arr[0]); + else + __builtin_abort (); + + switch (int arr[i] = { }; arr[0]) + { + case 0: + foo (arr[0]); + break; + default: + __builtin_abort (); + } +} diff --git a/gcc/testsuite/gcc.dg/c2y-if-decls-7.c b/gcc/testsuite/gcc.dg/c2y-if-decls-7.c new file mode 100644 index 00000000000..df451e3e779 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2y-if-decls-7.c @@ -0,0 +1,21 @@ +/* N3356 - if declarations. */ +/* PR c/117019 */ +/* { dg-do compile } */ +/* { dg-options "-std=c2y -Wall -Wextra" } */ +/* Test VLAs. Invalid code. */ + +void foo (int) { } + +void +g () +{ + int i = 3; + + switch (i) /* { dg-message "switch starts here" } */ + { /* { dg-warning "statement will never be executed" } */ + int arr[i] = { }; + default: /* { dg-error "switch jumps into scope" } */ + i = arr[0]; + break; + } +} diff --git a/gcc/testsuite/gcc.dg/gnu2y-if-decls-1.c b/gcc/testsuite/gcc.dg/gnu2y-if-decls-1.c new file mode 100644 index 00000000000..65f526e9dc2 --- /dev/null +++ b/gcc/testsuite/gcc.dg/gnu2y-if-decls-1.c @@ -0,0 +1,15 @@ +/* N3356 - if declarations. */ +/* PR c/117019 */ +/* { dg-do compile } */ +/* { dg-options "-std=gnu2y" } */ + +void +g () +{ + if (int i = 42); + if (int i = 42; i > 10); + if (int i, j; i = 42); + switch (int i = 42); + switch (int i = 42; i); + switch (int i, j; i = 42); +} diff --git a/gcc/testsuite/gcc.dg/gnu99-if-decls-1.c b/gcc/testsuite/gcc.dg/gnu99-if-decls-1.c new file mode 100644 index 00000000000..6d7a3bc196b --- /dev/null +++ b/gcc/testsuite/gcc.dg/gnu99-if-decls-1.c @@ -0,0 +1,15 @@ +/* N3356 - if declarations. */ +/* PR c/117019 */ +/* { dg-do compile } */ +/* { dg-options "-std=gnu99 -Wpedantic" } */ + +void +g () +{ + if (int i = 42); /* { dg-warning "ISO C does not support if declarations before C2Y" } */ + if (int i = 42; i > 10); /* { dg-warning "ISO C does not support if declarations before C2Y" } */ + if (int i, j; i = 42); /* { dg-warning "ISO C does not support if declarations before C2Y" } */ + switch (int i = 42); /* { dg-warning "ISO C does not support if declarations before C2Y" } */ + switch (int i = 42; i); /* { dg-warning "ISO C does not support if declarations before C2Y" } */ + switch (int i, j; i = 42); /* { dg-warning "ISO C does not support if declarations before C2Y" } */ +} diff --git a/gcc/testsuite/gcc.dg/gnu99-if-decls-2.c b/gcc/testsuite/gcc.dg/gnu99-if-decls-2.c new file mode 100644 index 00000000000..82f779c71c2 --- /dev/null +++ b/gcc/testsuite/gcc.dg/gnu99-if-decls-2.c @@ -0,0 +1,15 @@ +/* N3356 - if declarations. */ +/* PR c/117019 */ +/* { dg-do compile } */ +/* { dg-options "-std=gnu99" } */ + +void +g () +{ + if (int i = 42); + if (int i = 42; i > 10); + if (int i, j; i = 42); + switch (int i = 42); + switch (int i = 42; i); + switch (int i, j; i = 42); +}