From 9b2f0394a02119a605017481a138bb10b5624077 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Thu, 14 Feb 2013 20:27:47 -0500 Subject: [PATCH] re PR c++/54922 ([C++11][DR 1359] constexpr constructors require initialization of all union members) PR c++/54922 * semantics.c (build_anon_member_initialization): New. (build_data_member_initialization): Use it. From-SVN: r196070 --- gcc/cp/ChangeLog | 4 + gcc/cp/semantics.c | 74 +++++++++++++++++-- gcc/testsuite/g++.dg/cpp0x/constexpr-union4.C | 18 +++++ gcc/testsuite/g++.dg/cpp0x/constexpr-union5.C | 41 ++++++++++ 4 files changed, 131 insertions(+), 6 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/constexpr-union4.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/constexpr-union5.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 1e658e9b14c..9033b51df28 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,9 @@ 2013-02-14 Jason Merrill + PR c++/54922 + * semantics.c (build_anon_member_initialization): New. + (build_data_member_initialization): Use it. + PR c++/55003 * decl.c (cp_finish_decl): Force instantiation of an auto static data member. diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 95158a58771..28b4b791273 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -5815,6 +5815,59 @@ is_valid_constexpr_fn (tree fun, bool complain) return ret; } +/* Subroutine of build_data_member_initialization. MEMBER is a COMPONENT_REF + for a member of an anonymous aggregate, INIT is the initializer for that + member, and VEC_OUTER is the vector of constructor elements for the class + whose constructor we are processing. Add the initializer to the vector + and return true to indicate success. */ + +static bool +build_anon_member_initialization (tree member, tree init, + vec **vec_outer) +{ + /* MEMBER presents the relevant fields from the inside out, but we need + to build up the initializer from the outside in so that we can reuse + previously built CONSTRUCTORs if this is, say, the second field in an + anonymous struct. So we use a vec as a stack. */ + vec fields; + fields.create (2); + do + { + fields.safe_push (TREE_OPERAND (member, 1)); + member = TREE_OPERAND (member, 0); + } + while (ANON_AGGR_TYPE_P (TREE_TYPE (member))); + + /* VEC has the constructor elements vector for the context of FIELD. + If FIELD is an anonymous aggregate, we will push inside it. */ + vec **vec = vec_outer; + tree field; + while (field = fields.pop(), + ANON_AGGR_TYPE_P (TREE_TYPE (field))) + { + tree ctor; + /* If there is already an outer constructor entry for the anonymous + aggregate FIELD, use it; otherwise, insert one. */ + if (vec_safe_is_empty (*vec) + || (*vec)->last().index != field) + { + ctor = build_constructor (TREE_TYPE (field), NULL); + CONSTRUCTOR_APPEND_ELT (*vec, field, ctor); + } + else + ctor = (*vec)->last().value; + vec = &CONSTRUCTOR_ELTS (ctor); + } + + /* Now we're at the innermost field, the one that isn't an anonymous + aggregate. Add its initializer to the CONSTRUCTOR and we're done. */ + gcc_assert (fields.is_empty()); + fields.release (); + CONSTRUCTOR_APPEND_ELT (*vec, field, init); + + return true; +} + /* Subroutine of build_constexpr_constructor_member_initializers. The expression tree T represents a data member initialization in a (constexpr) constructor definition. Build a pairing of @@ -5901,12 +5954,21 @@ build_data_member_initialization (tree t, vec **vec) } if (TREE_CODE (member) == ADDR_EXPR) member = TREE_OPERAND (member, 0); - if (TREE_CODE (member) == COMPONENT_REF - /* If we're initializing a member of a subaggregate, it's a vtable - pointer. Leave it as COMPONENT_REF so we remember the path to get - to the vfield. */ - && TREE_CODE (TREE_OPERAND (member, 0)) != COMPONENT_REF) - member = TREE_OPERAND (member, 1); + if (TREE_CODE (member) == COMPONENT_REF) + { + tree aggr = TREE_OPERAND (member, 0); + if (TREE_CODE (aggr) != COMPONENT_REF) + /* Normal member initialization. */ + member = TREE_OPERAND (member, 1); + else if (ANON_AGGR_TYPE_P (TREE_TYPE (aggr))) + /* Initializing a member of an anonymous union. */ + return build_anon_member_initialization (member, init, vec); + else + /* We're initializing a vtable pointer in a base. Leave it as + COMPONENT_REF so we remember the path to get to the vfield. */ + gcc_assert (TREE_TYPE (member) == vtbl_ptr_type_node); + } + CONSTRUCTOR_APPEND_ELT (*vec, member, init); return true; } diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-union4.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-union4.C new file mode 100644 index 00000000000..a8d6b8d3ea6 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-union4.C @@ -0,0 +1,18 @@ +// PR c++/54922 +// { dg-do compile { target c++11 } } + +struct nullable_int +{ + bool init_; + union { + unsigned char for_value_init; + int value_; + }; + + constexpr nullable_int() : init_(false), for_value_init() {} +}; + +#define SA(X) static_assert(X,#X) + +constexpr nullable_int n; +SA((n.for_value_init == 0)); diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-union5.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-union5.C new file mode 100644 index 00000000000..e8e678d3eca --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-union5.C @@ -0,0 +1,41 @@ +// PR c++/54922 +// { dg-options "-std=c++11 -pedantic" } + +#define SA(X) static_assert(X,#X) + +struct A +{ + union { + union { + union { + unsigned char i; + int j; + }; + }; + }; + + constexpr A() : i(42) {} +}; + +constexpr A a; +SA((a.i == 42)); + +struct B +{ + struct { + int h; + struct { + union { + unsigned char i; + int j; + }; + int k; + }; // { dg-warning "anonymous struct" } + }; // { dg-warning "anonymous struct" } + int l; + + constexpr B(): h(1), i(2), k(3), l(4) {} +}; + +constexpr B b; +SA((b.h == 1 && b.i == 2 && b.k == 3 && b.l == 4)); -- 2.30.2