From: Jakub Jelinek Date: Fri, 29 Sep 2017 17:53:50 +0000 (+0200) Subject: P0683R1 - default member initializers for bit-fields X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=603be0224edf653c1e38229e1d32ed449ffd23bd;p=gcc.git P0683R1 - default member initializers for bit-fields P0683R1 - default member initializers for bit-fields cp/ * cp-tree.h (grokbitfield): Add INIT parameter. * parser.c (cp_parser_constant_expression): Add STRICT_P argument, if true, parse a conditional-expression rather than assignment-expression. (cp_parser_member_declaration): For C++11 and later pass true as STRICT_P to cp_parser_constant_expression. Parse C++2A bitfield NSDMIs. Adjust grokbitfield caller. Handle DECL_INITIAL also for DECL_C_BIT_FIELDs. (cp_parser_objc_class_ivars): Adjust grokbitfield caller. * class.c (check_field_decl): Recurse even for DECL_C_BIT_FIELDs. (check_field_decls): Call check_field_decl even for DECL_C_BIT_FIELDs. * decl2.c (grokbitfield): Add INIT parameter, pass it to cp_finish_decl. * pt.c (tsubst_decl): Handle DECL_INITIAL for all FIELD_DECLs, not just non-bitfields. testsuite/ * g++.dg/ext/bitfield6.C: New test. * g++.dg/cpp2a/bitfield1.C: New test. * g++.dg/cpp2a/bitfield2.C: New test. * g++.dg/cpp2a/bitfield3.C: New test. From-SVN: r253302 --- diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index fe73935eea2..a9ee9a5eacf 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,22 @@ 2017-09-29 Jakub Jelinek + P0683R1 - default member initializers for bit-fields + * cp-tree.h (grokbitfield): Add INIT parameter. + * parser.c (cp_parser_constant_expression): Add STRICT_P argument, + if true, parse a conditional-expression rather than + assignment-expression. + (cp_parser_member_declaration): For C++11 and later pass true + as STRICT_P to cp_parser_constant_expression. Parse C++2A bitfield + NSDMIs. Adjust grokbitfield caller. Handle DECL_INITIAL also for + DECL_C_BIT_FIELDs. + (cp_parser_objc_class_ivars): Adjust grokbitfield caller. + * class.c (check_field_decl): Recurse even for DECL_C_BIT_FIELDs. + (check_field_decls): Call check_field_decl even for DECL_C_BIT_FIELDs. + * decl2.c (grokbitfield): Add INIT parameter, pass it to + cp_finish_decl. + * pt.c (tsubst_decl): Handle DECL_INITIAL for all FIELD_DECLs, not + just non-bitfields. + * class.c (check_bitfield_decl): Retrieve and clear width from DECL_BIT_FIELD_REPRESENTATIVE rather than DECL_INITIAL. (check_field_decls): Test DECL_BIT_FIELD_REPRESENTATIVE rather than diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 687ddaa5c8f..0c4a7b3db04 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -3324,7 +3324,7 @@ check_field_decl (tree field, { for (tree fields = TYPE_FIELDS (type); fields; fields = DECL_CHAIN (fields)) - if (TREE_CODE (fields) == FIELD_DECL && !DECL_C_BIT_FIELD (field)) + if (TREE_CODE (fields) == FIELD_DECL) any_default_members |= check_field_decl (fields, t, cant_have_const_ctor, no_const_asn_ref); @@ -3636,10 +3636,10 @@ check_field_decls (tree t, tree *access_decls, /* We set DECL_C_BIT_FIELD in grokbitfield. If the type and width are valid, we'll also set DECL_BIT_FIELD. */ - if ((! DECL_C_BIT_FIELD (x) || ! check_bitfield_decl (x)) - && check_field_decl (x, t, - cant_have_const_ctor_p, - no_const_asn_ref_p)) + if (DECL_C_BIT_FIELD (x)) + check_bitfield_decl (x); + + if (check_field_decl (x, t, cant_have_const_ctor_p, no_const_asn_ref_p)) { if (any_default_members && TREE_CODE (t) == UNION_TYPE) diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index f56c9517967..a21c9485393 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -6159,7 +6159,7 @@ extern void check_member_template (tree); extern tree grokfield (const cp_declarator *, cp_decl_specifier_seq *, tree, bool, tree, tree); extern tree grokbitfield (const cp_declarator *, cp_decl_specifier_seq *, - tree, tree); + tree, tree, tree); extern bool any_dependent_type_attributes_p (tree); extern tree cp_reconstruct_complex_type (tree, tree); extern bool attributes_naming_typedef_ok (tree); diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 107ce7bc882..eb9c6a59e04 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -974,14 +974,16 @@ grokfield (const cp_declarator *declarator, } /* Like `grokfield', but for bitfields. - WIDTH is non-NULL for bit fields only, and is an INTEGER_CST node. */ + WIDTH is the width of the bitfield, a constant expression. + The other parameters are as for grokfield. */ tree grokbitfield (const cp_declarator *declarator, - cp_decl_specifier_seq *declspecs, tree width, + cp_decl_specifier_seq *declspecs, tree width, tree init, tree attrlist) { - tree value = grokdeclarator (declarator, declspecs, BITFIELD, 0, &attrlist); + tree value = grokdeclarator (declarator, declspecs, BITFIELD, + init != NULL_TREE, &attrlist); if (value == error_mark_node) return NULL_TREE; /* friends went bad. */ @@ -1036,7 +1038,11 @@ grokbitfield (const cp_declarator *declarator, error ("static member %qD cannot be a bit-field", value); return NULL_TREE; } - cp_finish_decl (value, NULL_TREE, false, NULL_TREE, 0); + + int flags = LOOKUP_IMPLICIT; + if (init && DIRECT_LIST_INIT_P (init)) + flags = LOOKUP_NORMAL; + cp_finish_decl (value, init, false, NULL_TREE, flags); if (width != error_mark_node) { diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 71c27a40ce2..6e817cb9fd5 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -2089,7 +2089,7 @@ static enum tree_code cp_parser_assignment_operator_opt static cp_expr cp_parser_expression (cp_parser *, cp_id_kind * = NULL, bool = false, bool = false); static cp_expr cp_parser_constant_expression - (cp_parser *, bool = false, bool * = NULL); + (cp_parser *, bool = false, bool * = NULL, bool = false); static cp_expr cp_parser_builtin_offsetof (cp_parser *); static cp_expr cp_parser_lambda_expression @@ -9626,12 +9626,15 @@ cp_parser_expression (cp_parser* parser, cp_id_kind * pidk, If ALLOW_NON_CONSTANT_P a non-constant expression is silently accepted. If ALLOW_NON_CONSTANT_P is true and the expression is not constant, *NON_CONSTANT_P is set to TRUE. If ALLOW_NON_CONSTANT_P - is false, NON_CONSTANT_P should be NULL. */ + is false, NON_CONSTANT_P should be NULL. If STRICT_P is true, + only parse a conditional-expression, otherwise parse an + assignment-expression. See below for rationale. */ static cp_expr cp_parser_constant_expression (cp_parser* parser, bool allow_non_constant_p, - bool *non_constant_p) + bool *non_constant_p, + bool strict_p) { bool saved_integral_constant_expression_p; bool saved_allow_non_integral_constant_expression_p; @@ -9665,16 +9668,27 @@ cp_parser_constant_expression (cp_parser* parser, parser->allow_non_integral_constant_expression_p = (allow_non_constant_p || cxx_dialect >= cxx11); parser->non_integral_constant_expression_p = false; - /* Although the grammar says "conditional-expression", we parse an - "assignment-expression", which also permits "throw-expression" - and the use of assignment operators. In the case that - ALLOW_NON_CONSTANT_P is false, we get better errors than we would + /* Although the grammar says "conditional-expression", when not STRICT_P, + we parse an "assignment-expression", which also permits + "throw-expression" and the use of assignment operators. In the case + that ALLOW_NON_CONSTANT_P is false, we get better errors than we would otherwise. In the case that ALLOW_NON_CONSTANT_P is true, it is actually essential that we look for an assignment-expression. For example, cp_parser_initializer_clauses uses this function to determine whether a particular assignment-expression is in fact constant. */ - expression = cp_parser_assignment_expression (parser); + if (strict_p) + { + /* Parse the binary expressions (logical-or-expression). */ + expression = cp_parser_binary_expression (parser, false, false, false, + PREC_NOT_OPERATOR, NULL); + /* If the next token is a `?' then we're actually looking at + a conditional-expression; otherwise we're done. */ + if (cp_lexer_next_token_is (parser->lexer, CPP_QUERY)) + expression = cp_parser_question_colon_clause (parser, expression); + } + else + expression = cp_parser_assignment_expression (parser); /* Restore the old settings. */ parser->integral_constant_expression_p = saved_integral_constant_expression_p; @@ -23445,6 +23459,7 @@ cp_parser_member_declaration (cp_parser* parser) { tree attributes = NULL_TREE; tree first_attribute; + tree initializer; bool is_bitfld = false; bool named_bitfld = false; @@ -23492,18 +23507,48 @@ cp_parser_member_declaration (cp_parser* parser) cp_lexer_consume_token (parser->lexer); /* Get the width of the bitfield. */ - width = cp_parser_constant_expression (parser); - - /* Look for attributes that apply to the bitfield after - the `:' token and width. This is where GCC used to - parse attributes in the past, pedwarn if there is - a std attribute. */ - if (cp_next_tokens_can_be_std_attribute_p (parser)) - pedwarn (input_location, OPT_Wpedantic, - "ISO C++ allows bit-field attributes only before " - "the %<:%> token"); - - late_attributes = cp_parser_attributes_opt (parser); + width = cp_parser_constant_expression (parser, false, NULL, + cxx_dialect >= cxx11); + + /* In C++2A and as extension for C++11 and above we allow + default member initializers for bit-fields. */ + initializer = NULL_TREE; + if (cxx_dialect >= cxx11 + && (cp_lexer_next_token_is (parser->lexer, CPP_EQ) + || cp_lexer_next_token_is (parser->lexer, + CPP_OPEN_BRACE))) + { + location_t loc + = cp_lexer_peek_token (parser->lexer)->location; + if (cxx_dialect < cxx2a + && !in_system_header_at (loc) + && identifier != NULL_TREE) + pedwarn (loc, 0, + "default member initializers for bit-fields " + "only available with -std=c++2a or " + "-std=gnu++2a"); + + initializer = cp_parser_save_nsdmi (parser); + if (identifier == NULL_TREE) + { + error_at (loc, "default member initializer for " + "unnamed bit-field"); + initializer = NULL_TREE; + } + } + else + { + /* Look for attributes that apply to the bitfield after + the `:' token and width. This is where GCC used to + parse attributes in the past, pedwarn if there is + a std attribute. */ + if (cp_next_tokens_can_be_std_attribute_p (parser)) + pedwarn (input_location, OPT_Wpedantic, + "ISO C++ allows bit-field attributes only " + "before the %<:%> token"); + + late_attributes = cp_parser_attributes_opt (parser); + } attributes = chainon (attributes, late_attributes); @@ -23520,13 +23565,12 @@ cp_parser_member_declaration (cp_parser* parser) sfk_none) : NULL, &decl_specifiers, - width, + width, initializer, attributes); } else { cp_declarator *declarator; - tree initializer; tree asm_specification; int ctor_dtor_or_conv_p; @@ -23745,7 +23789,6 @@ cp_parser_member_declaration (cp_parser* parser) if (TREE_CODE (decl) == FUNCTION_DECL) cp_parser_save_default_args (parser, decl); else if (TREE_CODE (decl) == FIELD_DECL - && !DECL_C_BIT_FIELD (decl) && DECL_INITIAL (decl)) /* Add DECL to the queue of NSDMI to be parsed later. */ vec_safe_push (unparsed_nsdmis, decl); @@ -30086,10 +30129,9 @@ cp_parser_objc_class_ivars (cp_parser* parser) attributes = chainon (prefix_attributes, attributes); if (width) - /* Create the bitfield declaration. */ - decl = grokbitfield (declarator, &declspecs, - width, - attributes); + /* Create the bitfield declaration. */ + decl = grokbitfield (declarator, &declspecs, + width, NULL_TREE, attributes); else decl = grokfield (declarator, &declspecs, NULL_TREE, /*init_const_expr_p=*/false, diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 70cfc9aac8a..c29c779a147 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -12841,7 +12841,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) = tsubst_expr (DECL_BIT_FIELD_REPRESENTATIVE (t), args, complain, in_decl, /*integral_constant_expression_p=*/true); - else if (DECL_INITIAL (t)) + if (DECL_INITIAL (t)) { /* Set up DECL_TEMPLATE_INFO so that we can get at the NSDMI in perform_member_init. Still set DECL_INITIAL diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index ac88fd3edf7..94cedb73717 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,11 @@ +2017-09-29 Jakub Jelinek + + P0683R1 - default member initializers for bit-fields + * g++.dg/ext/bitfield6.C: New test. + * g++.dg/cpp2a/bitfield1.C: New test. + * g++.dg/cpp2a/bitfield2.C: New test. + * g++.dg/cpp2a/bitfield3.C: New test. + 2017-09-29 Vladimir Makarov PR target/81481 diff --git a/gcc/testsuite/g++.dg/cpp2a/bitfield1.C b/gcc/testsuite/g++.dg/cpp2a/bitfield1.C new file mode 100644 index 00000000000..497b529854b --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/bitfield1.C @@ -0,0 +1,77 @@ +// P0683R1 +// { dg-do run { target c++11 } } +// { dg-options "" } + +extern "C" void abort (); +int a; +const int b = 0; +struct S { + int c : 5 = 1; // { dg-warning "default member initializers for bit-fields only available with" "" { target c++17_down } } + int d : 6 { 2 }; // { dg-warning "default member initializers for bit-fields only available with" "" { target c++17_down } } + int e : true ? 7 : a = 3; + int f : (true ? 8 : b) = 4; // { dg-warning "default member initializers for bit-fields only available with" "" { target c++17_down } } + int g : (true ? 9 : b) { 5 }; // { dg-warning "default member initializers for bit-fields only available with" "" { target c++17_down } } + int h : 1 || new int { 0 }; +}; +#if __cplusplus >= 201402L +static_assert (S{}.c == 1); +static_assert (S{}.d == 2); +static_assert (S{}.e == 0); +static_assert (S{}.f == 4); +static_assert (S{}.g == 5); +static_assert (S{}.h == 0); +#endif +template +struct U { + int j : W = 7; // { dg-warning "default member initializers for bit-fields only available with" "" { target c++17_down } } + int k : W { 8 }; // { dg-warning "default member initializers for bit-fields only available with" "" { target c++17_down } } + int l : V ? 7 : a = 3; + int m : (V ? W : b) = 9; // { dg-warning "default member initializers for bit-fields only available with" "" { target c++17_down } } + int n : (V ? W : b) { 10 }; // { dg-warning "default member initializers for bit-fields only available with" "" { target c++17_down } } + int o : 1 || new int { 0 }; +}; +#if __cplusplus >= 201402L +static_assert (U{}.j == 7); +static_assert (U{}.k == 8); +static_assert (U{}.l == 0); +static_assert (U{}.m == 9); +static_assert (U{}.n == 10); +static_assert (U{}.o == 0); +#endif +S s; +U u; + +int +main () +{ + if (s.c != 1 || s.d != 2 || s.e != 0 || s.f != 4 || s.g != 5 || s.h != 0) + abort (); + s.c = 47; // { dg-warning "overflow in conversion from" } + s.d = 47 * 2; // { dg-warning "overflow in conversion from" } + s.e = 47 * 4; // { dg-warning "overflow in conversion from" } + s.f = 47 * 8; // { dg-warning "overflow in conversion from" } + s.g = 47 * 16; // { dg-warning "overflow in conversion from" } + s.h = 2; // { dg-warning "overflow in conversion from" } + if (s.c != 15 || s.d != 15 * 2 || s.e != 15 * 4 || s.f != 15 * 8 || s.g != 15 * 16 || s.h != 0) + abort (); + if (u.j != 7 || u.k != 8 || u.l != 0 || u.m != 9 || u.n != 10 || u.o != 0) + abort (); + u.j = 47 * 32; // { dg-warning "overflow in conversion from" } + u.k = 47 * 32; // { dg-warning "overflow in conversion from" } + u.l = 47 * 4; // { dg-warning "overflow in conversion from" } + u.m = 47 * 32; // { dg-warning "overflow in conversion from" } + u.n = 47 * 32; // { dg-warning "overflow in conversion from" } + u.o = 2; // { dg-warning "overflow in conversion from" } + if (u.j != 15 * 32 || u.k != 15 * 32 || u.l != 15 * 4 || u.m != 15 * 32 || u.n != 15 * 32 || u.o != 0) + abort (); + s.c = 15; + s.d = 15 * 2; + s.e = 15 * 4; + s.f = 16 * 8; + s.g = 15 * 16; + u.j = 15 * 32; + u.k = 15 * 32; + u.l = 15 * 4; + u.m = 15 * 32; + u.n = 15 * 32; +} diff --git a/gcc/testsuite/g++.dg/cpp2a/bitfield2.C b/gcc/testsuite/g++.dg/cpp2a/bitfield2.C new file mode 100644 index 00000000000..dcb424fc8f6 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/bitfield2.C @@ -0,0 +1,26 @@ +// P0683R1 +// { dg-do compile { target c++11 } } +// { dg-options "" } + +int a; +const int b = 0; +struct T { + int i : true ? 10 : b = 6; // { dg-error "assignment of read-only variable" } + int : 4 = 10; // { dg-error "default member initializer for unnamed bit-field" } + int : 5 = a + b; // { dg-error "default member initializer for unnamed bit-field" } +}; +template +struct U { + int j : W = 7; // { dg-warning "default member initializers for bit-fields only available with" "" { target c++17_down } } + int k : W { 8 }; // { dg-warning "default member initializers for bit-fields only available with" "" { target c++17_down } } + int l : V ? 7 : a = 3; // { dg-error "modification of .a. is not a constant expression" } + // { dg-error "width not an integer constant" "" { target *-*-* } .-1 } + int m : (V ? W : b) = 9; // { dg-warning "default member initializers for bit-fields only available with" "" { target c++17_down } } + // { dg-error "zero width for bit-field" "" { target *-*-* } .-1 } + int n : (V ? W : b) { 10 }; // { dg-warning "default member initializers for bit-fields only available with" "" { target c++17_down } } + // { dg-error "zero width for bit-field" "" { target *-*-* } .-1 } + int o : 1 || new int { 0 }; + int : 4 = 10; // { dg-error "default member initializer for unnamed bit-field" } + int : 5 = a + b; // { dg-error "default member initializer for unnamed bit-field" } +}; +U u; diff --git a/gcc/testsuite/g++.dg/cpp2a/bitfield3.C b/gcc/testsuite/g++.dg/cpp2a/bitfield3.C new file mode 100644 index 00000000000..511c8894703 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/bitfield3.C @@ -0,0 +1,55 @@ +// P0683R1 +// { dg-do compile { target c++11 } } +// { dg-options "" } + +extern "C" void abort (); + +int +foo () +{ + return 2; +} + +int a = foo (); +const int b = 0; +struct S { + int c : 5 = 2 * a; // { dg-warning "default member initializers for bit-fields only available with" "" { target c++17_down } } + int d : 6 { c + a }; // { dg-warning "default member initializers for bit-fields only available with" "" { target c++17_down } } + // { dg-warning "narrowing conversion of" "" { target *-*-* } .-1 } + int e : true ? 7 : a = 3; + int f : (true ? 8 : b) = d + a; // { dg-warning "default member initializers for bit-fields only available with" "" { target c++17_down } } + int g : (true ? 9 : b) { f + a }; // { dg-warning "default member initializers for bit-fields only available with" "" { target c++17_down } } + // { dg-warning "narrowing conversion of" "" { target *-*-* } .-1 } + int h : 1 || new int { 0 }; + int i = g + a; +}; +S c; +template +struct U { + int j : W = 3 * a; // { dg-warning "default member initializers for bit-fields only available with" "" { target c++17_down } } + int k : W { j + a }; // { dg-warning "default member initializers for bit-fields only available with" "" { target c++17_down } } + // { dg-warning "narrowing conversion of" "" { target *-*-* } .-1 } + int l : V ? 7 : a = 3; + int m : (V ? W : b) = k + a; // { dg-warning "default member initializers for bit-fields only available with" "" { target c++17_down } } + int n : (V ? W : b) { m + a }; // { dg-warning "default member initializers for bit-fields only available with" "" { target c++17_down } } + // { dg-warning "narrowing conversion of" "" { target *-*-* } .-1 } + int o : 1 || new int { 0 }; + int p = n + a; +}; +U d; + +int +main () +{ + a = 1; + if (c.c != 4 || c.d != 6 || c.e != 0 || c.f != 8 || c.g != 10 || c.h != 0 || c.i != 12) + abort (); + if (d.j != 6 || d.k != 8 || d.l != 0 || d.m != 10 || d.n != 12 || d.o != 0 || d.p != 14) + abort (); + S s; + U u; + if (s.c != 2 || s.d != 3 || s.f != 4 || s.g != 5 || s.i != 6) + abort (); + if (u.j != 3 || u.k != 4 || u.m != 5 || u.n != 6 || u.p != 7) + abort (); +} diff --git a/gcc/testsuite/g++.dg/ext/bitfield6.C b/gcc/testsuite/g++.dg/ext/bitfield6.C new file mode 100644 index 00000000000..4b0bb77509c --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/bitfield6.C @@ -0,0 +1,15 @@ +// { dg-do compile { target c++11 } } +// { dg-options "" } + +struct S { + char a [[gnu::packed]] = 1; // { dg-warning "attribute ignored for field of type" } + char b [[gnu::packed]] : 8; + char c [[gnu::packed]] : 8 = 2; // { dg-warning "default member initializers for bit-fields only available with" "" { target c++17_down } } +}; +template +struct T { + U d [[gnu::packed]] = 1; // { dg-warning "attribute ignored for field of type" } + U e [[gnu::packed]] : 8; + U f [[gnu::packed]] : 8 = 2; // { dg-warning "default member initializers for bit-fields only available with" "" { target c++17_down } } +}; +T t;