From patchwork Fri Sep 29 12:26:55 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jakub Jelinek X-Patchwork-Id: 819889 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-463176-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="BHyyi1Lk"; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3y3W5z4Hgbz9t3H for ; Fri, 29 Sep 2017 22:27:18 +1000 (AEST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:cc:subject:message-id:reply-to:references:mime-version :content-type:in-reply-to; q=dns; s=default; b=hSHflNDC6G0oAZS0Y gbIigzY46WVHMIYWMTEVm26eK3xAKq/fVjntNg1f9fJvYyXZXKFjdmza/yRI0+Fc Fl/G/yvpJgW8F9QfGQzkEkI+a5aWMb9dWuIxQvDyRmn/s83iJ3o/Vcnw2nLQqERD Gf95uYbwN0trtfV6JJDBG8Ap+M= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:cc:subject:message-id:reply-to:references:mime-version :content-type:in-reply-to; s=default; bh=A0keWGrGvasKzBZ0fGC9rcF Nc4M=; b=BHyyi1LkqwtMbYloQ/leUx1j8on5iPzoh56NnL4ygTtt9j3ZhFFSQa3 26Nqr1l5hsi44nSIosRzwHJ71gRMVuwgkmttUZW4qAcXE1Y6J9dtFRkTTTnmoJhW PkCTcHaM4KI5tyLWxWgEN2Z5GkpEedT00/PLw5rWEO+JZBAiw01I= Received: (qmail 34726 invoked by alias); 29 Sep 2017 12:27:10 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 34326 invoked by uid 89); 29 Sep 2017 12:27:09 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-11.9 required=5.0 tests=BAYES_00, GIT_PATCH_2, GIT_PATCH_3, RP_MATCHES_RCVD, SPF_HELO_PASS autolearn=ham version=3.3.2 spammy=up, sc, essential, sf X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Fri, 29 Sep 2017 12:27:06 +0000 Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 6378C4A6E6; Fri, 29 Sep 2017 12:27:05 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 6378C4A6E6 Authentication-Results: ext-mx09.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx09.extmail.prod.ext.phx2.redhat.com; spf=fail smtp.mailfrom=jakub@redhat.com Received: from tucnak.zalov.cz (ovpn-116-41.ams2.redhat.com [10.36.116.41]) by smtp.corp.redhat.com (Postfix) with ESMTPS id CE58317C2A; Fri, 29 Sep 2017 12:27:04 +0000 (UTC) Received: from tucnak.zalov.cz (localhost [127.0.0.1]) by tucnak.zalov.cz (8.15.2/8.15.2) with ESMTP id v8TCR1Rr002474; Fri, 29 Sep 2017 14:27:02 +0200 Received: (from jakub@localhost) by tucnak.zalov.cz (8.15.2/8.15.2/Submit) id v8TCQutm002473; Fri, 29 Sep 2017 14:26:56 +0200 Date: Fri, 29 Sep 2017 14:26:55 +0200 From: Jakub Jelinek To: Nathan Sidwell Cc: Jason Merrill , gcc-patches@gcc.gnu.org Subject: [C++ PATCH] C++2A P0683R1 - default member initializers for bit-fields (take 2) Message-ID: <20170929122655.GJ1701@tucnak> Reply-To: Jakub Jelinek References: <20170919125426.GK1701@tucnak> <56458ce2-1a72-7852-13ac-a1e71f5131ea@acm.org> MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: <56458ce2-1a72-7852-13ac-a1e71f5131ea@acm.org> User-Agent: Mutt/1.7.1 (2016-10-04) X-IsSubscribed: yes Hi! On Wed, Sep 27, 2017 at 07:55:20AM -0700, Nathan Sidwell wrote: > 1) fix the parsing bug you found and move to (ab)using > DECL_BIT_FIELD_REPRESENTATIVE > > 2) the new c++2a feature And here is the 2) patch, on top of the previous 3 ones. Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? 2017-09-29 Jakub Jelinek 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. Jakub --- gcc/cp/cp-tree.h.jj 2017-09-29 09:07:33.554063918 +0200 +++ gcc/cp/cp-tree.h 2017-09-29 10:24:26.846373177 +0200 @@ -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); --- gcc/cp/parser.c.jj 2017-09-29 09:47:43.978411525 +0200 +++ gcc/cp/parser.c 2017-09-29 10:55:51.364348848 +0200 @@ -2089,7 +2089,7 @@ static enum tree_code cp_parser_assignme 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, 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->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* { 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* 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* 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* 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* p 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, --- gcc/cp/class.c.jj 2017-09-29 09:57:12.585423540 +0200 +++ gcc/cp/class.c 2017-09-29 10:24:26.863372969 +0200 @@ -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_ /* 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) --- gcc/cp/decl2.c.jj 2017-09-29 09:57:12.586423527 +0200 +++ gcc/cp/decl2.c 2017-09-29 10:24:26.864372956 +0200 @@ -978,10 +978,11 @@ grokfield (const cp_declarator *declarat 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 +1037,11 @@ grokbitfield (const cp_declarator *decla 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) { --- gcc/cp/pt.c.jj 2017-09-29 10:24:26.872372858 +0200 +++ gcc/cp/pt.c 2017-09-29 10:24:58.639983280 +0200 @@ -12841,7 +12841,7 @@ tsubst_decl (tree t, tree args, tsubst_f = 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 --- gcc/testsuite/g++.dg/ext/bitfield6.C.jj 2017-09-29 10:24:26.874372834 +0200 +++ gcc/testsuite/g++.dg/ext/bitfield6.C 2017-09-29 10:24:26.874372834 +0200 @@ -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; --- gcc/testsuite/g++.dg/cpp2a/bitfield1.C.jj 2017-09-29 10:24:26.874372834 +0200 +++ gcc/testsuite/g++.dg/cpp2a/bitfield1.C 2017-09-29 10:24:26.874372834 +0200 @@ -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; +} --- gcc/testsuite/g++.dg/cpp2a/bitfield2.C.jj 2017-09-29 10:24:26.875372822 +0200 +++ gcc/testsuite/g++.dg/cpp2a/bitfield2.C 2017-09-29 10:24:26.875372822 +0200 @@ -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; --- gcc/testsuite/g++.dg/cpp2a/bitfield3.C.jj 2017-09-29 10:24:26.875372822 +0200 +++ gcc/testsuite/g++.dg/cpp2a/bitfield3.C 2017-09-29 10:24:26.875372822 +0200 @@ -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 (); +}