+ Joseph

On Mon, Nov 04, 2024 at 06:26:47PM -0500, Marek Polacek wrote:
> Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?
> 
> -- >8 --
> 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.  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
> 
> 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<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,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,
>                       "%<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 +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 %<=%>, %<,%>, %<;%>, "
> -                       "%<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 +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<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 +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);
> +}
> 
> base-commit: fe97ac43e05a8da8a12fbad2208a1ebb19d2d6c9
> -- 
> 2.47.0
> 

Marek

Reply via email to