P0683R1 - default member initializers for bit-fields
authorJakub Jelinek <jakub@redhat.com>
Fri, 29 Sep 2017 17:53:50 +0000 (19:53 +0200)
committerJakub Jelinek <jakub@gcc.gnu.org>
Fri, 29 Sep 2017 17:53:50 +0000 (19:53 +0200)
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

gcc/cp/ChangeLog
gcc/cp/class.c
gcc/cp/cp-tree.h
gcc/cp/decl2.c
gcc/cp/parser.c
gcc/cp/pt.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/cpp2a/bitfield1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp2a/bitfield2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp2a/bitfield3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/bitfield6.C [new file with mode: 0644]

index fe73935eea2fbcb8eb32828c450cf003ae97b144..a9ee9a5eacf383c3933cd8e679549e7cd5e2f16e 100644 (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
index 687ddaa5c8f2f410bd1147a6028474a093448152..0c4a7b3db0419cc393613a74269706acf03355c2 100644 (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)
index f56c9517967cfd31390e2ee75dc916ce92264a57..a21c948539342a784075b94e6a1d66da2b691cf9 100644 (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);
index 107ce7bc882ffdfd9a3703da5bb8a2b061bba862..eb9c6a59e047a1a2281e93203b7b9089b6fbe39b 100644 (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)
     {
index 71c27a40ce2c18f86fe9f86d692687d59d6cec5e..6e817cb9fd5b2a3e1602cd8d8a9e997ad7058d19 100644 (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);
-
-             /* 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,
index 70cfc9aac8a4523d09f63e7f71a3a8a494fe0fbd..c29c779a14783b565bc357c3a8de46fa809215c0 100644 (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
index ac88fd3edf71289979fd0ff4476e2a5ebc5e7f28..94cedb737173257bd9e76ef7e1bc1adc6400f980 100644 (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
diff --git a/gcc/testsuite/g++.dg/cpp2a/bitfield1.C b/gcc/testsuite/g++.dg/cpp2a/bitfield1.C
new file mode 100644 (file)
index 0000000..497b529
--- /dev/null
@@ -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;
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/bitfield2.C b/gcc/testsuite/g++.dg/cpp2a/bitfield2.C
new file mode 100644 (file)
index 0000000..dcb424f
--- /dev/null
@@ -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;
diff --git a/gcc/testsuite/g++.dg/cpp2a/bitfield3.C b/gcc/testsuite/g++.dg/cpp2a/bitfield3.C
new file mode 100644 (file)
index 0000000..511c889
--- /dev/null
@@ -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 ();
+}
diff --git a/gcc/testsuite/g++.dg/ext/bitfield6.C b/gcc/testsuite/g++.dg/ext/bitfield6.C
new file mode 100644 (file)
index 0000000..4b0bb77
--- /dev/null
@@ -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;