From 14cfa01755a66afbae2539f8b5796c960ddcecc6 Mon Sep 17 00:00:00 2001 From: Joseph Myers Date: Thu, 25 Aug 2022 21:02:57 +0000 Subject: c: Support C2x empty initializer braces ISO C2x standardizes empty initializer braces {}. Implement this feature accordingly. The basic case was already supported and so just needed diagnostic adjustments. However, the standard feature also includes two cases that were not previously supported: empty initializer braces for scalars, and empty initializer braces for VLAs. Thus, add support for those features as well, updating existing tests that expected them to be diagnosed. There was already some gimplifier support for converting variable-sized initializations with empty CONSTRUCTORs to memset. However, it didn't apply here; code earlier in gimplify_modify_expr ended up calling gimplify_init_constructor via gimplify_modify_expr_rhs, which ended up handling the CONSTRUCTOR in a way that generated an ICE later. Add a check for this case earlier in gimplify_modify_expr to avoid that issue. Bootstrapped with no regressions for x86_64-pc-linux-gnu. gcc/ * gimplify.cc (gimplify_modify_expr): Convert initialization from a variable-size CONSTRUCTOR to memset before call to gimplify_modify_expr_rhs. gcc/c/ * c-decl.cc (start_decl): Do not diagnose initialization of variable-sized objects here. * c-parser.cc (c_parser_braced_init): Add argument DECL. All callers changed. (c_parser_initializer): Diagnose initialization of variable-sized objects other than with braced initializer. (c_parser_braced_init): Use pedwarn_c11 for empty initializer braces and update diagnostic text. Diagnose initialization of variable-sized objects with nonempty braces. * c-typeck.cc (digest_init): Update diagnostic for initialization of variable-sized objects. (really_start_incremental_init, set_designator) (process_init_element): Update comments. (pop_init_level): Allow scalar empty initializers. gcc/testsuite/ * gcc.dg/c11-empty-init-1.c, gcc.dg/c11-empty-init-2.c, gcc.dg/c11-empty-init-3.c, gcc.dg/c2x-empty-init-1.c, gcc.dg/c2x-empty-init-2.c, gcc.dg/c2x-empty-init-3.c, gcc.dg/gnu2x-empty-init-1.c, gcc.dg/gnu2x-empty-init-2.c: New tests. * gcc.dg/torture/dfp-default-init-1.c: Also test empty initializers. * gcc.dg/init-bad-1.c, gcc.dg/noncompile/pr71583.c, gcc.dg/pr61096-1.c, gcc.dg/vla-init-2.c, gcc.dg/vla-init-3.c, gcc.target/i386/sse2-bfloat16-scalar-typecheck.c: Update expected diagnostics. * gcc.dg/ubsan/c-shift-1.c: Use nonempty initializers for VLA initializations expected to be diagnosed. --- gcc/c/c-decl.cc | 20 +++----------------- gcc/c/c-parser.cc | 24 +++++++++++++++++------- gcc/c/c-typeck.cc | 23 ++++++++++++++--------- 3 files changed, 34 insertions(+), 33 deletions(-) (limited to 'gcc/c') diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc index 9e590c6..1fe31e0 100644 --- a/gcc/c/c-decl.cc +++ b/gcc/c/c-decl.cc @@ -5180,29 +5180,15 @@ start_decl (struct c_declarator *declarator, struct c_declspecs *declspecs, initialized = false; else if (COMPLETE_TYPE_P (TREE_TYPE (decl))) { - /* A complete type is ok if size is fixed. */ - - if (!poly_int_tree_p (TYPE_SIZE (TREE_TYPE (decl))) - || C_DECL_VARIABLE_SIZE (decl)) - { - error ("variable-sized object may not be initialized"); - initialized = false; - } + /* A complete type is ok if size is fixed. If the size is + variable, an empty initializer is OK and nonempty + initializers will be diagnosed in the parser. */ } else if (TREE_CODE (TREE_TYPE (decl)) != ARRAY_TYPE) { error ("variable %qD has initializer but incomplete type", decl); initialized = false; } - else if (C_DECL_VARIABLE_SIZE (decl)) - { - /* Although C99 is unclear about whether incomplete arrays - of VLAs themselves count as VLAs, it does not make - sense to permit them to be initialized given that - ordinary VLAs may not be initialized. */ - error ("variable-sized object may not be initialized"); - initialized = false; - } } if (initialized) diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc index 759f200..1e8d9dc 100644 --- a/gcc/c/c-parser.cc +++ b/gcc/c/c-parser.cc @@ -1523,7 +1523,7 @@ static tree c_parser_simple_asm_expr (c_parser *); static tree c_parser_gnu_attributes (c_parser *); static struct c_expr c_parser_initializer (c_parser *, tree); static struct c_expr c_parser_braced_init (c_parser *, tree, bool, - struct obstack *); + struct obstack *, tree); static void c_parser_initelt (c_parser *, struct obstack *); static void c_parser_initval (c_parser *, struct c_expr *, struct obstack *); @@ -5220,11 +5220,15 @@ static struct c_expr c_parser_initializer (c_parser *parser, tree decl) { if (c_parser_next_token_is (parser, CPP_OPEN_BRACE)) - return c_parser_braced_init (parser, NULL_TREE, false, NULL); + return c_parser_braced_init (parser, NULL_TREE, false, NULL, decl); else { struct c_expr ret; location_t loc = c_parser_peek_token (parser)->location; + if (decl != error_mark_node && C_DECL_VARIABLE_SIZE (decl)) + error_at (loc, + "variable-sized object may not be initialized except " + "with an empty initializer"); ret = c_parser_expr_no_commas (parser, NULL); /* This is handled mostly by gimplify.cc, but we have to deal with not warning about int x = x; as it is a GCC extension to turn off @@ -5251,11 +5255,12 @@ location_t last_init_list_comma; compound literal, and NULL_TREE for other initializers and for nested braced lists. NESTED_P is true for nested braced lists, false for the list of a compound literal or the list that is the - top-level initializer in a declaration. */ + top-level initializer in a declaration. DECL is the declaration for + the top-level initializer for a declaration, otherwise NULL_TREE. */ static struct c_expr c_parser_braced_init (c_parser *parser, tree type, bool nested_p, - struct obstack *outer_obstack) + struct obstack *outer_obstack, tree decl) { struct c_expr ret; struct obstack braced_init_obstack; @@ -5273,10 +5278,15 @@ c_parser_braced_init (c_parser *parser, tree type, bool nested_p, really_start_incremental_init (type); if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) { - pedwarn (brace_loc, OPT_Wpedantic, "ISO C forbids empty initializer braces"); + pedwarn_c11 (brace_loc, OPT_Wpedantic, + "ISO C forbids empty initializer braces before C2X"); } else { + if (decl && decl != error_mark_node && C_DECL_VARIABLE_SIZE (decl)) + error_at (brace_loc, + "variable-sized object may not be initialized except " + "with an empty initializer"); /* Parse a non-empty initializer list, possibly with a trailing comma. */ while (true) @@ -5532,7 +5542,7 @@ c_parser_initval (c_parser *parser, struct c_expr *after, if (c_parser_next_token_is (parser, CPP_OPEN_BRACE) && !after) init = c_parser_braced_init (parser, NULL_TREE, true, - braced_init_obstack); + braced_init_obstack, NULL_TREE); else { init = c_parser_expr_no_commas (parser, after); @@ -10307,7 +10317,7 @@ c_parser_postfix_expression_after_paren_type (c_parser *parser, error_at (type_loc, "compound literal has variable size"); type = error_mark_node; } - init = c_parser_braced_init (parser, type, false, NULL); + init = c_parser_braced_init (parser, type, false, NULL, NULL_TREE); finish_init (); maybe_warn_string_init (type_loc, type, init); diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc index de8780a..0e37ab8 100644 --- a/gcc/c/c-typeck.cc +++ b/gcc/c/c-typeck.cc @@ -8291,7 +8291,9 @@ digest_init (location_t init_loc, tree type, tree init, tree origtype, if (COMPLETE_TYPE_P (type) && TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST) { - error_init (init_loc, "variable-sized object may not be initialized"); + error_init (init_loc, + "variable-sized object may not be initialized except " + "with an empty initializer"); return error_mark_node; } @@ -8641,8 +8643,9 @@ really_start_incremental_init (tree type) constructor_max_index = integer_minus_one_node; /* constructor_max_index needs to be an INTEGER_CST. Attempts - to initialize VLAs will cause a proper error; avoid tree - checking errors as well by setting a safe value. */ + to initialize VLAs with a nonempty initializer will cause a + proper error; avoid tree checking errors as well by setting a + safe value. */ if (constructor_max_index && TREE_CODE (constructor_max_index) != INTEGER_CST) constructor_max_index = integer_minus_one_node; @@ -9024,12 +9027,14 @@ pop_init_level (location_t loc, int implicit, && !gnu_vector_type_p (constructor_type)) { /* A nonincremental scalar initializer--just return - the element, after verifying there is just one. */ + the element, after verifying there is just one. + Empty scalar initializers are supported in C2X. */ if (vec_safe_is_empty (constructor_elements)) { - if (!constructor_erroneous && constructor_type != error_mark_node) - error_init (loc, "empty scalar initializer"); - ret.value = error_mark_node; + if (constructor_erroneous || constructor_type == error_mark_node) + ret.value = error_mark_node; + else + ret.value = build_zero_cst (constructor_type); } else if (vec_safe_length (constructor_elements) != 1) { @@ -9114,7 +9119,7 @@ set_designator (location_t loc, bool array, return true; /* Likewise for an initializer for a variable-size type. Those are - diagnosed in digest_init. */ + diagnosed in the parser, except for empty initializer braces. */ if (COMPLETE_TYPE_P (constructor_type) && TREE_CODE (TYPE_SIZE (constructor_type)) != INTEGER_CST) return true; @@ -10275,7 +10280,7 @@ process_init_element (location_t loc, struct c_expr value, bool implicit, return; /* Ignore elements of an initializer for a variable-size type. - Those are diagnosed in digest_init. */ + Those are diagnosed in the parser (empty initializer braces are OK). */ if (COMPLETE_TYPE_P (constructor_type) && !poly_int_tree_p (TYPE_SIZE (constructor_type))) return; -- cgit v1.1