https://gcc.gnu.org/g:440be01b07941506d1c8819448bd17c8717d55f5
commit r15-5053-g440be01b07941506d1c8819448bd17c8717d55f5 Author: Marek Polacek <pola...@redhat.com> Date: Thu Oct 31 09:28:15 2024 -0400 c: Implement C2y N3356, if declarations [PR117019] This patch implements C2y N3356, if declarations as described at <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3356.htm>. This feature is cognate with C++17 Selection statements with initializer <https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0305r1.html>, 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. 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/c2y-if-decls-8.c: New test. * gcc.dg/c2y-if-decls-9.c: New test. * gcc.dg/c2y-if-decls-10.c: New test. * gcc.dg/c2y-if-decls-11.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. Diff: --- gcc/c/c-parser.cc | 253 +++++++++++++++++++++++++------- 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 | 168 +++++++++++++++++++++ gcc/testsuite/gcc.dg/c2y-if-decls-10.c | 38 +++++ gcc/testsuite/gcc.dg/c2y-if-decls-11.c | 199 +++++++++++++++++++++++++ gcc/testsuite/gcc.dg/c2y-if-decls-2.c | 35 +++++ gcc/testsuite/gcc.dg/c2y-if-decls-3.c | 39 +++++ gcc/testsuite/gcc.dg/c2y-if-decls-4.c | 199 +++++++++++++++++++++++++ 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 | 96 ++++++++++++ gcc/testsuite/gcc.dg/c2y-if-decls-8.c | 168 +++++++++++++++++++++ gcc/testsuite/gcc.dg/c2y-if-decls-9.c | 35 +++++ 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 ++ 17 files changed, 1302 insertions(+), 56 deletions(-) diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc index 179c772fb76f..3ab8a49bf353 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<c_token> * = 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<c_token> *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,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, break; } } + if (c_parser_next_token_is (parser, CPP_SEMICOLON)) { bool handled_assume = false; @@ -2383,7 +2397,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 +2439,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 +2452,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 +2462,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 +2474,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 +2489,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 +2506,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 +2546,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 +2569,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 +2589,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 +2602,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, "%<auto%> 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 +2643,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 +2783,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 +2794,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 +2887,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 +2906,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 +2917,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 +2939,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 %<=%>, %<,%>, %<;%>, " - "%<asm%> 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 %<=%>, %<,%>, %<;%>, " + "%<asm%> or %<__attribute__%>"); + c_parser_skip_to_end_of_block_or_statement (parser); + } + return result; } /* Function definition (nested or otherwise). */ if (nested) @@ -2988,7 +3020,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 +3050,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 +3091,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 +7412,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 +7455,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 +8109,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 +8127,108 @@ 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; + } + if (expr.value) + { + expr.original_type = TREE_TYPE (expr.value); + expr = convert_lvalue_to_rvalue (loc, expr, /*convert_p=*/true, + /*read_p=*/true); + } + } + 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 +8381,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 +8405,7 @@ c_parser_if_statement (c_parser *parser, bool *if_p, vec<tree> *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 +8492,10 @@ 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 + if it parsed an expression, read_p was false. Make sure we mark + the expression as read. */ ce = convert_lvalue_to_rvalue (switch_cond_loc, ce, true, true); expr = ce.value; /* ??? expr has no valid location? */ @@ -8667,7 +8807,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 +8838,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 +14190,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 +21310,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 +23276,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 +25519,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 +25553,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 +25563,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 000000000000..ea968c67c6a0 --- /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 000000000000..d53db7153771 --- /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 000000000000..ab9b3f207003 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2y-if-decls-1.c @@ -0,0 +1,168 @@ +/* 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); + + if (register int i = 0); /* { dg-warning "if declarations before C2Y" } */ + if (static int i = 0); /* { dg-warning "if declarations before C2Y" } */ + if (static int arr[3] = {}); /* { dg-warning "if declarations before C2Y" } */ + if (_Atomic int i = 0); /* { dg-warning "if declarations before C2Y" } */ + + if (int arr[] = { 1 }) /* { dg-warning "if declarations before C2Y" } */ + foo (arr[0]); + else + __builtin_abort (); + + 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 (); + + if (register int i = 0; i); /* { dg-warning "if declarations before C2Y" } */ + if (static int i = 0; i); /* { dg-warning "if declarations before C2Y" } */ + if (_Atomic int i = 0; i); /* { dg-warning "if declarations before C2Y" } */ + + double i; +} + +int +main () +{ + simple (); + expr (); +} diff --git a/gcc/testsuite/gcc.dg/c2y-if-decls-10.c b/gcc/testsuite/gcc.dg/c2y-if-decls-10.c new file mode 100644 index 000000000000..019c81b453df --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2y-if-decls-10.c @@ -0,0 +1,38 @@ +/* N3356 - if declarations. */ +/* PR c/117019 */ +/* { dg-do compile } */ +/* { dg-options "-std=c2y -pedantic-errors" } */ +/* 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" } */ + 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 "both .extern. and initializer" } */ + switch (extern int i); /* { dg-error "initializer" } */ + switch (thread_local int i = 0); /* { dg-error "function-scope" } */ + switch (typedef int i); /* { dg-error "initializer" } */ + switch (typedef int i = 0); /* { dg-error "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-11.c b/gcc/testsuite/gcc.dg/c2y-if-decls-11.c new file mode 100644 index 000000000000..5ac962507c9e --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2y-if-decls-11.c @@ -0,0 +1,199 @@ +/* N3356 - if declarations. */ +/* PR c/117019 */ +/* { dg-do run } */ +/* { dg-options "-std=c2y -pedantic-errors" } */ +/* 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 ()) + { + case 42: + foo (i); + break; + default: + __builtin_abort (); + } + + switch (int i = 0) + { + case 0: + foo (i); + break; + default: + __builtin_abort (); + } + + switch (auto i = get ()) + { + case 42: + foo (i); + break; + default: + __builtin_abort (); + } + + switch (__typeof__(get ()) i = get ()) + { + case 42: + foo (i); + break; + default: + __builtin_abort (); + } + + switch (auto i = 0) + { + case 0: + foo (i); + break; + default: + __builtin_abort (); + } + + switch ([[maybe_unused]] int i = get ()) + { + case 42: + foo (i); + break; + default: + __builtin_abort (); + } + + switch (__attribute__((unused)) int i = get ()) + { + case 42: + foo (i); + break; + default: + __builtin_abort (); + } + + switch (enum E e = X) + { + case X: + foo (X); + break; + default: + __builtin_abort (); + } + + switch (constexpr int i = 42) + { + case 42: + foo (i); + break; + default: + __builtin_abort (); + } + + switch (register int i = 0); + switch (static int i = 0); + switch (_Atomic int i = 0); + + double i; +} + +void +expr () +{ + switch (int i = get (); i) + { + case 42: + foo (i); + break; + default: + __builtin_abort (); + } + + switch (auto i = get (); i) + { + case 42: + foo (i); + break; + default: + __builtin_abort (); + } + + switch (__typeof__(get ()) i = get (); i) + { + case 42: + foo (i); + break; + default: + __builtin_abort (); + } + + switch (int (*f)(int) = foo; f (42)) + { + case 42: + foo (42); + break; + default: + __builtin_abort (); + } + + switch ([[maybe_unused]] int i = get (); i) + { + case 42: + foo (i); + break; + default: + __builtin_abort (); + } + + switch (__attribute__((unused)) int i = get (); i) + { + case 42: + foo (i); + break; + default: + __builtin_abort (); + } + + switch (enum E e = X; e) + { + case X: + foo (X); + break; + default: + __builtin_abort (); + } + + switch (constexpr int i = 42; i) + { + case 42: + foo (i); + break; + default: + __builtin_abort (); + } + + switch (int arr[] = { 1, 2, 3}; arr[0]) + { + case 1: + foo (arr[0]); + break; + default: + __builtin_abort (); + } + + switch (register int i = 0; i); + switch (static int i = 0; i); + switch (_Atomic int i = 0; i); + + 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 000000000000..146f5415d610 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2y-if-decls-2.c @@ -0,0 +1,35 @@ +/* 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 "both .extern. and initializer" } */ + if (extern int i); /* { dg-error "initializer" } */ + if (thread_local int i = 0); /* { dg-error "function-scope" } */ + if (typedef int i); /* { dg-error "initializer" } */ + if (typedef int i = 0); /* { dg-error "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" } */ +} 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 000000000000..69926d1c6344 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2y-if-decls-3.c @@ -0,0 +1,39 @@ +/* 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 "both .extern. and initializer" } */ + switch (extern int i); /* { dg-error "initializer" } */ + switch (thread_local int i = 0); /* { dg-error "function-scope" } */ + switch (typedef int i); /* { dg-error "initializer" } */ + switch (typedef int i = 0); /* { dg-error "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 000000000000..6df4bb09a9e2 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2y-if-decls-4.c @@ -0,0 +1,199 @@ +/* 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 (); + } + + switch (register int i = 0); /* { dg-warning "if declarations before C2Y" } */ + switch (static int i = 0); /* { dg-warning "if declarations before C2Y" } */ + switch (_Atomic int i = 0); /* { dg-warning "if declarations before C2Y" } */ + + 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 (); + } + + switch (register int i = 0; i); /* { dg-warning "if declarations before C2Y" } */ + switch (static int i = 0; i); /* { dg-warning "if declarations before C2Y" } */ + switch (_Atomic int i = 0; i); /* { dg-warning "if declarations before C2Y" } */ + + 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 000000000000..dfab357c3125 --- /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 000000000000..57dd9e01bde0 --- /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 000000000000..58c1d856ce2f --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2y-if-decls-7.c @@ -0,0 +1,96 @@ +/* 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; + } +} + +void +g2 (int i) +{ + goto L1; /* { dg-error "jump into scope" } */ + if (int arr[i] = { }; arr[0]) + { +L1: + } + + goto L2; /* { dg-error "jump into scope" } */ + if (int arr[i] = { }) /* { dg-warning "will always evaluate as .true." } */ + { +L2: + arr[0] = 42; + } + + goto L3; /* { dg-error "jump into scope" } */ + switch (int arr[i] = { }; arr[0]) + { + case 0: + L3: + return; + } +} + +void +g3 (int i, int n) +{ + switch (i) + { + case 0: + if (int arr[n] = { }) /* { dg-warning "will always evaluate as .true." } */ + { + case 3: /* { dg-error "switch jumps into scope" } */ + arr[0] = 42; + } + break; + default: + return; + } +} + +void +g4 (int i, int n) +{ + switch (i) + { + case 0: + if (int arr[n] = { }; arr[0]) + { + case 3: /* { dg-error "switch jumps into scope" } */ + } + break; + default: + return; + } +} + +void +g5 (int i, int n) +{ + switch (i) + { + case 0: + goto L; /* { dg-error "jump into scope" } */ + switch (int arr[n] = { }; arr[0]) + { + L: + } + break; + default: + return; + } +} diff --git a/gcc/testsuite/gcc.dg/c2y-if-decls-8.c b/gcc/testsuite/gcc.dg/c2y-if-decls-8.c new file mode 100644 index 000000000000..bd3c5cc4403c --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2y-if-decls-8.c @@ -0,0 +1,168 @@ +/* N3356 - if declarations. */ +/* PR c/117019 */ +/* { dg-do run } */ +/* { dg-options "-std=c2y -pedantic-errors" } */ +/* 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 ()) + foo (i); + else + __builtin_abort (); + + if (int i = 0) + __builtin_abort (); + else + foo (i); + + if (auto i = get ()) + foo (i); + else + __builtin_abort (); + + if (__typeof__(get ()) i = get ()) + foo (i); + else + __builtin_abort (); + + if (auto i = 0) + __builtin_abort (); + else + foo (i); + + if (int (*f)(int) = foo) + f (1); + else + __builtin_abort (); + + if ([[maybe_unused]] int i = get ()) + foo (i); + else + __builtin_abort (); + + if (__attribute__((unused)) int i = get ()) + foo (i); + else + __builtin_abort (); + + if (enum E e = X) + foo (e); + else + __builtin_abort (); + + if (constexpr int i = 42) + foo (i); + else + __builtin_abort (); + + if (int i = 1) + if (int j = 2) + if (int k = 3) + foo (i + j + k); + + if (register int i = 0); + if (static int i = 0); + if (static int arr[3] = {}); + if (_Atomic int i = 0); + + if (int arr[] = { 1 }) + foo (arr[0]); + else + __builtin_abort (); + + double i; +} + +void +expr () +{ + if (int i = get (); i == 42) + foo (i); + else + __builtin_abort (); + + if (int i = get (); i != 42) + __builtin_abort (); + else + foo (i); + + if (auto i = get (); i == 42) + foo (i); + else + __builtin_abort (); + + if (__typeof__(get ()) i = get (); i == 42) + foo (i); + else + __builtin_abort (); + + if (auto i = get (); i != 42) + __builtin_abort (); + else + foo (i); + + if (int (*f)(int) = foo; f (42)) + f (1); + else + __builtin_abort (); + + if ([[maybe_unused]] int i = get (); i == 42) + foo (i); + else + __builtin_abort (); + + if (__attribute__((unused)) int i = get (); i == 42) + foo (i); + else + __builtin_abort (); + + if (enum E e = X; e == X) + foo (e); + else + __builtin_abort (); + + if (constexpr int i = 42; i == 42) + foo (i); + else + __builtin_abort (); + + if (int i = 1; i) + if (int j = 2; j) + if (int k = 3; k) + foo (i + j + k); + + if (int i = 2, j = get (); i + j > 0) + foo (i + j); + else + __builtin_abort (); + + if (int i; i = 1) + foo (i); + else + __builtin_abort (); + + if (int arr[] = { 1, 2, 3}; arr[0]) + foo (arr[0]); + else + __builtin_abort (); + + if (register int i = 0; i); + if (static int i = 0; i); + if (_Atomic int i = 0; i); + + double i; +} + +int +main () +{ + simple (); + expr (); +} diff --git a/gcc/testsuite/gcc.dg/c2y-if-decls-9.c b/gcc/testsuite/gcc.dg/c2y-if-decls-9.c new file mode 100644 index 000000000000..ee9beef9fd69 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2y-if-decls-9.c @@ -0,0 +1,35 @@ +/* N3356 - if declarations. */ +/* PR c/117019 */ +/* { dg-do compile } */ +/* { dg-options "-std=c2y -pedantic-errors" } */ +/* 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-error "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 "both .extern. and initializer" } */ + if (extern int i); /* { dg-error "initializer" } */ + if (thread_local int i = 0); /* { dg-error "function-scope" } */ + if (typedef int i); /* { dg-error "initializer" } */ + if (typedef int i = 0); /* { dg-error "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" } */ +} 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 000000000000..65f526e9dc2f --- /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 000000000000..6d7a3bc196b4 --- /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 000000000000..82f779c71c2a --- /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); +}