PR c++/89833 - sorry, unimplemented: string literal in function template signature

gcc/cp/ChangeLog:

        PR c++/89833
	* 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.

Index: gcc/cp/decl.c
===================================================================
--- gcc/cp/decl.c	(revision 270037)
+++ gcc/cp/decl.c	(working copy)
@@ -5799,6 +5799,9 @@ reshape_init_array_1 (tree elt_type, tree max_inde
 	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);
@@ -5817,11 +5820,28 @@ reshape_init_array_1 (tree elt_type, tree max_inde
       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 && trivial_type_p (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;
 }
 
Index: gcc/cp/mangle.c
===================================================================
--- gcc/cp/mangle.c	(revision 270037)
+++ gcc/cp/mangle.c	(working copy)
@@ -3136,18 +3136,48 @@ write_expression (tree expr)
     }
   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);
 	}
-      FOR_EACH_CONSTRUCTOR_VALUE (elts, i, val)
-	write_expression (val);
+
+      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);
+	    }
+	}
       write_char ('E');
     }
   else if (code == LAMBDA_EXPR)
@@ -3353,9 +3383,15 @@ write_expression (tree 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.  */
   if (null_member_pointer_value_p (value))
@@ -3397,9 +3433,36 @@ write_template_arg_literal (const tree value)
 	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.  */
+	  tree strsizenode = TYPE_SIZE_UNIT (TREE_TYPE (value));
+	  unsigned strsize = tree_to_uhwi (strsizenode);
+	  if (strsize > n)
+	    strsize = n;
+	  for (const char *p = str + strsize - 1; ; --p)
+	    {
+	      if (*p || p == str)
+		{
+		  strsize -= str + strsize - !!*p - p;
+		  break;
+		}
+	    }
+	  tree eltype = TREE_TYPE (valtype);
+	  for (const char *p = str; strsize--; ++p)
+	    {
+	      write_char ('L');
+	      write_type (eltype);
+	      write_unsigned_number (*(const unsigned char*)p);
+	      write_string ("E");
+	    }
+	  break;
+	}
+
       default:
 	gcc_unreachable ();
       }
Index: gcc/testsuite/g++.dg/cpp0x/constexpr-array19.C
===================================================================
--- gcc/testsuite/g++.dg/cpp0x/constexpr-array19.C	(nonexistent)
+++ gcc/testsuite/g++.dg/cpp0x/constexpr-array19.C	(working copy)
@@ -0,0 +1,137 @@
+// 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);
+}
Index: gcc/testsuite/g++.dg/cpp2a/nontype-class15.C
===================================================================
--- gcc/testsuite/g++.dg/cpp2a/nontype-class15.C	(nonexistent)
+++ gcc/testsuite/g++.dg/cpp2a/nontype-class15.C	(working copy)
@@ -0,0 +1,222 @@
+// 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) { }
Index: gcc/testsuite/g++.dg/abi/mangle69.C
===================================================================
--- gcc/testsuite/g++.dg/abi/mangle69.C	(nonexistent)
+++ gcc/testsuite/g++.dg/abi/mangle69.C	(working copy)
@@ -0,0 +1,164 @@
+// { 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" } }
Index: gcc/testsuite/g++.dg/abi/mangle70.C
===================================================================
--- gcc/testsuite/g++.dg/abi/mangle70.C	(nonexistent)
+++ gcc/testsuite/g++.dg/abi/mangle70.C	(working copy)
@@ -0,0 +1,29 @@
+// 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" } }
Index: gcc/testsuite/g++.dg/abi/mangle71.C
===================================================================
--- gcc/testsuite/g++.dg/abi/mangle71.C	(nonexistent)
+++ gcc/testsuite/g++.dg/abi/mangle71.C	(working copy)
@@ -0,0 +1,28 @@
+// 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" } }
