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
This commit is contained in:
Jakub Jelinek 2017-09-29 19:53:50 +02:00 committed by Jakub Jelinek
parent 7d386d4508
commit 603be0224e
11 changed files with 282 additions and 36 deletions

View File

@ -1,5 +1,22 @@
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

View File

@ -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)

View File

@ -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);

View File

@ -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)
{

View File

@ -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);
width = cp_parser_constant_expression (parser, false, NULL,
cxx_dialect >= cxx11);
/* 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");
/* 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");
late_attributes = cp_parser_attributes_opt (parser);
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,

View File

@ -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

View File

@ -1,3 +1,11 @@
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

View File

@ -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 <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;
}

View File

@ -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 <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;

View File

@ -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 <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 ();
}

View File

@ -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 <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;