aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/common.opt1
-rw-r--r--gcc/cp/class.cc54
-rw-r--r--gcc/cp/cp-tree.h8
-rw-r--r--gcc/doc/invoke.texi3
-rw-r--r--gcc/testsuite/g++.dg/abi/base-defaulted1.C19
-rw-r--r--gcc/testsuite/g++.dg/abi/base-defaulted1a.C23
6 files changed, 95 insertions, 13 deletions
diff --git a/gcc/common.opt b/gcc/common.opt
index 8a5b69d..0e50305 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -1056,6 +1056,7 @@ Driver Undocumented
; Default in G++ 15.
;
; 21: Fix noexcept lambda capture pruning.
+; Fix C++20 layout of base with all explicitly defaulted constructors.
; Default in G++ 16.
;
; Additional positive integers will be assigned as new versions of
diff --git a/gcc/cp/class.cc b/gcc/cp/class.cc
index 2b694b9..6767ac1 100644
--- a/gcc/cp/class.cc
+++ b/gcc/cp/class.cc
@@ -6413,9 +6413,7 @@ check_bases_and_members (tree t)
Again, other conditions for being an aggregate are checked
elsewhere. */
CLASSTYPE_NON_AGGREGATE (t)
- |= ((cxx_dialect < cxx20
- ? type_has_user_provided_or_explicit_constructor (t)
- : TYPE_HAS_USER_CONSTRUCTOR (t))
+ |= (type_has_user_provided_or_explicit_constructor (t)
|| TYPE_POLYMORPHIC_P (t));
/* This is the C++98/03 definition of POD; it changed in C++0x, but we
retain the old definition internally for ABI reasons. */
@@ -6437,6 +6435,20 @@ check_bases_and_members (tree t)
CLASSTYPE_NON_LAYOUT_POD_P (t) = true;
}
+ /* P1008: Prohibit aggregates with user-declared constructors. */
+ if (cxx_dialect >= cxx20 && TYPE_HAS_USER_CONSTRUCTOR (t))
+ {
+ CLASSTYPE_NON_AGGREGATE (t) = true;
+ if (!CLASSTYPE_NON_LAYOUT_POD_P (t))
+ {
+ /* c++/120012: The C++20 aggregate change affected layout. */
+ if (!abi_version_at_least (21))
+ CLASSTYPE_NON_LAYOUT_POD_P (t) = true;
+ if (abi_version_crosses (21))
+ CLASSTYPE_NON_AGGREGATE_POD (t) = true;
+ }
+ }
+
/* If the only explicitly declared default constructor is user-provided,
set TYPE_HAS_COMPLEX_DFLT. */
if (!TYPE_HAS_COMPLEX_DFLT (t)
@@ -6809,7 +6821,8 @@ end_of_class (tree t, eoc_mode mode)
static void
check_non_pod_aggregate (tree field)
{
- if (!abi_version_crosses (17) || cxx_dialect < cxx14)
+ if ((!abi_version_crosses (17) || cxx_dialect < cxx14)
+ && (!abi_version_crosses (21) || cxx_dialect < cxx20))
return;
if (TREE_CODE (field) != FIELD_DECL
|| (!DECL_FIELD_IS_BASE (field)
@@ -6822,7 +6835,8 @@ check_non_pod_aggregate (tree field)
tree type = TREE_TYPE (field);
if (TYPE_IDENTIFIER (type) == as_base_identifier)
type = TYPE_CONTEXT (type);
- if (!CLASS_TYPE_P (type) || !CLASSTYPE_NON_POD_AGGREGATE (type))
+ if (!CLASS_TYPE_P (type) || (!CLASSTYPE_NON_POD_AGGREGATE (type)
+ && !CLASSTYPE_NON_AGGREGATE_POD (type)))
return;
tree size = end_of_class (type, (DECL_FIELD_IS_BASE (field)
? eoc_nvsize : eoc_nv_or_dsize));
@@ -6831,13 +6845,31 @@ check_non_pod_aggregate (tree field)
{
location_t loc = DECL_SOURCE_LOCATION (next);
if (DECL_FIELD_IS_BASE (next))
- warning_at (loc, OPT_Wabi,"offset of %qT base class for "
- "%<-std=c++14%> and up changes in "
- "%<-fabi-version=17%> (GCC 12)", TREE_TYPE (next));
+ {
+ if (abi_version_crosses (17)
+ && CLASSTYPE_NON_POD_AGGREGATE (type))
+ warning_at (loc, OPT_Wabi,"offset of %qT base class for "
+ "%<-std=c++14%> and up changes in "
+ "%<-fabi-version=17%> (GCC 12)", TREE_TYPE (next));
+ else if (abi_version_crosses (21)
+ && CLASSTYPE_NON_AGGREGATE_POD (type))
+ warning_at (loc, OPT_Wabi,"offset of %qT base class for "
+ "%<-std=c++20%> and up changes in "
+ "%<-fabi-version=21%> (GCC 16)", TREE_TYPE (next));
+ }
else
- warning_at (loc, OPT_Wabi, "offset of %qD for "
- "%<-std=c++14%> and up changes in "
- "%<-fabi-version=17%> (GCC 12)", next);
+ {
+ if (abi_version_crosses (17)
+ && CLASSTYPE_NON_POD_AGGREGATE (type))
+ warning_at (loc, OPT_Wabi, "offset of %qD for "
+ "%<-std=c++14%> and up changes in "
+ "%<-fabi-version=17%> (GCC 12)", next);
+ else if (abi_version_crosses (21)
+ && CLASSTYPE_NON_AGGREGATE_POD (type))
+ warning_at (loc, OPT_Wabi, "offset of %qD for "
+ "%<-std=c++20%> and up changes in "
+ "%<-fabi-version=21%> (GCC 16)", next);
+ }
}
}
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 856202c..af51d67 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -2491,6 +2491,7 @@ struct GTY(()) lang_type {
unsigned unique_obj_representations_set : 1;
bool erroneous : 1;
bool non_pod_aggregate : 1;
+ bool non_aggregate_pod : 1;
/* When adding a flag here, consider whether or not it ought to
apply to a template instance if it applies to the template. If
@@ -2499,7 +2500,7 @@ struct GTY(()) lang_type {
/* There are some bits left to fill out a 32-bit word. Keep track
of this by updating the size of this bitfield whenever you add or
remove a flag. */
- unsigned dummy : 3;
+ unsigned dummy : 2;
tree primary_base;
vec<tree_pair_s, va_gc> *vcall_indices;
@@ -2826,6 +2827,11 @@ struct GTY(()) lang_type {
with a hash_set only filled in when abi_version_crosses (17). */
#define CLASSTYPE_NON_POD_AGGREGATE(NODE) \
(LANG_TYPE_CLASS_CHECK (NODE)->non_pod_aggregate)
+
+/* True if this class is layout-POD though it's not an aggregate in C++20 and
+ above (c++/120012). This could also be a hash_set. */
+#define CLASSTYPE_NON_AGGREGATE_POD(NODE) \
+ (LANG_TYPE_CLASS_CHECK (NODE)->non_aggregate_pod)
/* Additional macros for inheritance information. */
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index e7a9a03..32bc457 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -3015,7 +3015,8 @@ Version 20, which first appeared in G++ 15, fixes manglings of lambdas
in static data member initializers.
Version 21, which first appeared in G++ 16, fixes unnecessary captures
-in noexcept lambdas (c++/119764).
+in noexcept lambdas (c++/119764) and layout of a base class
+with all explicitly defaulted constructors (c++/120012).
See also @option{-Wabi}.
diff --git a/gcc/testsuite/g++.dg/abi/base-defaulted1.C b/gcc/testsuite/g++.dg/abi/base-defaulted1.C
new file mode 100644
index 0000000..aaada72
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/base-defaulted1.C
@@ -0,0 +1,19 @@
+// PR c++/120012
+// { dg-do compile { target c++11 } }
+// { dg-additional-options "-fabi-version=21 -Wabi=20" }
+
+struct A
+{
+ A(const A&) = default;
+ A(A&&) = default;
+ A& operator=(A&&) = default;
+ unsigned int a;
+ unsigned char b;
+};
+struct B: A
+{
+ unsigned char c; // { dg-warning "offset" "" { target c++20 } }
+};
+
+static_assert(sizeof(A) == (2 * sizeof(unsigned int)), "");
+static_assert(sizeof(B) == (3 * sizeof(unsigned int)), "");
diff --git a/gcc/testsuite/g++.dg/abi/base-defaulted1a.C b/gcc/testsuite/g++.dg/abi/base-defaulted1a.C
new file mode 100644
index 0000000..d61eb39
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/base-defaulted1a.C
@@ -0,0 +1,23 @@
+// PR c++/120012
+// { dg-do compile { target c++11 } }
+// { dg-additional-options "-fabi-version=20 -Wabi" }
+
+struct A
+{
+ A(const A&) = default;
+ A(A&&) = default;
+ A& operator=(A&&) = default;
+ unsigned int a;
+ unsigned char b;
+};
+struct B: A
+{
+ unsigned char c; // { dg-warning "offset" "" { target c++20 } }
+};
+
+static_assert(sizeof(A) == (2 * sizeof(unsigned int)), "");
+#if __cplusplus >= 202002L
+static_assert(sizeof(B) == (2 * sizeof(unsigned int)), "");
+#else
+static_assert(sizeof(B) == (3 * sizeof(unsigned int)), "");
+#endif