aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/common.opt2
-rw-r--r--gcc/cp/mangle.cc51
-rw-r--r--gcc/doc/invoke.texi5
-rw-r--r--gcc/testsuite/g++.dg/abi/mangle82.C85
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/nontype-class73.C30
5 files changed, 171 insertions, 2 deletions
diff --git a/gcc/common.opt b/gcc/common.opt
index 70659fa..bf38f60 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -1067,6 +1067,8 @@ Driver Undocumented
;
; 21: Fix noexcept lambda capture pruning.
; Fix C++20 layout of base with all explicitly defaulted constructors.
+; Fix mangling of class and array objects with implicitly
+; zero-initialized non-trailing subojects.
; Default in G++ 16.
;
; Additional positive integers will be assigned as new versions of
diff --git a/gcc/cp/mangle.cc b/gcc/cp/mangle.cc
index 13d5ded..fd69099 100644
--- a/gcc/cp/mangle.cc
+++ b/gcc/cp/mangle.cc
@@ -3745,11 +3745,59 @@ write_expression (tree expr)
|| !zero_init_expr_p (ce->value))
last_nonzero = i;
+ tree prev_field = NULL_TREE;
if (undigested || last_nonzero != UINT_MAX)
for (HOST_WIDE_INT i = 0; vec_safe_iterate (elts, i, &ce); ++i)
{
if (i > last_nonzero)
break;
+ if (!undigested && !CONSTRUCTOR_NO_CLEARING (expr)
+ && (TREE_CODE (etype) == RECORD_TYPE
+ || TREE_CODE (etype) == ARRAY_TYPE))
+ {
+ /* Write out any implicit non-trailing zeros
+ (which we neglected to do before v21). */
+ if (TREE_CODE (etype) == RECORD_TYPE)
+ {
+ tree field;
+ if (i == 0)
+ field = first_field (etype);
+ else
+ field = DECL_CHAIN (prev_field);
+ for (;;)
+ {
+ field = next_subobject_field (field);
+ if (field == ce->index)
+ break;
+ if (abi_check (21))
+ write_expression (build_zero_cst
+ (TREE_TYPE (field)));
+ field = DECL_CHAIN (field);
+ }
+ }
+ else if (TREE_CODE (etype) == ARRAY_TYPE)
+ {
+ unsigned HOST_WIDE_INT j;
+ if (i == 0)
+ j = 0;
+ else
+ j = 1 + tree_to_uhwi (prev_field);
+ unsigned HOST_WIDE_INT k;
+ if (TREE_CODE (ce->index) == RANGE_EXPR)
+ k = tree_to_uhwi (TREE_OPERAND (ce->index, 0));
+ else
+ k = tree_to_uhwi (ce->index);
+ tree zero = NULL_TREE;
+ for (; j < k; ++j)
+ if (abi_check (21))
+ {
+ if (!zero)
+ zero = build_zero_cst (TREE_TYPE (etype));
+ write_expression (zero);
+ }
+ }
+ }
+
if (!undigested && TREE_CODE (etype) == UNION_TYPE)
{
/* Express the active member as a designator. */
@@ -3794,6 +3842,9 @@ write_expression (tree expr)
else
for (unsigned j = 0; j < reps; ++j)
write_expression (ce->value);
+ prev_field = ce->index;
+ if (prev_field && TREE_CODE (prev_field) == RANGE_EXPR)
+ prev_field = TREE_OPERAND (prev_field, 1);
}
}
else
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index bc5b3e0..00468a7 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -3016,8 +3016,9 @@ 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) and layout of a base class
-with all explicitly defaulted constructors (c++/120012).
+in noexcept lambdas (c++/119764), layout of a base class with all explicitly
+defaulted constructors (c++/120012), and mangling of class and array
+objects with implicitly zero-initialized non-trailing subobjects (c++/121231).
See also @option{-Wabi}.
diff --git a/gcc/testsuite/g++.dg/abi/mangle82.C b/gcc/testsuite/g++.dg/abi/mangle82.C
new file mode 100644
index 0000000..39dd581
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/mangle82.C
@@ -0,0 +1,85 @@
+// Test mangling of C++20 class NTTP objects with implicitly zeroed
+// non-trailing subojects.
+// PR c++/121231
+// { dg-do compile { target c++20 } }
+
+struct A {
+ int x, y, z;
+
+ static constexpr A make(int x, int y, int z) {
+ A a{};
+ if (x != 0)
+ a.x = x;
+ if (y != 0)
+ a.y = y;
+ if (z != 0)
+ a.z = z;
+ return a;
+ }
+};
+
+struct B : A {
+ int w;
+
+ static constexpr B make(int x, int y, int z, int w) {
+ B b{};
+ if (x != 0 || y != 0 || z != 0)
+ static_cast<A&>(b) = A::make(x, y, z);
+ if (w != 0)
+ b.w = w;
+ return b;
+ }
+};
+
+struct C {
+ int xyz[3];
+
+ static constexpr C make(int x, int y, int z) {
+ C c{};
+ if (x != 0)
+ c.xyz[0] = x;
+ if (y != 0)
+ c.xyz[1] = y;
+ if (z != 0)
+ c.xyz[2] = z;
+ return c;
+ }
+};
+
+template<int N, A a> void f();
+template<int N, B b> void g();
+template<int N, C c> void h();
+
+int main() {
+ f<0, A::make(0, 0, 1)>(); // void f<0, A{0, 0, 1}>()
+ f<1, A::make(0, 1, 0)>(); // void f<1, A{0, 1}>()
+ f<2, A::make(0, 0, 0)>(); // void f<2, A{}>()
+ f<3, A::make(1, 0, 1)>(); // void f<3, A{1, 0, 1}>()
+
+ g<0, B::make(0, 0, 0, 1)>(); // void g<0, B{A{}, 1}>()
+ g<1, B::make(0, 0, 1, 0)>(); // void g<1, B{A{0, 0, 1}}>()
+ g<2, B::make(0, 1, 0, 0)>(); // void g<2, B{A{0, 1}}>()
+ g<3, B::make(0, 0, 0, 0)>(); // void g<3, B{}>()
+ g<4, B::make(1, 0, 1, 0)>(); // void g<4, B{A{1, 0, 1}}>()
+
+ h<0, C::make(0, 0, 1)>(); // void h<0, C{int [3]{0, 0, 1}}>()
+ h<1, C::make(0, 1, 0)>(); // void h<1, C{int [3]{0, 1}}>()
+ h<2, C::make(0, 0, 0)>(); // void h<2, C{}>()
+ h<3, C::make(1, 0, 1)>(); // void h<3, C{int [3]{1, 0, 1}}>()
+}
+
+// { dg-final { scan-assembler "_Z1fILi0EXtl1ALi0ELi0ELi1EEEEvv" } }
+// { dg-final { scan-assembler "_Z1fILi1EXtl1ALi0ELi1EEEEvv" } }
+// { dg-final { scan-assembler "_Z1fILi2EXtl1AEEEvv" } }
+// { dg-final { scan-assembler "_Z1fILi3EXtl1ALi1ELi0ELi1EEEEvv" } }
+
+// { dg-final { scan-assembler "_Z1gILi0EXtl1Btl1AELi1EEEEvv" } }
+// { dg-final { scan-assembler "_Z1gILi1EXtl1Btl1ALi0ELi0ELi1EEEEEvv" } }
+// { dg-final { scan-assembler "_Z1gILi2EXtl1Btl1ALi0ELi1EEEEEvv" } }
+// { dg-final { scan-assembler "_Z1gILi3EXtl1BEEEvv" } }
+// { dg-final { scan-assembler "_Z1gILi4EXtl1Btl1ALi1ELi0ELi1EEEEEvv" } }
+
+// { dg-final { scan-assembler "_Z1hILi0EXtl1CtlA3_iLi0ELi0ELi1EEEEEvv" } }
+// { dg-final { scan-assembler "_Z1hILi1EXtl1CtlA3_iLi0ELi1EEEEEvv" } }
+// { dg-final { scan-assembler "_Z1hILi2EXtl1CEEEvv" } }
+// { dg-final { scan-assembler "_Z1hILi3EXtl1CtlA3_iLi1ELi0ELi1EEEEEvv" } }
diff --git a/gcc/testsuite/g++.dg/cpp2a/nontype-class73.C b/gcc/testsuite/g++.dg/cpp2a/nontype-class73.C
new file mode 100644
index 0000000..7f27cad
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/nontype-class73.C
@@ -0,0 +1,30 @@
+// PR c++/119688
+// { dg-do compile { target c++20 } }
+
+template<int N>
+struct builder {
+ bool value[256]{};
+ constexpr builder(char const (&s)[N]) {
+ for(int i = 0 ; i < N; ++i)
+ value[static_cast<unsigned char>(s[i])] = true;
+ }
+};
+
+template<builder A>
+constexpr auto operator""_ar() {
+ return A.value;
+}
+
+constexpr auto first = "ab"_ar;
+static_assert( first['a']);
+static_assert( first['b']);
+static_assert(!first['c']);
+static_assert(!first['d']);
+static_assert(!first['z']);
+
+constexpr auto second = "cd"_ar;
+static_assert(!second['a']);
+static_assert(!second['b']);
+static_assert(!second['z']);
+static_assert( second['c']);
+static_assert( second['d']);