2017-09-29 Jakub Jelinek <jakub@redhat.com>
+ 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
{
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);
/* 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)
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);
}
/* 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. */
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)
{
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
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;
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;
{
tree attributes = NULL_TREE;
tree first_attribute;
+ tree initializer;
bool is_bitfld = false;
bool named_bitfld = false;
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);
sfk_none)
: NULL,
&decl_specifiers,
- width,
+ width, initializer,
attributes);
}
else
{
cp_declarator *declarator;
- tree initializer;
tree asm_specification;
int ctor_dtor_or_conv_p;
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);
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,
= 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
+2017-09-29 Jakub Jelinek <jakub@redhat.com>
+
+ 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 <vmakarov@redhat.com>
PR target/81481
--- /dev/null
+// 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 <bool V, int W>
+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<true, 12>{}.j == 7);
+static_assert (U<true, 13>{}.k == 8);
+static_assert (U<true, 10>{}.l == 0);
+static_assert (U<true, 11>{}.m == 9);
+static_assert (U<true, 8>{}.n == 10);
+static_assert (U<true, 7>{}.o == 0);
+#endif
+S s;
+U<true, 10> 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;
+}
--- /dev/null
+// 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 <bool V, int W>
+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<false, 10> u;
--- /dev/null
+// 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 <bool V, int W>
+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<true, 10> 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<true, 10> 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 ();
+}
--- /dev/null
+// { 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 <typename U>
+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<char> t;