mirror of git://gcc.gnu.org/git/gcc.git
Implement P0017R1, C++17 aggregates with bases.
* class.c (build_base_field_1): Split out from... (build_base_field): ...here. In C++17 mode, build a field for empty bases. * decl.c (xref_basetypes): In C++17 aggregates can have bases. (next_initializable_field): Allow base fields in C++17. * typeck2.c (process_init_constructor_record): Likewise. From-SVN: r241187
This commit is contained in:
parent
efc5aa6bc7
commit
ec2416b5ff
|
|
@ -1,3 +1,13 @@
|
||||||
|
2016-10-14 Jason Merrill <jason@redhat.com>
|
||||||
|
|
||||||
|
Implement P0017R1, C++17 aggregates with bases.
|
||||||
|
* class.c (build_base_field_1): Split out from...
|
||||||
|
(build_base_field): ...here. In C++17 mode, build a field for
|
||||||
|
empty bases.
|
||||||
|
* decl.c (xref_basetypes): In C++17 aggregates can have bases.
|
||||||
|
(next_initializable_field): Allow base fields in C++17.
|
||||||
|
* typeck2.c (process_init_constructor_record): Likewise.
|
||||||
|
|
||||||
2016-10-14 Jakub Jelinek <jakub@redhat.com>
|
2016-10-14 Jakub Jelinek <jakub@redhat.com>
|
||||||
|
|
||||||
DR 1511 - const volatile variables and ODR
|
DR 1511 - const volatile variables and ODR
|
||||||
|
|
|
||||||
|
|
@ -4452,6 +4452,34 @@ layout_empty_base (record_layout_info rli, tree binfo,
|
||||||
return atend;
|
return atend;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Build the FIELD_DECL for BASETYPE as a base of T, add it to the chain of
|
||||||
|
fields at NEXT_FIELD, and return it. */
|
||||||
|
|
||||||
|
static tree
|
||||||
|
build_base_field_1 (tree t, tree basetype, tree *&next_field)
|
||||||
|
{
|
||||||
|
/* Create the FIELD_DECL. */
|
||||||
|
gcc_assert (CLASSTYPE_AS_BASE (basetype));
|
||||||
|
tree decl = build_decl (input_location,
|
||||||
|
FIELD_DECL, NULL_TREE, CLASSTYPE_AS_BASE (basetype));
|
||||||
|
DECL_ARTIFICIAL (decl) = 1;
|
||||||
|
DECL_IGNORED_P (decl) = 1;
|
||||||
|
DECL_FIELD_CONTEXT (decl) = t;
|
||||||
|
DECL_SIZE (decl) = CLASSTYPE_SIZE (basetype);
|
||||||
|
DECL_SIZE_UNIT (decl) = CLASSTYPE_SIZE_UNIT (basetype);
|
||||||
|
SET_DECL_ALIGN (decl, CLASSTYPE_ALIGN (basetype));
|
||||||
|
DECL_USER_ALIGN (decl) = CLASSTYPE_USER_ALIGN (basetype);
|
||||||
|
DECL_MODE (decl) = TYPE_MODE (basetype);
|
||||||
|
DECL_FIELD_IS_BASE (decl) = 1;
|
||||||
|
|
||||||
|
/* Add the new FIELD_DECL to the list of fields for T. */
|
||||||
|
DECL_CHAIN (decl) = *next_field;
|
||||||
|
*next_field = decl;
|
||||||
|
next_field = &DECL_CHAIN (decl);
|
||||||
|
|
||||||
|
return decl;
|
||||||
|
}
|
||||||
|
|
||||||
/* Layout the base given by BINFO in the class indicated by RLI.
|
/* Layout the base given by BINFO in the class indicated by RLI.
|
||||||
*BASE_ALIGN is a running maximum of the alignments of
|
*BASE_ALIGN is a running maximum of the alignments of
|
||||||
any base class. OFFSETS gives the location of empty base
|
any base class. OFFSETS gives the location of empty base
|
||||||
|
|
@ -4483,29 +4511,12 @@ build_base_field (record_layout_info rli, tree binfo,
|
||||||
CLASSTYPE_EMPTY_P (t) = 0;
|
CLASSTYPE_EMPTY_P (t) = 0;
|
||||||
|
|
||||||
/* Create the FIELD_DECL. */
|
/* Create the FIELD_DECL. */
|
||||||
decl = build_decl (input_location,
|
decl = build_base_field_1 (t, basetype, next_field);
|
||||||
FIELD_DECL, NULL_TREE, CLASSTYPE_AS_BASE (basetype));
|
|
||||||
DECL_ARTIFICIAL (decl) = 1;
|
|
||||||
DECL_IGNORED_P (decl) = 1;
|
|
||||||
DECL_FIELD_CONTEXT (decl) = t;
|
|
||||||
if (CLASSTYPE_AS_BASE (basetype))
|
|
||||||
{
|
|
||||||
DECL_SIZE (decl) = CLASSTYPE_SIZE (basetype);
|
|
||||||
DECL_SIZE_UNIT (decl) = CLASSTYPE_SIZE_UNIT (basetype);
|
|
||||||
SET_DECL_ALIGN (decl, CLASSTYPE_ALIGN (basetype));
|
|
||||||
DECL_USER_ALIGN (decl) = CLASSTYPE_USER_ALIGN (basetype);
|
|
||||||
DECL_MODE (decl) = TYPE_MODE (basetype);
|
|
||||||
DECL_FIELD_IS_BASE (decl) = 1;
|
|
||||||
|
|
||||||
/* Try to place the field. It may take more than one try if we
|
/* Try to place the field. It may take more than one try if we
|
||||||
have a hard time placing the field without putting two
|
have a hard time placing the field without putting two
|
||||||
objects of the same type at the same address. */
|
objects of the same type at the same address. */
|
||||||
layout_nonempty_base_or_field (rli, decl, binfo, offsets);
|
layout_nonempty_base_or_field (rli, decl, binfo, offsets);
|
||||||
/* Add the new FIELD_DECL to the list of fields for T. */
|
|
||||||
DECL_CHAIN (decl) = *next_field;
|
|
||||||
*next_field = decl;
|
|
||||||
next_field = &DECL_CHAIN (decl);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -4536,11 +4547,17 @@ build_base_field (record_layout_info rli, tree binfo,
|
||||||
CLASSTYPE_NEARLY_EMPTY_P (t) = 0;
|
CLASSTYPE_NEARLY_EMPTY_P (t) = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We do not create a FIELD_DECL for empty base classes because
|
/* We used to not create a FIELD_DECL for empty base classes because of
|
||||||
it might overlap some other field. We want to be able to
|
back end issues with overlapping FIELD_DECLs, but that doesn't seem to
|
||||||
create CONSTRUCTORs for the class by iterating over the
|
be a problem anymore. We need them to handle initialization of C++17
|
||||||
FIELD_DECLs, and the back end does not handle overlapping
|
aggregate bases. */
|
||||||
FIELD_DECLs. */
|
if (cxx_dialect >= cxx1z && !BINFO_VIRTUAL_P (binfo))
|
||||||
|
{
|
||||||
|
tree decl = build_base_field_1 (t, basetype, next_field);
|
||||||
|
DECL_FIELD_OFFSET (decl) = BINFO_OFFSET (binfo);
|
||||||
|
DECL_FIELD_BIT_OFFSET (decl) = bitsize_zero_node;
|
||||||
|
SET_DECL_OFFSET_ALIGN (decl, BITS_PER_UNIT);
|
||||||
|
}
|
||||||
|
|
||||||
/* An empty virtual base causes a class to be non-empty
|
/* An empty virtual base causes a class to be non-empty
|
||||||
-- but in that case we do not need to clear CLASSTYPE_EMPTY_P
|
-- but in that case we do not need to clear CLASSTYPE_EMPTY_P
|
||||||
|
|
@ -6586,7 +6603,7 @@ layout_class_type (tree t, tree *virtuals_p)
|
||||||
|
|
||||||
/* Make sure that empty classes are reflected in RLI at this
|
/* Make sure that empty classes are reflected in RLI at this
|
||||||
point. */
|
point. */
|
||||||
include_empty_classes(rli);
|
include_empty_classes (rli);
|
||||||
|
|
||||||
/* Make sure not to create any structures with zero size. */
|
/* Make sure not to create any structures with zero size. */
|
||||||
if (integer_zerop (rli_size_unit_so_far (rli)) && CLASSTYPE_EMPTY_P (t))
|
if (integer_zerop (rli_size_unit_so_far (rli)) && CLASSTYPE_EMPTY_P (t))
|
||||||
|
|
|
||||||
|
|
@ -5569,7 +5569,8 @@ next_initializable_field (tree field)
|
||||||
while (field
|
while (field
|
||||||
&& (TREE_CODE (field) != FIELD_DECL
|
&& (TREE_CODE (field) != FIELD_DECL
|
||||||
|| (DECL_C_BIT_FIELD (field) && !DECL_NAME (field))
|
|| (DECL_C_BIT_FIELD (field) && !DECL_NAME (field))
|
||||||
|| DECL_ARTIFICIAL (field)))
|
|| (DECL_ARTIFICIAL (field)
|
||||||
|
&& !(cxx_dialect >= cxx1z && DECL_FIELD_IS_BASE (field)))))
|
||||||
field = DECL_CHAIN (field);
|
field = DECL_CHAIN (field);
|
||||||
|
|
||||||
return field;
|
return field;
|
||||||
|
|
@ -13153,8 +13154,8 @@ xref_basetypes (tree ref, tree base_list)
|
||||||
if (max_bases)
|
if (max_bases)
|
||||||
{
|
{
|
||||||
vec_alloc (BINFO_BASE_ACCESSES (binfo), max_bases);
|
vec_alloc (BINFO_BASE_ACCESSES (binfo), max_bases);
|
||||||
/* An aggregate cannot have baseclasses. */
|
/* A C++98 POD cannot have base classes. */
|
||||||
CLASSTYPE_NON_AGGREGATE (ref) = 1;
|
CLASSTYPE_NON_LAYOUT_POD_P (ref) = true;
|
||||||
|
|
||||||
if (TREE_CODE (ref) == UNION_TYPE)
|
if (TREE_CODE (ref) == UNION_TYPE)
|
||||||
error ("derived union %qT invalid", ref);
|
error ("derived union %qT invalid", ref);
|
||||||
|
|
@ -13182,6 +13183,13 @@ xref_basetypes (tree ref, tree base_list)
|
||||||
if (access == access_default_node)
|
if (access == access_default_node)
|
||||||
access = default_access;
|
access = default_access;
|
||||||
|
|
||||||
|
/* Before C++17, an aggregate cannot have base classes. In C++17, an
|
||||||
|
aggregate can't have virtual, private, or protected base classes. */
|
||||||
|
if (cxx_dialect < cxx1z
|
||||||
|
|| access != access_public_node
|
||||||
|
|| via_virtual)
|
||||||
|
CLASSTYPE_NON_AGGREGATE (ref) = true;
|
||||||
|
|
||||||
if (PACK_EXPANSION_P (basetype))
|
if (PACK_EXPANSION_P (basetype))
|
||||||
basetype = PACK_EXPANSION_PATTERN (basetype);
|
basetype = PACK_EXPANSION_PATTERN (basetype);
|
||||||
if (TREE_CODE (basetype) == TYPE_DECL)
|
if (TREE_CODE (basetype) == TYPE_DECL)
|
||||||
|
|
|
||||||
|
|
@ -1352,6 +1352,7 @@ process_init_constructor_record (tree type, tree init,
|
||||||
gcc_assert (TREE_CODE (type) == RECORD_TYPE);
|
gcc_assert (TREE_CODE (type) == RECORD_TYPE);
|
||||||
gcc_assert (!CLASSTYPE_VBASECLASSES (type));
|
gcc_assert (!CLASSTYPE_VBASECLASSES (type));
|
||||||
gcc_assert (!TYPE_BINFO (type)
|
gcc_assert (!TYPE_BINFO (type)
|
||||||
|
|| cxx_dialect >= cxx1z
|
||||||
|| !BINFO_N_BASE_BINFOS (TYPE_BINFO (type)));
|
|| !BINFO_N_BASE_BINFOS (TYPE_BINFO (type)));
|
||||||
gcc_assert (!TYPE_POLYMORPHIC_P (type));
|
gcc_assert (!TYPE_POLYMORPHIC_P (type));
|
||||||
|
|
||||||
|
|
@ -1369,7 +1370,9 @@ process_init_constructor_record (tree type, tree init,
|
||||||
if (!DECL_NAME (field) && DECL_C_BIT_FIELD (field))
|
if (!DECL_NAME (field) && DECL_C_BIT_FIELD (field))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (TREE_CODE (field) != FIELD_DECL || DECL_ARTIFICIAL (field))
|
if (TREE_CODE (field) != FIELD_DECL
|
||||||
|
|| (DECL_ARTIFICIAL (field)
|
||||||
|
&& !(cxx_dialect >= cxx1z && DECL_FIELD_IS_BASE (field))))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* If this is a bitfield, first convert to the declared type. */
|
/* If this is a bitfield, first convert to the declared type. */
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
// { dg-options -std=c++1z }
|
||||||
|
// { dg-do run }
|
||||||
|
|
||||||
|
struct base1 { int b1, b2 = 42; };
|
||||||
|
struct base2 {
|
||||||
|
base2() {
|
||||||
|
b3 = 42;
|
||||||
|
}
|
||||||
|
int b3;
|
||||||
|
};
|
||||||
|
struct derived : base1, base2 {
|
||||||
|
int d;
|
||||||
|
};
|
||||||
|
|
||||||
|
derived d1{{1, 2}, {}, 4};
|
||||||
|
derived d2{{}, {}, 4};
|
||||||
|
|
||||||
|
#define assert(X) do { if (!(X)) __builtin_abort(); } while(0)
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
assert (d1.b1 == 1 && d1.b2 == 2 && d1.b3 == 42 && d1.d == 4);
|
||||||
|
assert (d2.b1 == 0 && d2.b2 == 42 && d2.b3 == 42 && d2.d == 4);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
// { dg-do compile { target { c++11 && c++14_down } } }
|
||||||
|
|
||||||
|
struct base1 { int b1, b2 = 42; };
|
||||||
|
struct base2 {
|
||||||
|
base2() {
|
||||||
|
b3 = 42;
|
||||||
|
}
|
||||||
|
int b3;
|
||||||
|
};
|
||||||
|
struct derived : base1, base2 {
|
||||||
|
int d;
|
||||||
|
};
|
||||||
|
|
||||||
|
derived d1{{1, 2}, {}, 4}; // { dg-error "" }
|
||||||
|
derived d2{{}, {}, 4}; // { dg-error "" }
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
// { dg-options -std=c++1z }
|
||||||
|
|
||||||
|
struct derived;
|
||||||
|
struct base {
|
||||||
|
friend struct derived;
|
||||||
|
private:
|
||||||
|
base();
|
||||||
|
};
|
||||||
|
struct derived : base {};
|
||||||
|
|
||||||
|
derived d1{}; // { dg-error "" "" { target c++1z } }
|
||||||
|
derived d2; // still OK
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
// { dg-do compile { target c++11 } }
|
||||||
|
|
||||||
|
struct derived;
|
||||||
|
struct base {
|
||||||
|
friend struct derived;
|
||||||
|
private:
|
||||||
|
base();
|
||||||
|
};
|
||||||
|
struct derived : base {};
|
||||||
|
|
||||||
|
derived d1{}; // { dg-error "" "" { target c++1z } }
|
||||||
|
derived d2; // still OK
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
// { dg-options -std=c++1z }
|
||||||
|
|
||||||
|
struct derived;
|
||||||
|
struct base { };
|
||||||
|
struct derived : base {
|
||||||
|
int i;
|
||||||
|
};
|
||||||
|
|
||||||
|
derived d1{1}; // { dg-error "base" }
|
||||||
|
derived d2{{},1}; // OK
|
||||||
|
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
// { dg-options -std=c++1z }
|
||||||
|
// { dg-do run }
|
||||||
|
|
||||||
|
struct derived;
|
||||||
|
struct base { };
|
||||||
|
struct derived : base {
|
||||||
|
int i;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool flag;
|
||||||
|
base f() {
|
||||||
|
flag = true;
|
||||||
|
return base();
|
||||||
|
}
|
||||||
|
|
||||||
|
derived d2{f(),1};
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
return (!flag || d2.i != 1);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
// { dg-options "-std=c++1z -w" }
|
||||||
|
// { dg-do run }
|
||||||
|
|
||||||
|
struct A { };
|
||||||
|
struct B: A { int i; };
|
||||||
|
struct C: A, B { int j; };
|
||||||
|
|
||||||
|
constexpr C c = { {}, { {}, 1 }, 2 };
|
||||||
|
|
||||||
|
#define assert(X) do { if (!(X)) __builtin_abort(); } while(0)
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
assert (c.i == 1 && c.j == 2);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
// { dg-options "-std=c++1z -w" }
|
||||||
|
// { dg-do run }
|
||||||
|
|
||||||
|
struct A { };
|
||||||
|
struct B: A { int i; };
|
||||||
|
struct C: B, A { int j; };
|
||||||
|
|
||||||
|
constexpr C c = { { {}, 1 }, {}, 2 };
|
||||||
|
|
||||||
|
#define assert(X) do { if (!(X)) __builtin_abort(); } while(0)
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
assert (c.i == 1 && c.j == 2);
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue