PR c++/89974 - ICE on a definition of a non-type specialization on a struct object with pointer to member function
PR c++/89878 - same specializations on a zero-initialized struct object as a non-type parameter treated as distinct
PR c++/89833 - sorry, unimplemented: string literal in function template signature
PR c++/47488 - sorry, unimplemented: string literal in function template signature
gcc/cp/ChangeLog:
PR c++/89974
PR c++/89878
PR c++/89833
PR c++/47488
* decl.c (reshape_init_array_1): Strip trailing zero-initializers
from arrays of trivial type and known size.
* mangle.c (write_expression): Convert braced initializer lists
to STRING_CSTs.
(write_expression): Trim trailing zero-initializers from arrays
of trivial type.
(write_template_arg_literal): Mangle strings the same as braced
initializer lists.
gcc/testsuite/ChangeLog:
PR c++/89974
PR c++/89878
PR c++/89833
PR c++/47488
* gcc/testsuite/g++.dg/abi/mangle69.C: New test.
* gcc/testsuite/g++.dg/abi/mangle70.C: New test.
* gcc/testsuite/g++.dg/abi/mangle71.C: New test.
* gcc/testsuite/g++.dg/abi/mangle72.C: New test.
* gcc/testsuite/g++.dg/cpp0x/constexpr-array19.C: New test.
* gcc/testsuite/g++.dg/cpp2a/nontype-class15.C: New test.
* gcc/testsuite/g++.dg/cpp2a/nontype-class16.C: New test.
* gcc/testsuite/g++.dg/init/array51.C: New test.
From-SVN: r270155
+2019-04-04 Martin Sebor <msebor@redhat.com>
+
+ PR c++/89974
+ PR c++/89878
+ PR c++/89833
+ PR c++/47488
+ * decl.c (reshape_init_array_1): Strip trailing zero-initializers
+ from arrays of trivial type and known size.
+ * mangle.c (write_expression): Convert braced initializer lists
+ to STRING_CSTs.
+ (write_expression): Trim trailing zero-initializers from arrays
+ of trivial type.
+ (write_template_arg_literal): Mangle strings the same as braced
+ initializer lists.
+
2019-04-03 Jason Merrill <jason@redhat.com>
PR c++/81866 - ICE with member template and default targ.
max_index_cst = tree_to_uhwi (fold_convert (size_type_node, max_index));
}
+ /* Set to the index of the last element with a non-zero initializer.
+ Initializers for elements past this one can be dropped. */
+ unsigned HOST_WIDE_INT last_nonzero = -1;
/* Loop until there are no more initializers. */
for (index = 0;
d->cur != d->end && (!sized_array_p || index <= max_index_cst);
if (!TREE_CONSTANT (elt_init))
TREE_CONSTANT (new_init) = false;
+ if (!initializer_zerop (elt_init))
+ last_nonzero = index;
+
/* This can happen with an invalid initializer (c++/54501). */
if (d->cur == old_cur && !sized_array_p)
break;
}
+ if (sized_array_p
+ && (!CLASS_TYPE_P (elt_type)
+ || TYPE_HAS_TRIVIAL_DFLT (elt_type)))
+ {
+ /* Strip trailing zero-initializers from an array of a trivial
+ type of known size. They are redundant and get in the way
+ of telling them apart from those with implicit zero value. */
+ unsigned HOST_WIDE_INT nelts = CONSTRUCTOR_NELTS (new_init);
+ if (last_nonzero > nelts)
+ nelts = 0;
+ else if (last_nonzero < nelts - 1)
+ nelts = last_nonzero + 1;
+
+ vec_safe_truncate (CONSTRUCTOR_ELTS (new_init), nelts);
+ }
+
return new_init;
}
}
else if (code == CONSTRUCTOR)
{
- vec<constructor_elt, va_gc> *elts = CONSTRUCTOR_ELTS (expr);
- unsigned i; tree val;
+ bool braced_init = BRACE_ENCLOSED_INITIALIZER_P (expr);
+ tree etype = TREE_TYPE (expr);
- if (BRACE_ENCLOSED_INITIALIZER_P (expr))
+ if (braced_init)
write_string ("il");
else
{
write_string ("tl");
- write_type (TREE_TYPE (expr));
+ write_type (etype);
+ }
+
+ if (!initializer_zerop (expr) || !trivial_type_p (etype))
+ {
+ /* Convert braced initializer lists to STRING_CSTs so that
+ A<"Foo"> mangles the same as A<{'F', 'o', 'o', 0}> while
+ still using the latter mangling for strings that
+ originated as braced initializer lists. */
+ expr = braced_lists_to_strings (etype, expr);
+
+ if (TREE_CODE (expr) == CONSTRUCTOR)
+ {
+ vec<constructor_elt, va_gc> *elts = CONSTRUCTOR_ELTS (expr);
+ unsigned last_nonzero = -1, i;
+ tree val;
+
+ FOR_EACH_CONSTRUCTOR_VALUE (elts, i, val)
+ if (!initializer_zerop (val))
+ last_nonzero = i;
+
+ FOR_EACH_CONSTRUCTOR_VALUE (elts, i, val)
+ {
+ if (i > last_nonzero)
+ break;
+ write_expression (val);
+ }
+ }
+ else
+ {
+ gcc_assert (TREE_CODE (expr) == STRING_CST);
+ write_expression (expr);
+ }
}
- FOR_EACH_CONSTRUCTOR_VALUE (elts, i, val)
- write_expression (val);
write_char ('E');
}
else if (code == LAMBDA_EXPR)
static void
write_template_arg_literal (const tree value)
{
- write_char ('L');
- write_type (TREE_TYPE (value));
+ if (TREE_CODE (value) == STRING_CST)
+ /* Temporarily mangle strings as braced initializer lists. */
+ write_string ("tl");
+ else
+ write_char ('L');
+
+ tree valtype = TREE_TYPE (value);
+ write_type (valtype);
/* Write a null member pointer value as (type)0, regardless of its
real representation. */
break;
case STRING_CST:
- sorry ("string literal in function template signature");
- break;
+ {
+ /* Mangle strings the same as braced initializer lists. */
+ unsigned n = TREE_STRING_LENGTH (value);
+ const char *str = TREE_STRING_POINTER (value);
+
+ /* Count the number of trailing nuls and subtract them from
+ STRSIZE because they don't need to be mangled. */
+ for (const char *p = str + n - 1; ; --p)
+ {
+ if (*p || p == str)
+ {
+ n -= str + n - !!*p - p;
+ break;
+ }
+ }
+ tree eltype = TREE_TYPE (valtype);
+ for (const char *p = str; n--; ++p)
+ {
+ write_char ('L');
+ write_type (eltype);
+ write_unsigned_number (*(const unsigned char*)p);
+ write_string ("E");
+ }
+ break;
+ }
default:
gcc_unreachable ();
+2019-04-04 Martin Sebor <msebor@redhat.com>
+
+ PR c++/89974
+ PR c++/89878
+ PR c++/89833
+ PR c++/47488
+ * gcc/testsuite/g++.dg/abi/mangle69.C: New test.
+ * gcc/testsuite/g++.dg/abi/mangle70.C: New test.
+ * gcc/testsuite/g++.dg/abi/mangle71.C: New test.
+ * gcc/testsuite/g++.dg/abi/mangle72.C: New test.
+ * gcc/testsuite/g++.dg/cpp0x/constexpr-array19.C: New test.
+ * gcc/testsuite/g++.dg/cpp2a/nontype-class15.C: New test.
+ * gcc/testsuite/g++.dg/cpp2a/nontype-class16.C: New test.
+ * gcc/testsuite/g++.dg/init/array51.C: New test.
+ * gcc/testsuite/g++.dg/template/nontype29.C: New test.
+
2019-04-04 Martin Sebor <msebor@redhat.com>
PR middle-end/89957
--- /dev/null
+// { dg-do compile { target c++2a } }
+
+struct A1 { char c[5]; };
+
+template <A1> struct B { };
+
+// All of the following name the same type.
+typedef B<A1{ }> A______;
+typedef B<A1{ { 0 } }> A_Z____;
+typedef B<A1{ { 0, 0 } }> A_ZZ___;
+typedef B<A1{ { 0, 0, 0 } }> A_ZZZ__;
+typedef B<A1{ { 0, 0, 0, 0 } }> A_ZZZZ_;
+typedef B<A1{ { 0, 0, 0, 0, 0 } }> A_ZZZZZ;
+
+// Verify that the types mangle the same.
+void a______ (A______) { }
+// { dg-final { scan-assembler "_Z7a______1BIXtl2A1EEE" } }
+
+void a_z____ (A_Z____) { }
+// { dg-final { scan-assembler "_Z7a_z____1BIXtl2A1EEE" } }
+
+void a_zz___ (A_ZZ___) { }
+// { dg-final { scan-assembler "_Z7a_zz___1BIXtl2A1EEE" } }
+
+void a_zzz__ (A_ZZZ__) { }
+// { dg-final { scan-assembler "_Z7a_zzz__1BIXtl2A1EEE" } }
+
+void a_zzzz_ (A_ZZZZ_) { }
+// { dg-final { scan-assembler "_Z7a_zzzz_1BIXtl2A1EEE" } }
+
+void a_zzzzz (A_ZZZZZ) { }
+// { dg-final { scan-assembler "_Z7a_zzzzz1BIXtl2A1EEE" } }
+
+
+// All of the following use a string to initialize the array but
+// also name the same type as the above.
+typedef B<A1{ "" }> S_z____;
+typedef B<A1{ "\0" }> S_Zz___;
+typedef B<A1{ "\0\0" }> S_ZZz__;
+typedef B<A1{ "\0\0\0" }> S_ZZZz_;
+typedef B<A1{ "\0\0\0\0" }> S_ZZZZz;
+
+// Verify that the types mangle the same.
+void s_z____ (S_z____) { }
+// { dg-final { scan-assembler "_Z7s_z____1BIXtl2A1EEE" } }
+
+void s_Zz___ (S_Zz___) { }
+// { dg-final { scan-assembler "_Z7s_Zz___1BIXtl2A1EEE" } }
+
+void s_ZZz__ (S_ZZz__) { }
+// { dg-final { scan-assembler "_Z7s_ZZz__1BIXtl2A1EEE" } }
+
+void s_ZZZz_ (S_ZZZz_) { }
+// { dg-final { scan-assembler "_Z7s_ZZZz_1BIXtl2A1EEE" } }
+
+void s_ZZZZz (S_ZZZZz) { }
+// { dg-final { scan-assembler "_Z7s_ZZZZz1BIXtl2A1EEE" } }
+
+
+// All of the following also name the same type (distinct from
+// the above).
+typedef B<A1{ { 'A' } }> A_A____;
+typedef B<A1{ { 'A', 0 } }> A_AZ___;
+typedef B<A1{ { 'A', 0, 0 } }> A_AZZ__;
+typedef B<A1{ { 'A', 0, 0, 0 } }> A_AZZZ_;
+typedef B<A1{ { 'A', 0, 0, 0, 0 } }> A_AZZZZ;
+
+void a_A____ (A_A____) { }
+// { dg-final { scan-assembler "_Z7a_A____1BIXtl2A1tlA5_cLc65EEEEE" } }
+
+void a_AZ___ (A_AZ___) { }
+// { dg-final { scan-assembler "_Z7a_AZ___1BIXtl2A1tlA5_cLc65EEEEE" } }
+
+void a_AZZ__ (A_AZZ__) { }
+// { dg-final { scan-assembler "_Z7a_AZZ__1BIXtl2A1tlA5_cLc65EEEEE" } }
+
+void a_AZZZ_ (A_AZZZ_) { }
+// { dg-final { scan-assembler "_Z7a_AZZZ_1BIXtl2A1tlA5_cLc65EEEEE" } }
+
+void a_AZZZZ (A_AZZZZ) { }
+// { dg-final { scan-assembler "_Z7a_AZZZZ1BIXtl2A1tlA5_cLc65EEEEE" } }
+
+
+typedef B<A1{ "A" }> S_Az___;
+typedef B<A1{ "A\0" }> S_AZz__;
+typedef B<A1{ "A\0\0" }> S_AZZz_;
+typedef B<A1{ "A\0\0\0" }> S_AZZZz;
+
+void s_Az___ (S_Az___) { }
+// { dg-final { scan-assembler "_Z7s_Az___1BIXtl2A1tlA5_cLc65EEEEE" } }
+
+void s_AZz__ (S_AZz__) { }
+// { dg-final { scan-assembler "_Z7s_AZz__1BIXtl2A1tlA5_cLc65EEEEE" } }
+
+void s_AZZz_ (S_AZZz_) { }
+// { dg-final { scan-assembler "_Z7s_AZZz_1BIXtl2A1tlA5_cLc65EEEEE" } }
+
+void s_AZZZz (S_AZZZz) { }
+// { dg-final { scan-assembler "_Z7s_AZZZz1BIXtl2A1tlA5_cLc65EEEEE" } }
+
+
+typedef B<A1{ 'A', 0, 0, 'D', 0 }> A_AZZDZ;
+typedef B<A1{ 'A', 0, 0, 'D' }> A_AZZD_;
+
+void a_AZZDZ (A_AZZDZ) { }
+// { dg-final { scan-assembler "_Z7a_AZZD_1BIXtl2A1tlA5_cLc65ELc0ELc0ELc68EEEEE" } }
+
+void a_AZZD_ (A_AZZD_) { }
+// { dg-final { scan-assembler "_Z7a_AZZDZ1BIXtl2A1tlA5_cLc65ELc0ELc0ELc68EEEEE" } }
+
+
+typedef B<A1{ { "AB\0D" } }> S_ABZD_;
+typedef B<A1{ { "AB\0\0" } }> S_ABZZ_;
+typedef B<A1{ { "AB\0" } }> S_ABZ__;
+typedef B<A1{ { "AB" } }> S_AB___;
+
+void s_abzd_ (S_ABZD_) { }
+// { dg-final { scan-assembler "_Z7s_abzd_1BIXtl2A1tlA5_cLc65ELc66ELc0ELc68EEEEE" } }
+
+void s_abzz_ (S_ABZZ_) { }
+// { dg-final { scan-assembler "_Z7s_abzz_1BIXtl2A1tlA5_cLc65ELc66EEEEE" } }
+
+void s_abz__ (S_ABZ__) { }
+// { dg-final { scan-assembler "_Z7s_abz__1BIXtl2A1tlA5_cLc65ELc66EEEEE" } }
+
+void s_ab___ (S_AB___) { }
+// { dg-final { scan-assembler "_Z7s_ab___1BIXtl2A1tlA5_cLc65ELc66EEEEE" } }
+
+
+struct A3 { char a[5], b[5], c[5]; };
+template <A3> struct B3 { };
+
+/* These all name the same type. */
+typedef B3<A3{ "\1\2", { }, "\3\4\5\6" }> T_123z_______3456z;
+typedef B3<A3{ "\1\2", { 0 }, "\3\4\5\6" }> T_123z__Z____3456z;
+typedef B3<A3{ "\1\2", { 0, 0 }, "\3\4\5\6" }> T_123z__ZZ___3456z;
+typedef B3<A3{ "\1\2", { 0, 0, 0 }, "\3\4\5\6" }> T_123z__ZZZ__3456z;
+typedef B3<A3{ "\1\2", { 0, 0, 0, 0 }, "\3\4\5\6" }> T_123z__ZZZZ_3456z;
+typedef B3<A3{ "\1\2", "", "\3\4\5\6" }> T_123z__Z____3456z;
+typedef B3<A3{ "\1\2", "\0", "\3\4\5\6" }> T_123z__ZZ___3456z;
+typedef B3<A3{ "\1\2", "\0\0", "\3\4\5\6" }> T_123z__ZZZ__3456z;
+typedef B3<A3{ "\1\2", "\0\0\0", "\3\4\5\6" }> T_123z__ZZZZ_3456z;
+typedef B3<A3{ "\1\2", "\0\0\0\0", "\3\4\5\6" }> T_123z__ZZZZZ3456z;
+typedef B3<A3{ "\1\2\0", "\0\0\0\0", "\3\4\5\6" }> T_123Zz_ZZZZZ3456z;
+typedef B3<A3{ "\1\2\0\0", "\0\0\0\0", "\3\4\5\6" }> T_123ZZzZZZZZ3456z;
+
+
+void ft0 (T_123z_______3456z) { }
+// { dg-final { scan-assembler "_Z3ft02B3IXtl2A3tlA5_cLc1ELc2EEtlS1_EtlS1_Lc3ELc4ELc5ELc6EEEEE" } }
+
+void ft1 (T_123z__Z____3456z) { }
+// { dg-final { scan-assembler "_Z3ft12B3IXtl2A3tlA5_cLc1ELc2EEtlS1_EtlS1_Lc3ELc4ELc5ELc6EEEEE" } }
+void ft2 (T_123z__ZZ___3456z) { }
+// { dg-final { scan-assembler "_Z3ft22B3IXtl2A3tlA5_cLc1ELc2EEtlS1_EtlS1_Lc3ELc4ELc5ELc6EEEEE" } }
+void ft3 (T_123z__ZZZ__3456z) { }
+// { dg-final { scan-assembler "_Z3ft32B3IXtl2A3tlA5_cLc1ELc2EEtlS1_EtlS1_Lc3ELc4ELc5ELc6EEEEE" } }
+void ft4 (T_123z__ZZZZ_3456z) { }
+// { dg-final { scan-assembler "_Z3ft42B3IXtl2A3tlA5_cLc1ELc2EEtlS1_EtlS1_Lc3ELc4ELc5ELc6EEEEE" } }
+void ft9 (T_123z__ZZZZZ3456z) { }
+// { dg-final { scan-assembler "_Z3ft92B3IXtl2A3tlA5_cLc1ELc2EEtlS1_EtlS1_Lc3ELc4ELc5ELc6EEEEE" } }
+void fta (T_123Zz_ZZZZZ3456z) { }
+// { dg-final { scan-assembler "_Z3fta2B3IXtl2A3tlA5_cLc1ELc2EEtlS1_EtlS1_Lc3ELc4ELc5ELc6EEEEE" } }
+void ftb (T_123ZZzZZZZZ3456z) { }
+// { dg-final { scan-assembler "_Z3ftb2B3IXtl2A3tlA5_cLc1ELc2EEtlS1_EtlS1_Lc3ELc4ELc5ELc6EEEEE" } }
--- /dev/null
+// Verify that class literals are mangled the same way regardless
+// of the underlying type.
+// { dg-do compile { target c++2a } }
+
+struct I { int a[5], b[5], c[5]; };
+template <I> struct X { };
+
+typedef X<I{ {1,2}, {}, {11,12,13,14} }> Ti;
+void f (Ti) { }
+// { dg-final { scan-assembler "_Z1f1XIXtl1ItlA5_iLi1ELi2EEtlS1_EtlS1_Li11ELi12ELi13ELi14EEEEE" } }
+
+struct C { char a[5], b[5], c[5]; };
+template <C> struct Y { };
+
+typedef Y<C{ {1,2}, {}, {11,12,13,14} }> Tca;
+void g (Tca) { }
+// { dg-final { scan-assembler "_Z1g1YIXtl1CtlA5_cLc1ELc2EEtlS1_EtlS1_Lc11ELc12ELc13ELc14EEEEE" } }
+
+typedef Y<C{ "\1\2", "", {11,12,13,14} }> Tcs;
+void h (Tcs) { }
+// { dg-final { scan-assembler "_Z1h1YIXtl1CtlA5_cLc1ELc2EEtlS1_EtlS1_Lc11ELc12ELc13ELc14EEEEE" } }
+
+struct S { signed char a[5], b[5], c[5]; };
+template <S> struct Z { };
+
+typedef Z<S{ {1,2}, {}, {11,12,13,14} }> Tsc;
+
+void i (Tsc) { }
+// { dg-final { scan-assembler "_Z1i1ZIXtl1StlA5_aLa1ELa2EEtlS1_EtlS1_La11ELa12ELa13ELa14EEEEE" } }
--- /dev/null
+// Verify manglinng of class literals of types with ctors.
+// { dg-do compile { target c++2a } }
+
+struct A
+{
+ char i;
+ constexpr A (): i (1) { }
+ constexpr A (int i): i (i) { }
+};
+
+struct B { A a[3]; };
+
+template <B> struct X { };
+
+void f___ (X<B{{ }}>) { }
+// { dg-final { scan-assembler "_Z4f___1XIXtl1BtlA3_1AtlS1_Lc1EEEEEE" } }
+
+void f0__ (X<B{{ 0 }}>) { }
+// { dg-final { scan-assembler "_Z4f0__1XIXtl1BtlA3_1AtlS1_Lc0EEtlS1_Lc1EEEEEE" } }
+
+void f00_ (X<B{{ 0, 0 }}>) { }
+// { dg-final { scan-assembler "_Z4f00_1XIXtl1BtlA3_1AtlS1_Lc0EEtlS1_Lc0EEtlS1_Lc1EEEEEE" } }
+
+void f000 (X<B{{ 0, 0, 0 }}>) { }
+// { dg-final { scan-assembler "_Z4f0001XIXtl1BtlA3_1AtlS1_Lc0EEtlS1_Lc0EEtlS1_Lc0EEEEEE" } }
+
+void f1__ (X<B{{ 1 }}>) { }
+// { dg-final { scan-assembler "_Z4f1__1XIXtl1BtlA3_1AtlS1_Lc1EEtlS1_Lc1EEEEEE" } }
--- /dev/null
+// Verify manglinng of class literals with pointers to members.
+// Some of the mangling here is wrong. Note the FIXME comments below.
+// { dg-do compile { target c++2a } }
+
+struct A { int a[2]; };
+
+template <A> struct X { };
+
+// Let's mangle some non-member pointer literals for comparison.
+void f__ (X<A{{ }}>) { }
+// { dg-final { scan-assembler "_Z3f001XIXtl1AEEE" } }
+
+void f0_ (X<A{{ 0 }}>) { }
+// { dg-final { scan-assembler "_Z3f0_1XIXtl1AEEE" } }
+
+void f00 (X<A{{ 0, 0 }}>) { }
+// { dg-final { scan-assembler "_Z3f__1XIXtl1AEEE" } }
+
+
+// Exercise arrays of pointers to data members.
+typedef int (A::*padm_t)[2];
+
+struct B { padm_t a[2]; };
+template <B> struct Y { };
+
+void g__ (Y<B{{ }}>) { }
+// { dg-final { scan-assembler "_Z3g__1YIXtl1BtlA2_M1AA2_iLS3_0EEEEE" } }
+
+void g0_ (Y<B{{ 0 }}>) { }
+// { dg-final { scan-assembler "_Z3g0_1YIXtl1BtlA2_M1AA2_iLS3_0EEEEE" } }
+
+void g00 (Y<B{{ 0, 0 }}>) { }
+// { dg-final { scan-assembler "_Z3g001YIXtl1BtlA2_M1AA2_iLS3_0EEEEE" } }
+
+void g0x (Y<B{{ 0, &A::a }}>) { }
+// FIXME: This needs to mangle differently from g00. The space at
+// the end is intentional to make the directive fail so that the xfail
+// can be reminder to change this once the mangling is fixed.
+// { dg-final { scan-assembler "_Z3g0x1YIXtl1BtlA2_M1AA2_iLS3_0EEEEE " { xfail *-*-* } } }
+
+void gx_ (Y<B{{ &A::a }}>) { }
+// { dg-final { scan-assembler "_Z3gx_1YIXtl1BtlA2_M1AA2_iLS3_0ELS3_0EEEEE" } }
+
+
+struct C { padm_t a[3]; };
+template <C> struct Z { };
+
+void h___ (Z<C{{ }}>) { }
+// { dg-final { scan-assembler "_Z4h___1ZIXtl1CtlA3_M1AA2_iLS3_0EEEEE" } }
+
+void h0__ (Z<C{{ 0 }}>) { }
+// { dg-final { scan-assembler "_Z4h0__1ZIXtl1CtlA3_M1AA2_iLS3_0EEEEE" } }
+
+void h00_ (Z<C{{ 0, 0 }}>) { }
+// { dg-final { scan-assembler "_Z4h00_1ZIXtl1CtlA3_M1AA2_iLS3_0EEEEE" } }
+
+void h000 (Z<C{{ 0, 0, 0 }}>) { }
+// { dg-final { scan-assembler "_Z4h0001ZIXtl1CtlA3_M1AA2_iLS3_0EEEEE" } }
+
+void h00x (Z<C{{ 0, 0, &A::a }}>) { }
+// FIXME: This needs to mangle differently from hx0_ and hx__.
+// { dg-final { scan-assembler "_Z4h00x1ZIXtl1CtlA3_M1AA2_iLS3_0ELS3_0EEEEE " { xfail *-*-*} } }
+
+void h0x0 (Z<C{{ 0, &A::a, 0 }}>) { }
+// { dg-final { scan-assembler "_Z4h0x01ZIXtl1CtlA3_M1AA2_iLS3_0ELS3_0ELS3_0EEEEE" } }
+
+void h0x_ (Z<C{{ 0, &A::a }}>) { }
+// { dg-final { scan-assembler "_Z4h0x_1ZIXtl1CtlA3_M1AA2_iLS3_0ELS3_0ELS3_0EEEEE" } }
+
+void hx0_ (Z<C{{ &A::a, 0 }}>) { }
+// FIXME: This needs to mangle differently from h00x and hx__.
+// { dg-final { scan-assembler "_Z4hx0_1ZIXtl1CtlA3_M1AA2_iLS3_0ELS3_0EEEEE " { xfail *-*-*} } }
+
+void hx__ (Z<C{{ &A::a }}>) { }
+// FIXME: This needs to mangle differently from h00x and hx0_.
+// { dg-final { scan-assembler "_Z4hx__1ZIXtl1CtlA3_M1AA2_iLS3_0ELS3_0EEEEE " { xfail *-*-* } } }
+
+
+// Exercise arrays of pointers to function members.
+
+struct AF { void f (); };
+typedef void (AF::*pafm_t)();
+
+struct D { pafm_t a[2]; };
+template <D> struct F { };
+
+void k__ (F<D{{ }}>) { }
+// { dg-final { scan-assembler "_Z3k__1FIXtl1DEEE" } }
+
+void k0_ (F<D{{ 0 }}>) { }
+// { dg-final { scan-assembler "_Z3k0_1FIXtl1DEEE" } }
+
+void k00 (F<D{{ 0, 0 }}>) { }
+// { dg-final { scan-assembler "_Z3k001FIXtl1DEEE" } }
+
+void k0x (F<D{{ 0, &AF::f }}>) { }
+// { dg-final { scan-assembler "_Z3k0x1FIXtl1DtlA2_M2AFFvvEtlS3_EtlS3_adL_ZNS1_1fEvEEEEEE" } }
+
+void kx_ (F<D{{ &AF::f }}>) { }
+// { dg-final { scan-assembler "_Z3kx_1FIXtl1DtlA2_M2AFFvvEtlS3_adL_ZNS1_1fEvEEEEEE" } }
+
+void kx0 (F<D{{ &AF::f, 0 }}>) { }
+// { dg-final { scan-assembler "_Z3kx01FIXtl1DtlA2_M2AFFvvEtlS3_adL_ZNS1_1fEvEEEEEE" } }
+
+void kxx (F<D{{ &AF::f, &AF::f }}>) { }
+// { dg-final { scan-assembler "_Z3kxx1FIXtl1DtlA2_M2AFFvvEtlS3_adL_ZNS1_1fEvEEtlS3_adL_ZNS1_1fEvEEEEEE" } }
--- /dev/null
+// PR c++/89833
+// Test to verify that constant array elements initialized to zero
+// evaluate to zero regardless of the form of their initilizer,
+// and irrespective whether it's explicit or implicit.
+
+// { dg-do compile { target c++11 } }
+// { dg-options "-Wall" }
+
+static const char all_zero[1024] = { };
+
+namespace test_int
+{
+constexpr int a[][3] = { { 0, 0 }, { 0 }, { } };
+
+static_assert (sizeof a == sizeof (int) * 3 * 3);
+
+static_assert ( a[0][0] == 0 && a[0][1] == 0 && a[0][2] == 0
+ && a[1][0] == 0 && a[1][1] == 0 && a[1][2] == 0
+ && a[2][0] == 0 && a[2][1] == 0 && a[2][2] == 0);
+
+constexpr int b[3][3] = { { 0, 0 }, { 0 } };
+
+static_assert (sizeof b == sizeof (int) * 3 * 3);
+
+static_assert ( b[0][0] == 0 && b[0][1] == 0 && b[0][2] == 0
+ && b[1][0] == 0 && b[1][1] == 0 && b[1][2] == 0
+ && b[2][0] == 0 && b[2][1] == 0 && b[2][2] == 0);
+
+constexpr int c[3][3] = { { } };
+
+static_assert (sizeof c == sizeof (int) * 3 * 3);
+
+static_assert ( c[0][0] == 0 && c[0][1] == 0 && c[0][2] == 0
+ && c[1][0] == 0 && c[1][1] == 0 && c[1][2] == 0
+ && c[2][0] == 0 && c[2][1] == 0 && c[2][2] == 0);
+
+}
+
+namespace test_char
+{
+constexpr char a[][3] = { { 0, 0 }, { 0 }, { } };
+
+static_assert (sizeof a == sizeof (char) * 3 * 3);
+
+static_assert ( a[0][0] == 0 && a[0][1] == 0 && a[0][2] == 0
+ && a[1][0] == 0 && a[1][1] == 0 && a[1][2] == 0
+ && a[2][0] == 0 && a[2][1] == 0 && a[2][2] == 0);
+
+constexpr char b[3][3] = { { 0, 0 }, { 0 } };
+
+static_assert (sizeof b == sizeof (char) * 3 * 3);
+
+static_assert ( b[0][0] == 0 && b[0][1] == 0 && b[0][2] == 0
+ && b[1][0] == 0 && b[1][1] == 0 && b[1][2] == 0
+ && b[2][0] == 0 && b[2][1] == 0 && b[2][2] == 0);
+
+constexpr char c[3][3] = { { } };
+
+static_assert (sizeof c == sizeof (char) * 3 * 3);
+
+static_assert ( c[0][0] == 0 && c[0][1] == 0 && c[0][2] == 0
+ && c[1][0] == 0 && c[1][1] == 0 && c[1][2] == 0
+ && c[2][0] == 0 && c[2][1] == 0 && c[2][2] == 0);
+}
+
+namespace test_string
+{
+constexpr char a[][3] = { "\0", "", { } };
+
+static_assert (sizeof a == sizeof (char) * 3 * 3);
+
+static_assert ( a[0][0] == 0 && a[0][1] == 0 && a[0][2] == 0
+ && a[1][0] == 0 && a[1][1] == 0 && a[1][2] == 0
+ && a[2][0] == 0 && a[2][1] == 0 && a[2][2] == 0);
+
+constexpr char b[3][3] = { "\0", "" };
+
+static_assert (sizeof b == sizeof (char) * 3 * 3);
+
+static_assert ( b[0][0] == 0 && b[0][1] == 0 && b[0][2] == 0
+ && b[1][0] == 0 && b[1][1] == 0 && b[1][2] == 0
+ && b[2][0] == 0 && b[2][1] == 0 && b[2][2] == 0);
+
+constexpr char c[3][3] = { };
+
+static_assert (sizeof c == sizeof (char) * 3 * 3);
+
+static_assert ( c[0][0] == 0 && c[0][1] == 0 && c[0][2] == 0
+ && c[1][0] == 0 && c[1][1] == 0 && c[1][2] == 0
+ && c[2][0] == 0 && c[2][1] == 0 && c[2][2] == 0);
+}
+
+namespace test_string_member
+{
+struct B { struct A { char a[5]; } a[2]; };
+
+constexpr B b[3] =
+ {
+ /* [0] */
+ {
+ /* a = */
+ {
+ /* a[0] */ { { 0, 0, 0, 0, 0 } },
+ /* a[1] */ { { 0, 0 } }
+ }
+ },
+ /* [1] */
+ {
+ /* a */
+ {
+ /* a[0] */ { "\0\0\0\0" },
+ /* a[0] */ { "" }
+ }
+ },
+ };
+
+static_assert ( b[0].a[0].a[0] == 0
+ && b[0].a[0].a[1] == 0
+ && b[0].a[0].a[2] == 0
+ && b[0].a[0].a[3] == 0
+ && b[0].a[0].a[4] == 0
+ && b[0].a[1].a[0] == 0
+ && b[0].a[1].a[1] == 0
+ && b[0].a[1].a[2] == 0
+ && b[0].a[1].a[3] == 0
+ && b[0].a[1].a[4] == 0
+ && b[1].a[0].a[0] == 0
+ && b[1].a[0].a[1] == 0
+ && b[1].a[0].a[2] == 0
+ && b[1].a[0].a[3] == 0
+ && b[1].a[0].a[4] == 0
+ && b[2].a[0].a[0] == 0
+ && b[2].a[0].a[1] == 0
+ && b[2].a[0].a[2] == 0
+ && b[2].a[0].a[3] == 0
+ && b[2].a[0].a[4] == 0);
+}
--- /dev/null
+// PR c++/89833
+// Test to verify that the same specializations on non-type template
+// parameters of class types are in fact treated as the same.
+// { dg-do compile { target c++2a } }
+
+struct A1 { char c[5]; };
+
+template <A1> struct B { };
+
+// All of the following name the same type.
+typedef B<A1{ }> A______;
+typedef B<A1{ { 0 } }> A_Z____;
+typedef B<A1{ { 0, 0 } }> A_ZZ___;
+typedef B<A1{ { 0, 0, 0 } }> A_ZZZ__;
+typedef B<A1{ { 0, 0, 0, 0 } }> A_ZZZZ_;
+typedef B<A1{ { 0, 0, 0, 0, 0 } }> A_ZZZZZ;
+
+// Verify the types are indeed the same by redeclaring the same identifier
+// of each of them.
+extern A______ same_type_B_A1;
+extern A_Z____ same_type_B_A1;
+extern A_ZZ___ same_type_B_A1;
+extern A_ZZZ__ same_type_B_A1;
+extern A_ZZZZ_ same_type_B_A1;
+extern A_ZZZZZ same_type_B_A1;
+
+
+// All of the following use a string to initialize the array but
+// also name the same type as the above.
+typedef B<A1{ "" }> S_z____;
+typedef B<A1{ "\0" }> S_Zz___;
+typedef B<A1{ "\0\0" }> S_ZZz__;
+typedef B<A1{ "\0\0\0" }> S_ZZZz_;
+typedef B<A1{ "\0\0\0\0" }> S_ZZZZz;
+
+// Verify the types are indeed the same by redeclaring the same identifier
+// of each of them.
+extern S_z____ same_type_B_A1;
+extern S_Zz___ same_type_B_A1;
+extern S_Zz___ same_type_B_A1;
+extern S_ZZz__ same_type_B_A1;
+extern S_ZZZz_ same_type_B_A1;
+extern S_ZZZZz same_type_B_A1;
+
+
+// All of the following also name the same type (distinct from
+// the above).
+typedef B<A1{ { 'A' } }> A_A____;
+typedef B<A1{ { 'A', 0 } }> A_AZ___;
+typedef B<A1{ { 'A', 0, 0 } }> A_AZZ__;
+typedef B<A1{ { 'A', 0, 0, 0 } }> A_AZZZ_;
+typedef B<A1{ { 'A', 0, 0, 0, 0 } }> A_AZZZZ;
+
+extern A_A____ same_type_B_A1_A;
+extern A_AZ___ same_type_B_A1_A;
+extern A_AZZ__ same_type_B_A1_A;
+extern A_AZZZ_ same_type_B_A1_A;
+extern A_AZZZZ same_type_B_A1_A;
+
+
+struct A3 { char a[5], b[5], c[5]; };
+template <A3> struct B3 { };
+
+// These all name the same type.
+typedef B3<A3{ }> B3_A3________________;
+typedef B3<A3{ { } }> B3_A3________________;
+typedef B3<A3{ { }, { } }> B3_A3________________;
+typedef B3<A3{ { }, { }, { } }> B3_A3________________;
+typedef B3<A3{ { 0 }, { }, { } }> B3_A3________________;
+typedef B3<A3{ { 0 }, { 0 }, { } }> B3_A3________________;
+typedef B3<A3{ { 0 }, { 0 }, { 0 } }> B3_A3________________;
+typedef B3<A3{ { 0, 0 }, { 0 }, { 0 } }> B3_A3________________;
+typedef B3<A3{ { 0, 0 }, { 0, 0 }, { 0 } }> B3_A3________________;
+typedef B3<A3{ { 0, 0 }, { 0, 0 }, { 0, 0 } }> B3_A3________________;
+
+// These all name the same type.
+typedef B3<A3{ "AB", { }, "IJKL" }> B3_A3_AB________IJKL_;
+typedef B3<A3{ "AB", { 0 }, "IJKL" }> B3_A3_AB________IJKL_;
+typedef B3<A3{ "AB", { 0, 0 }, "IJKL" }> B3_A3_AB________IJKL_;
+typedef B3<A3{ "AB", { 0, 0, 0 }, "IJKL" }> B3_A3_AB________IJKL_;
+typedef B3<A3{ "AB", { 0, 0, 0, 0 }, "IJKL" }> B3_A3_AB________IJKL_;
+typedef B3<A3{ "AB", "", "IJKL" }> B3_A3_AB________IJKL_;
+typedef B3<A3{ "AB", "\0", "IJKL" }> B3_A3_AB________IJKL_;
+typedef B3<A3{ "AB", "\0\0", "IJKL" }> B3_A3_AB________IJKL_;
+typedef B3<A3{ "AB", "\0\0\0", "IJKL" }> B3_A3_AB________IJKL_;
+typedef B3<A3{ "AB", "\0\0\0\0", "IJKL" }> B3_A3_AB________IJKL_;
+typedef B3<A3{ "AB\0", "\0\0\0\0", "IJKL" }> B3_A3_AB________IJKL_;
+typedef B3<A3{ "AB\0\0", "\0\0\0\0", "IJKL" }> B3_A3_AB________IJKL_;
+
+// Types with the same name must be the same (and so redefinitions
+// must be accepted). Likewise, overloads on distinct types must
+// be accepted.
+typedef B3<A3{ {0,0,0,0,0}, {0,0,0,0,0}, {0,0,0,0,0} }> B3_A3________________;
+typedef B3<A3{ {0,0,0,0,0}, {0,0,0,0,0}, {0} }> B3_A3________________;
+typedef B3<A3{ {0,0,0,0,0}, {0,0,0,0,0}, {} }> B3_A3________________;
+typedef B3<A3{ {0,0,0,0,0}, {0}, {} }> B3_A3________________;
+typedef B3<A3{ {0,0,0,0,0}, {}, {} }> B3_A3________________;
+typedef B3<A3{ {0}, {0}, {0} }> B3_A3________________;
+typedef B3<A3{ {0}, {0}, {} }> B3_A3________________;
+typedef B3<A3{ {0}, {}, {0} }> B3_A3________________;
+typedef B3<A3{ {}, {}, {} }> B3_A3________________;
+typedef B3<A3{ {}, {} }> B3_A3________________;
+typedef B3<A3{ {} }> B3_A3________________;
+typedef B3<A3{ }> B3_A3________________;
+typedef B3<A3{ {0,0,0,0,0}, {0,0,0,0,0}, {0,0,0,0,1} }> B3_A3_______________1;
+typedef B3<A3{ {0,0,0,0,0}, {0,0,0,0}, {0,0,0,0,1} }> B3_A3_______________1;
+typedef B3<A3{ {0,0,0,0,0}, {0,0,0}, {0,0,0,0,1} }> B3_A3_______________1;
+typedef B3<A3{ {0,0,0,0,0}, {0,0}, {0,0,0,0,1} }> B3_A3_______________1;
+typedef B3<A3{ {0,0,0,0,0}, {0}, {0,0,0,0,1} }> B3_A3_______________1;
+typedef B3<A3{ {0,0,0,0,0}, {}, {0,0,0,0,1} }> B3_A3_______________1;
+typedef B3<A3{ {0,0,0,0}, {0,0,0,0,0}, {0,0,0,0,1} }> B3_A3_______________1;
+typedef B3<A3{ {0,0,0}, {0,0,0,0}, {0,0,0,0,1} }> B3_A3_______________1;
+typedef B3<A3{ {0,0}, {0,0,0}, {0,0,0,0,1} }> B3_A3_______________1;
+typedef B3<A3{ {0}, {0,0,}, {0,0,0,0,1} }> B3_A3_______________1;
+typedef B3<A3{ {}, {0}, {0,0,0,0,1} }> B3_A3_______________1;
+typedef B3<A3{ {}, {}, {0,0,0,0,1} }> B3_A3_______________1;
+typedef B3<A3{ {0,0,0}, {0,0}, {0,0,0,1,0} }> B3_A3______________1_;
+typedef B3<A3{ {0,0,0}, {0,0}, {0,0,0,1} }> B3_A3______________1_;
+typedef B3<A3{ {0}, {}, {0,0,1,0} }> B3_A3_____________1__;
+typedef B3<A3{ {0}, {}, {0,0,1} }> B3_A3_____________1__;
+typedef B3<A3{ {0,0,0,0,0}, {0,0,0,0,0}, {0,1,0} }> B3_A3____________1___;
+typedef B3<A3{ {0,0,0,0,0}, {0,0,0,0,0}, {0,1} }> B3_A3____________1___;
+typedef B3<A3{ {0,0,0,0,0}, {0,0,0,0,0}, {1} }> B3_A3___________1____;
+typedef B3<A3{ {0,0,0,0,0}, {0,0,0,0,1}, {0,0,0,0,0} }> B3_A3__________1_____;
+typedef B3<A3{ {0,0,0,0,0}, {0,0,0,0,1}, {} }> B3_A3__________1_____;
+typedef B3<A3{ {0,0,0,0,0}, {0,0,0,0,1} }> B3_A3__________1_____;
+typedef B3<A3{ {0,0,0,0,0}, {0,0,0,1,0}, {0,0,0,0,0} }> B3_A3_________1______;
+typedef B3<A3{ {0,0,0,0,0}, {0,0,1,0,0}, {0,0,0,0,0} }> B3_A3________1_______;
+typedef B3<A3{ {0,0,0,0,0}, {0,1,0,0,0}, {0,0,0,0,0} }> B3_A3_______1________;
+typedef B3<A3{ {0,0,0,0,0}, {1,0,0,0,0}, {0,0,0,0,0} }> B3_A3______1_________;
+typedef B3<A3{ {0,0,0,0,1}, {0,0,0,0,0}, {0,0,0,0,0} }> B3_A3_____1__________;
+typedef B3<A3{ {0,0,0,0,1}, {0,0,0,0,0} }> B3_A3_____1__________;
+typedef B3<A3{ {0,0,0,0,1} }> B3_A3_____1__________;
+typedef B3<A3{ {0,0,0,1,0}, {0,0,0,0,0}, {0,0,0,0,0} }> B3_A3____1___________;
+typedef B3<A3{ {0,0,1,0,0}, {0,0,0,0,0}, {0,0,0,0,0} }> B3_A3___1____________;
+typedef B3<A3{ {0,1,0,0,0}, {0,0,0,0,0}, {0,0,0,0,0} }> B3_A3__1_____________;
+typedef B3<A3{ {1,0,0,0,0}, {0,0,0,0,0}, {0,0,0,0,0} }> B3_A3_1______________;
+typedef B3<A3{ {1,0,0,0,0}, {0,0,0,0,0} }> B3_A3_1______________;
+typedef B3<A3{ {1,0,0,0,0} }> B3_A3_1______________;
+typedef B3<A3{ {1,0,0,0} }> B3_A3_1______________;
+typedef B3<A3{ {1,0,0} }> B3_A3_1______________;
+typedef B3<A3{ {1,0} }> B3_A3_1______________;
+typedef B3<A3{ {1} }> B3_A3_1______________;
+
+typedef B3<A3{ {1,0,0,0,0}, {0,0,0,0,0}, {0,0,0,0,1} }> B3_A3_1_____________1;
+typedef B3<A3{ {1}, {0}, {0,0,0,0,1} }> B3_A3_1_____________1;
+typedef B3<A3{ {1}, {}, {0,0,0,0,1} }> B3_A3_1_____________1;
+typedef B3<A3{ {0,1,0,0,0}, {0,0,0,0,0}, {0,0,0,1} }> B3_A3__1___________1_;
+typedef B3<A3{ {0,1}, {0}, {0,0,0,1} }> B3_A3__1___________1_;
+typedef B3<A3{ {0,1}, {}, {0,0,0,1} }> B3_A3__1___________1_;
+
+// Same as above.
+typedef B3<A3{ "\0\0\0\0", "\0\0\0\0", "\0\0\0\0" }> B3_A3________________;
+typedef B3<A3{ "\0\0\0\0", "\0\0\0\0", "\0\0\0" }> B3_A3________________;
+typedef B3<A3{ "\0\0\0\0", "\0\0\0\0", "\0\0" }> B3_A3________________;
+typedef B3<A3{ "\0\0\0\0", "\0\0\0\0", "\0" }> B3_A3________________;
+typedef B3<A3{ "\0\0\0\0", "\0\0\0\0", "" }> B3_A3________________;
+typedef B3<A3{ "\0\0\0\0", "\0\0\0", "" }> B3_A3________________;
+typedef B3<A3{ "\0\0\0\0", "\0\0", "" }> B3_A3________________;
+typedef B3<A3{ "\0\0\0\0", "\0", "" }> B3_A3________________;
+typedef B3<A3{ "\0\0\0\0", "", "" }> B3_A3________________;
+typedef B3<A3{ "\0\0\0", "", "" }> B3_A3________________;
+typedef B3<A3{ "\0\0", "", "" }> B3_A3________________;
+typedef B3<A3{ "\0", "", "" }> B3_A3________________;
+typedef B3<A3{ "", "", "" }> B3_A3________________;
+typedef B3<A3{ "", "" }> B3_A3________________;
+typedef B3<A3{ "" }> B3_A3________________;
+typedef B3<A3{ "\0\0\0\0", "\0\0\0", { 0 } }> B3_A3________________;
+typedef B3<A3{ "\0\0", { 0 }, "\0" }> B3_A3________________;
+typedef B3<A3{ { 0 }, "", "\0\0\0\0" }> B3_A3________________;
+typedef B3<A3{ "\0\0\0", "\0\0", { } }> B3_A3________________;
+typedef B3<A3{ "\0", { }, "" }> B3_A3________________;
+typedef B3<A3{ { }, "\0\0\0\0", "\0\0\0" }> B3_A3________________;
+
+typedef B3<A3{ "\0\0\0\0", "\0\0\0", {0,0,0,0,1} }> B3_A3_______________1;
+typedef B3<A3{ "\0\0", "\0", "\0\0\0\1" }> B3_A3______________1_;
+typedef B3<A3{ "\0\0\0\0", "\0\0\0", "\0\0\1" }> B3_A3_____________1__;
+typedef B3<A3{ "\0\0", "\0", "\0\1" }> B3_A3____________1___;
+typedef B3<A3{ "\0\0\0\0", "\0\0\0", "\1" }> B3_A3___________1____;
+typedef B3<A3{ "\0\0", {0,0,0,0,1}, "\0" }> B3_A3__________1_____;
+typedef B3<A3{ "\0\0\0\0", "\0\0\0\1", "\0\0\0" }> B3_A3_________1______;
+typedef B3<A3{ "\0\0", "\0\0\1", "\0" }> B3_A3________1_______;
+typedef B3<A3{ "\0\0\0\0", "\0\1", "\0\0\0" }> B3_A3_______1________;
+typedef B3<A3{ "\0\0", "\1", "\0" }> B3_A3______1_________;
+typedef B3<A3{ {0,0,0,0,1}, "\0\0\0\0", "\0\0\0" }> B3_A3_____1__________;
+typedef B3<A3{ "\0\0\0\1", "\0\0", "\0" }> B3_A3____1___________;
+typedef B3<A3{ "\0\0\1", "\0\0\0\0", "\0\0\0" }> B3_A3___1____________;
+typedef B3<A3{ "\0\1", "\0\0", "\0" }> B3_A3__1_____________;
+typedef B3<A3{ "\1", "", "\0\0\0\0" }> B3_A3_1______________;
+
+typedef B3<A3{ "\1", {}, {0,0,0,0,1} }> B3_A3_1_____________1;
+typedef B3<A3{ "\1", "", {0,0,0,0,1} }> B3_A3_1_____________1;
+typedef B3<A3{ "\0\1", {}, {0,0,0,1} }> B3_A3__1___________1_;
+typedef B3<A3{ "\0\1", "", "\0\0\0\1" }> B3_A3__1___________1_;
+typedef B3<A3{ "\0\1\0", "\0", "\0\0\0\1" }> B3_A3__1___________1_;
+
+void f_b3_a3 (B3_A3________________) { }
+void f_b3_a3 (B3_A3_______________1) { }
+void f_b3_a3 (B3_A3______________1_) { }
+void f_b3_a3 (B3_A3_____________1__) { }
+void f_b3_a3 (B3_A3____________1___) { }
+void f_b3_a3 (B3_A3___________1____) { }
+void f_b3_a3 (B3_A3__________1_____) { }
+void f_b3_a3 (B3_A3_________1______) { }
+void f_b3_a3 (B3_A3________1_______) { }
+void f_b3_a3 (B3_A3_______1________) { }
+void f_b3_a3 (B3_A3______1_________) { }
+void f_b3_a3 (B3_A3_____1__________) { }
+void f_b3_a3 (B3_A3____1___________) { }
+void f_b3_a3 (B3_A3___1____________) { }
+void f_b3_a3 (B3_A3__1_____________) { }
+void f_b3_a3 (B3_A3_1______________) { }
+void f_b3_a3 (B3_A3_1_____________1) { }
+void f_b3_a3 (B3_A3__1___________1_) { }
+
+typedef B3<A3{ "AB\0D", { }, "IJKL" }> B3_A3_ABZDZZZZZZIJKLZ;
+typedef B3<A3{ "AB\0D", { 0, 0, 1 }, "IJKL" }> B3_A3_ABZDZZZ1ZZIJKLZ;
+typedef B3<A3{ "AB\0D", { 0, 1 }, "IJKL" }> B3_A3_ABZDZZ1ZZZIJKLZ;
+
+void f (B3_A3_ABZDZZZZZZIJKLZ) { }
+void f (B3_A3_ABZDZZZ1ZZIJKLZ) { }
+void f (B3_A3_ABZDZZ1ZZZIJKLZ) { }
--- /dev/null
+// PR c++/89833
+// Test to verify that arrays of null pointer to members used as
+// non-type template arguments are interprested as null regardless
+// of the form of their initialization.
+// { dg-do compile { target c++2a } }
+// { dg-options "-O2 -Wall -fdump-tree-optimized" }
+
+struct A { int i; };
+
+typedef int A::*pam_t;
+
+struct B { pam_t a[2]; };
+template <B x> struct C { static constexpr B b = x; };
+
+B f__ () { return B{ }; }
+B f0_ () { return B{ 0 }; }
+B f00 () { return B{ 0, 0 }; }
+
+typedef C<B{ }> X__;
+typedef C<B{ 0 }> X0_;
+typedef C<B{ 0, 0 }> X00;
+
+B g__ () { return X__::b; }
+B g0_ () { return X0_::b; }
+B g00 () { return X00::b; }
+
+const B b__{ };
+const B b0_{ 0 };
+const B b00{ 0, 0 };
+
+const pam_t apam__[2] = { };
+const pam_t apam0_[2] = { 0 };
+const pam_t apam00[2] = { 0, 0 };
+
+#define assert(expr) \
+ (expr) ? (void)0 : __builtin_abort ()
+
+void test ()
+{
+ assert (f__ ().a[0] == nullptr && f__ ().a[1] == nullptr);
+ assert (f0_ ().a[0] == nullptr && f0_ ().a[1] == nullptr);
+ assert (f00 ().a[0] == nullptr && f00 ().a[1] == nullptr);
+
+ assert (g__ ().a[0] == nullptr && g__ ().a[1] == nullptr);
+ assert (g0_ ().a[0] == nullptr && g0_ ().a[1] == nullptr);
+ assert (g00 ().a[0] == nullptr && g00 ().a[1] == nullptr);
+
+ assert (b__.a[0] == nullptr && b__.a[1] == nullptr);
+ assert (b0_.a[0] == nullptr && b0_.a[1] == nullptr);
+ assert (b00.a[0] == nullptr && b00.a[1] == nullptr);
+
+ assert (apam__[0] == nullptr && apam__[1] == nullptr);
+ assert (apam0_[0] == nullptr && apam0_[1] == nullptr);
+ assert (apam00[0] == nullptr && apam00[1] == nullptr);
+}
+
+// { dg-final { scan-tree-dump-not "abort" "optimized" } }
--- /dev/null
+// PR c++/89833
+// Anal test to verify that arrays of null pointer to members are
+// treated as null regardless of the form of their initialization,
+// and have all bits set in their representation.
+// { dg-do run { target c++11 } }
+// { dg-options "-O2 -Wall" }
+
+#define NOIPA __attribute__ ((noipa))
+
+struct A { int i; };
+
+typedef int A::*pam_t;
+
+pam_t apam__[2] = { };
+pam_t apam0_[2] = { 0 };
+pam_t apam00[2] = { 0, 0 };
+
+struct B { pam_t a[2]; };
+
+NOIPA B f__ () { return B{ }; }
+NOIPA B f0_ () { return B{ 0 }; }
+NOIPA B f00 () { return B{ 0, 0 }; }
+
+const B c__{ };
+const B c0_{ 0 };
+const B c00{ 0, 0 };
+
+B b__{ };
+B b0_{ 0 };
+B b00{ 0, 0 };
+
+#define assert(expr) \
+ (expr) ? (void)0 : __builtin_abort ()
+
+signed char allones[2 * sizeof (pam_t)];
+
+#define assert_rep(mp, n) \
+ assert (!test_allones (mp, n))
+
+NOIPA void init_allones ()
+{
+ __builtin_memset (allones, -1, sizeof allones);
+}
+
+NOIPA int test_allones (const pam_t *p, unsigned n)
+{
+ return __builtin_memcmp (allones, p, sizeof *p * n);
+}
+
+int main ()
+{
+ init_allones ();
+
+ assert (apam__[0] == nullptr && apam__[1] == nullptr);
+ assert (apam0_[0] == nullptr && apam0_[1] == nullptr);
+ assert (apam00[0] == nullptr && apam00[1] == nullptr);
+
+ assert (f__ ().a[0] == nullptr && f__ ().a[1] == nullptr);
+ assert (f0_ ().a[0] == nullptr && f0_ ().a[1] == nullptr);
+ assert (f00 ().a[0] == nullptr && f00 ().a[1] == nullptr);
+
+ assert (b__.a[0] == nullptr && b__.a[1] == nullptr);
+ assert (b0_.a[0] == nullptr && b0_.a[1] == nullptr);
+ assert (b00.a[0] == nullptr && b00.a[1] == nullptr);
+
+ assert (c__.a[0] == nullptr && c__.a[1] == nullptr);
+ assert (c0_.a[0] == nullptr && c0_.a[1] == nullptr);
+ assert (c00.a[0] == nullptr && c00.a[1] == nullptr);
+
+ assert_rep (apam__, 2);
+ assert_rep (apam0_, 2);
+ assert_rep (apam00, 2);
+
+ assert_rep (f__ ().a, 2);
+ assert_rep (f0_ ().a, 2);
+ assert_rep (f0_ ().a, 2);
+ assert_rep (f00 ().a, 2);
+
+ assert_rep (b__.a, 2);
+ assert_rep (b0_.a, 2);
+ assert_rep (b00.a, 2);
+
+ assert_rep (c__.a, 2);
+ assert_rep (c0_.a, 2);
+ assert_rep (c00.a, 2);
+}
--- /dev/null
+// PR c++/47488 - sorry, unimplemented: string literal in function
+// template signature
+// { dg-do compile }
+// { dg-options "-Wall" }
+
+#if __cpluspls >= 201103L
+
+// C++ 11 test case from comment #0.
+namespace comment_0 {
+
+template <typename T>
+int f (const T&, const char *);
+
+template <typename T>
+decltype (f (T (), "")) g (const T &);
+
+void h ()
+{
+ g (0);
+}
+
+} // comment_0
+
+#endif
+
+// C++ 98 test case from comment #1.
+namespace comment_1 {
+
+template <typename T>
+int f(const T&, const char *);
+
+template<int> struct N { };
+
+template <typename T>
+N<sizeof (f (T (), ""))> g (const T&);
+
+void h ()
+{
+ g (0);
+}
+
+} // comment_1
+
+// C++ 98 test case from comment #2.
+namespace comment_2 {
+
+template <typename T>
+int f (const char *);
+
+template<int> struct N { };
+
+template <typename T>
+N<sizeof (f<T>(""))> g (const T &);
+
+void h ()
+{
+ g (0);
+}
+
+} // comment_2
+
+
+#if __cpluspls >= 201103L
+
+// C++ 11 test case from comment #5.
+namespace comment_5 {
+
+template <typename T> constexpr T f(const T* p) { return p[0]; }
+template <int> struct N { };
+template <typename T> void g (T, N<f((const T*)"1")>) { }
+template <typename T> void g (T, N<f((const T*)"2")>) { }
+
+void h ()
+{
+ g ('1', N<'1'>());
+ g ('2', N<'2'>());
+}
+
+}
+
+#endif