diff options
author | Jason Merrill <jason@redhat.com> | 2016-10-14 17:54:39 -0400 |
---|---|---|
committer | Jason Merrill <jason@gcc.gnu.org> | 2016-10-14 17:54:39 -0400 |
commit | ec2416b5fff0e603e94ee98c1042003812847b59 (patch) | |
tree | 20dc5c1492c844c3ef6699033ebb18974cd22f91 | |
parent | efc5aa6bc7c686b302c5d7fd7f65e3f6361961e1 (diff) | |
download | gcc-ec2416b5fff0e603e94ee98c1042003812847b59.zip gcc-ec2416b5fff0e603e94ee98c1042003812847b59.tar.gz gcc-ec2416b5fff0e603e94ee98c1042003812847b59.tar.bz2 |
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
-rw-r--r-- | gcc/cp/ChangeLog | 10 | ||||
-rw-r--r-- | gcc/cp/class.c | 75 | ||||
-rw-r--r-- | gcc/cp/decl.c | 14 | ||||
-rw-r--r-- | gcc/cp/typeck2.c | 5 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp1z/aggr-base1.C | 23 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp1z/aggr-base1a.C | 15 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp1z/aggr-base2.C | 12 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp1z/aggr-base2a.C | 12 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp1z/aggr-base3.C | 11 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp1z/aggr-base4.C | 21 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp1z/aggr-base5.C | 14 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp1z/aggr-base6.C | 14 |
12 files changed, 193 insertions, 33 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index cdc5aff..43c573b 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -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> DR 1511 - const volatile variables and ODR diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 46f1bac..d334b7c 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -4452,6 +4452,34 @@ layout_empty_base (record_layout_info rli, tree binfo, 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. *BASE_ALIGN is a running maximum of the alignments of 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; /* Create the FIELD_DECL. */ - 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; - 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 - have a hard time placing the field without putting two - objects of the same type at the same address. */ - 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); - } + decl = build_base_field_1 (t, basetype, next_field); + + /* Try to place the field. It may take more than one try if we + have a hard time placing the field without putting two + objects of the same type at the same address. */ + layout_nonempty_base_or_field (rli, decl, binfo, offsets); } else { @@ -4536,11 +4547,17 @@ build_base_field (record_layout_info rli, tree binfo, CLASSTYPE_NEARLY_EMPTY_P (t) = 0; } - /* We do not create a FIELD_DECL for empty base classes because - it might overlap some other field. We want to be able to - create CONSTRUCTORs for the class by iterating over the - FIELD_DECLs, and the back end does not handle overlapping - FIELD_DECLs. */ + /* We used to not create a FIELD_DECL for empty base classes because of + back end issues with overlapping FIELD_DECLs, but that doesn't seem to + be a problem anymore. We need them to handle initialization of C++17 + aggregate bases. */ + 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 -- 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 point. */ - include_empty_classes(rli); + include_empty_classes (rli); /* Make sure not to create any structures with zero size. */ if (integer_zerop (rli_size_unit_so_far (rli)) && CLASSTYPE_EMPTY_P (t)) diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index d70d583..ecf4d14 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -5569,7 +5569,8 @@ next_initializable_field (tree field) while (field && (TREE_CODE (field) != FIELD_DECL || (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); return field; @@ -13153,8 +13154,8 @@ xref_basetypes (tree ref, tree base_list) if (max_bases) { vec_alloc (BINFO_BASE_ACCESSES (binfo), max_bases); - /* An aggregate cannot have baseclasses. */ - CLASSTYPE_NON_AGGREGATE (ref) = 1; + /* A C++98 POD cannot have base classes. */ + CLASSTYPE_NON_LAYOUT_POD_P (ref) = true; if (TREE_CODE (ref) == UNION_TYPE) error ("derived union %qT invalid", ref); @@ -13182,6 +13183,13 @@ xref_basetypes (tree ref, tree base_list) if (access == access_default_node) 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)) basetype = PACK_EXPANSION_PATTERN (basetype); if (TREE_CODE (basetype) == TYPE_DECL) diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c index 121da32..022a478 100644 --- a/gcc/cp/typeck2.c +++ b/gcc/cp/typeck2.c @@ -1352,6 +1352,7 @@ process_init_constructor_record (tree type, tree init, gcc_assert (TREE_CODE (type) == RECORD_TYPE); gcc_assert (!CLASSTYPE_VBASECLASSES (type)); gcc_assert (!TYPE_BINFO (type) + || cxx_dialect >= cxx1z || !BINFO_N_BASE_BINFOS (TYPE_BINFO (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)) 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; /* If this is a bitfield, first convert to the declared type. */ diff --git a/gcc/testsuite/g++.dg/cpp1z/aggr-base1.C b/gcc/testsuite/g++.dg/cpp1z/aggr-base1.C new file mode 100644 index 0000000..37bb472 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/aggr-base1.C @@ -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); +} diff --git a/gcc/testsuite/g++.dg/cpp1z/aggr-base1a.C b/gcc/testsuite/g++.dg/cpp1z/aggr-base1a.C new file mode 100644 index 0000000..4b28485 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/aggr-base1a.C @@ -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 "" } diff --git a/gcc/testsuite/g++.dg/cpp1z/aggr-base2.C b/gcc/testsuite/g++.dg/cpp1z/aggr-base2.C new file mode 100644 index 0000000..9da5ebf --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/aggr-base2.C @@ -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 diff --git a/gcc/testsuite/g++.dg/cpp1z/aggr-base2a.C b/gcc/testsuite/g++.dg/cpp1z/aggr-base2a.C new file mode 100644 index 0000000..821dce1 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/aggr-base2a.C @@ -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 diff --git a/gcc/testsuite/g++.dg/cpp1z/aggr-base3.C b/gcc/testsuite/g++.dg/cpp1z/aggr-base3.C new file mode 100644 index 0000000..4acbc0b --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/aggr-base3.C @@ -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 + diff --git a/gcc/testsuite/g++.dg/cpp1z/aggr-base4.C b/gcc/testsuite/g++.dg/cpp1z/aggr-base4.C new file mode 100644 index 0000000..fd93f4a --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/aggr-base4.C @@ -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); +} diff --git a/gcc/testsuite/g++.dg/cpp1z/aggr-base5.C b/gcc/testsuite/g++.dg/cpp1z/aggr-base5.C new file mode 100644 index 0000000..85dd365 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/aggr-base5.C @@ -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); +} diff --git a/gcc/testsuite/g++.dg/cpp1z/aggr-base6.C b/gcc/testsuite/g++.dg/cpp1z/aggr-base6.C new file mode 100644 index 0000000..31219ce --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/aggr-base6.C @@ -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); +} |