diff mbox

fix #69251 - [6 Regression] ICE in unify_array_domain on a flexible array member

Message ID 56B15600.5070509@gmail.com
State New
Headers show

Commit Message

Martin Sebor Feb. 3, 2016, 1:21 a.m. UTC
On 02/02/2016 05:28 AM, Jason Merrill wrote:
> On 01/25/2016 05:55 PM, Martin Sebor wrote:
>> The downside of this approach is that it prevents everything but
>> the front end from distinguishing flexible array members from
>> arrays of unspecified or unknown bounds.  The immediate impact
>> is that prevents us from maintaining ABI compatibility with GCC
>> 5 (with -fabi-version=9) and from diagnosing the mangling change.
>> This means should we decide to adopt this approach, the final
>> version of the patch for c++/69277 mentioned above that's still
>> pending approval will need to be tweaked to have the ABI checks
>> removed.
>
> That's unfortunate, but I think acceptable.
>
>>     * decl.c (compute_array_index_type): Return null for flexible array
>>     members.
>
> Instead of this, I would think we can remove the calls to
> compute_array_index_type added by your earlier patch, as well as many
> other changes from that patch to handle null TYPE_MAX_VALUE.

Yes, that's possible but it didn't seem essential at this stage.
I wanted to make only conservative changes to avoid any further
fallout.  I also wasn't sure whether the ABI issue above would
make this approach unviable.

>
>>     * tree.c (array_of_runtime_bound_p): Handle gracefully array types
>>     with null TYPE_MAX_VALUE.
>
> This seems unneeded.
>
>>     (build_ctor_subob_ref): Loosen debug checking to handle flexible
>>     array members.
>
> And this shouldn't need the TYPE_MAX_VALUE check.

I went ahead and made the requested changes.  They might seem
perfectly innocuous to you but the removal of the tests for
TYPE_MAX_VALUE(t) being null makes me nervous at this stage.
I'm not nearly comfortable enough with the code to be confident
that they're all 100% safe.  I defer to your better judgment
on this.

In the patch, I also corrected some transgressions against
the GNU formatting rules I introduced in the the original
change.

I've regtested the patch on x86_64.

Please let me know if this patch is good to commit.  In light
of his today's comment on bug 69277 I have the impression
Jakub would like to have the mangling change in the Fedora
mass rebuild or release and I don't want to hold that up.

Thanks
Martin

Comments

Jason Merrill Feb. 3, 2016, 6:47 p.m. UTC | #1
On 02/02/2016 08:21 PM, Martin Sebor wrote:
> On 02/02/2016 05:28 AM, Jason Merrill wrote:
>> On 01/25/2016 05:55 PM, Martin Sebor wrote:
>>> The downside of this approach is that it prevents everything but
>>> the front end from distinguishing flexible array members from
>>> arrays of unspecified or unknown bounds.  The immediate impact
>>> is that prevents us from maintaining ABI compatibility with GCC
>>> 5 (with -fabi-version=9) and from diagnosing the mangling change.
>>> This means should we decide to adopt this approach, the final
>>> version of the patch for c++/69277 mentioned above that's still
>>> pending approval will need to be tweaked to have the ABI checks
>>> removed.
>>
>> That's unfortunate, but I think acceptable.
>>
>>>     * decl.c (compute_array_index_type): Return null for flexible array
>>>     members.
>>
>> Instead of this, I would think we can remove the calls to
>> compute_array_index_type added by your earlier patch, as well as many
>> other changes from that patch to handle null TYPE_MAX_VALUE.
>
> Yes, that's possible but it didn't seem essential at this stage.
> I wanted to make only conservative changes to avoid any further
> fallout.  I also wasn't sure whether the ABI issue above would
> make this approach unviable.

I guess my sense of conservatism is different from yours: I think 
removing recent changes is conservative in that it minimizes the change 
from previous versions of the compiler.

>>>     * tree.c (array_of_runtime_bound_p): Handle gracefully array types
>>>     with null TYPE_MAX_VALUE.
>>
>> This seems unneeded.
>>
>>>     (build_ctor_subob_ref): Loosen debug checking to handle flexible
>>>     array members.
>>
>> And this shouldn't need the TYPE_MAX_VALUE check.
>
> I went ahead and made the requested changes.  They might seem
> perfectly innocuous to you but the removal of the tests for
> TYPE_MAX_VALUE(t) being null makes me nervous at this stage.
> I'm not nearly comfortable enough with the code to be confident
> that they're all 100% safe.  I defer to your better judgment
> on this.

It was impossible to have null TYPE_MAX_VALUE until you introduced that 
in compute_array_index_type, and thus we didn't test for it; if we 
aren't doing that anymore I can't imagine where it would come from now.

> @@ -4120,9 +4120,8 @@ walk_subobject_offsets (tree type,
> -	  || !domain
> -	  /* Flexible array members have no upper bound.  */
> -	  || !TYPE_MAX_VALUE (domain))
> +	  /* Flexible array members have a null domain.  */
> +	  || !domain)

With this patch flexible array members are a special case of array of 
unknown bound, so I don't think we need to call them out in a comment here.

> @@ -875,10 +875,11 @@ dump_type_suffix (cxx_pretty_printer *pp, tree t, int flags)
> -      if (TYPE_DOMAIN (t) && TYPE_MAX_VALUE (TYPE_DOMAIN (t)))
> +      /* C++ flexible array members have a null domain.  */
> +      if (tree dtype = TYPE_DOMAIN (t))

Likewise.

OK with these two comments removed.

Jason
Martin Sebor Feb. 4, 2016, 5:23 a.m. UTC | #2
I've committed the patch with the changes below.  Just to clarify
my concern (since put to rest):

> It was impossible to have null TYPE_MAX_VALUE until you introduced that
> in compute_array_index_type, and thus we didn't test for it; if we
> aren't doing that anymore I can't imagine where it would come from now.

The patch with the TYPE_MAX_VALUE checks has been in place for
several weeks.  Although unlikely, it seemed conceivable that
a change could have gone in since then that has introduced
a dependency on the domain being non-null for flexible array
members in some corner case.  But you know the code far better
than me (and the changes being committed) so I trust you when
you say the removal is safe.

Martin
diff mbox

Patch

PR c++/69251 - [6 Regression] ICE in unify_array_domain on a flexible array
               member
PR c++/69253 - [6 Regression] ICE in cxx_incomplete_type_diagnostic initializing
               a flexible array member with empty string
PR c++/69290 - [6 Regression] ICE on invalid initialization of a flexible array
               member
PR c++/69277 - [6 Regression] ICE mangling a flexible array member
PR c++/69349 - template substitution error for flexible array members

gcc/testsuite/ChangeLog:
2016-02-02  Martin Sebor  <msebor@redhat.com>

	PR c++/69251
	PR c++/69253
	PR c++/69290
	PR c++/69277
	PR c++/69349
	* g++.dg/ext/flexarray-mangle-2.C: New test.
	* g++.dg/ext/flexarray-mangle.C: New test.
	* g++.dg/ext/flexarray-subst.C: New test.
	* g++.dg/ext/flexary11.C: New test.
	* g++.dg/ext/flexary12.C: New test.
	* g++.dg/ext/flexary13.C: New test.
	* g++.dg/ext/flexary14.C: New test.
	* g++.dg/other/dump-ada-spec-2.C: Adjust.

gcc/cp/ChangeLog:
2016-02-02  Martin Sebor  <msebor@redhat.com>

	PR c++/69251
	PR c++/69253
	PR c++/69290
	PR c++/69277
	PR c++/69349
	* class.c (walk_subobject_offsets): Avoid testing the upper bound
	of a flexible array member for equality to null.
	(find_flexarrays): Remove spurious whitespace introduced in r231665.
	(diagnose_flexarrays): Avoid checking the upper bound of arrays.
	(check_flexarrays): Same.
	* decl.c (compute_array_index_type): Avoid special case for flexible
	array members.
	(grokdeclarator): Avoid calling compute_array_index_type for flexible
	array members.
	* error.c (dump_type_suffix): Revert changes introduced in r231665
	and rendered unnecessary by the changes above.
	* pt.c (tsubst):  Same.
	* tree.c (build_ctor_subob_ref): Handle flexible array members.
	* typeck2.c (digest_init_r): Revert changes introduced in r231665.
	(process_init_constructor_array): Same.
	(process_init_constructor_record): Same.

diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index 45d8a24..9876197 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -4120,9 +4120,8 @@  walk_subobject_offsets (tree type,
       /* Avoid recursing into objects that are not interesting.  */
       if (!CLASS_TYPE_P (element_type)
 	  || !CLASSTYPE_CONTAINS_EMPTY_CLASS_P (element_type)
-	  || !domain
-	  /* Flexible array members have no upper bound.  */
-	  || !TYPE_MAX_VALUE (domain))
+	  /* Flexible array members have a null domain.  */
+	  || !domain)
 	return 0;
 
       /* Step through each of the elements in the array.  */
@@ -6645,7 +6644,7 @@  find_flexarrays (tree t, flexmems_t *fmem)
       for (next = fld;
 	   (next = DECL_CHAIN (next))
 	     && TREE_CODE (next) != FIELD_DECL; );
-      
+
       tree fldtype = TREE_TYPE (fld);
       if (TREE_CODE (fld) != TYPE_DECL
 	  && RECORD_OR_UNION_TYPE_P (fldtype)
@@ -6672,22 +6671,20 @@  find_flexarrays (tree t, flexmems_t *fmem)
 	  /* Remember the first non-static data member.  */
 	  if (!fmem->first)
 	    fmem->first = fld;
-	  
+
 	  /* Remember the first non-static data member after the flexible
 	     array member, if one has been found, or the zero-length array
 	     if it has been found.  */
 	  if (!fmem->after && fmem->array)
 	    fmem->after = fld;
 	}
-	    
+
       /* Skip non-arrays.  */
       if (TREE_CODE (fldtype) != ARRAY_TYPE)
 	continue;
 
       /* Determine the upper bound of the array if it has one.  */
-      tree dom = TYPE_DOMAIN (fldtype);
-
-      if (dom && TYPE_MAX_VALUE (dom))
+      if (tree dom = TYPE_DOMAIN (fldtype))
 	{
 	  if (fmem->array)
 	    {
@@ -6710,14 +6707,13 @@  find_flexarrays (tree t, flexmems_t *fmem)
 	    {
 	      /* Replace the zero-length array if it's been stored and
 		 reset the after pointer.  */
-	      dom = TYPE_DOMAIN (TREE_TYPE (fmem->array));
-	      if (dom && TYPE_MAX_VALUE (dom))
+	      if (TYPE_DOMAIN (TREE_TYPE (fmem->array)))
 		{
 		  fmem->array = fld;
 		  fmem->after = NULL_TREE;
 		}
 	    }
-	  else	
+	  else
 	    fmem->array = fld;
 	}
     }
@@ -6737,8 +6733,7 @@  diagnose_flexarrays (tree t, const flexmems_t *fmem)
 
   const char *msg = 0;
 
-  const_tree dom = TYPE_DOMAIN (TREE_TYPE (fmem->array));
-  if (dom && TYPE_MAX_VALUE (dom))
+  if (TYPE_DOMAIN (TREE_TYPE (fmem->array)))
     {
       if (fmem->after)
 	msg = G_("zero-size array member %qD not at end of %q#T");
@@ -6770,7 +6765,7 @@  diagnose_flexarrays (tree t, const flexmems_t *fmem)
 	      inform (DECL_SOURCE_LOCATION (fmem->after),
 		      "next member %q#D declared here",
 		      fmem->after);
-	  
+
 	  inform (location_of (t), "in the definition of %q#T", t);
 	}
     }
@@ -6844,7 +6839,7 @@  check_flexarrays (tree t, flexmems_t *fmem /* = NULL */)
   find_flexarrays (t, fmem);
 
   if (fmem == &flexmems)
-    { 
+    {
       /* Issue diagnostics for invalid flexible and zero-length array members
 	 found in base classes or among the members of the current class.  */
       diagnose_flexarrays (t, fmem);
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 8da87d3..2c337bc 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -8645,10 +8645,9 @@  fold_sizeof_expr (tree t)
   return r;
 }
 
-/* Given the SIZE (i.e., number of elements) in an array, compute an
-   appropriate index type for the array.  When SIZE is null, the array
-   is a flexible array member.  If non-NULL, NAME is the name of
-   the entity being declared.  */
+/* Given the SIZE (i.e., number of elements) in an array, compute
+   an appropriate index type for the array.  If non-NULL, NAME is
+   the name of the entity being declared.  */
 
 tree
 compute_array_index_type (tree name, tree size, tsubst_flags_t complain)
@@ -8656,9 +8655,6 @@  compute_array_index_type (tree name, tree size, tsubst_flags_t complain)
   tree itype;
   tree osize = size;
 
-  if (size == NULL_TREE)
-    return build_index_type (NULL_TREE);
-
   if (error_operand_p (size))
     return error_mark_node;
 
@@ -10967,11 +10963,10 @@  grokdeclarator (const cp_declarator *declarator,
 		error ("flexible array member in union");
 		type = error_mark_node;
 	      }
-	    else
+	    else 
 	      {
-		tree itype = compute_array_index_type (dname, NULL_TREE,
-						       tf_warning_or_error);
-		type = build_cplus_array_type (TREE_TYPE (type), itype);
+		/* Flexible array member has a null domain.  */
+		type = build_cplus_array_type (TREE_TYPE (type), NULL_TREE);
 	      }
 	  }
 
diff --git a/gcc/cp/error.c b/gcc/cp/error.c
index 89a00a0..4948fab 100644
--- a/gcc/cp/error.c
+++ b/gcc/cp/error.c
@@ -875,10 +875,11 @@  dump_type_suffix (cxx_pretty_printer *pp, tree t, int flags)
     case ARRAY_TYPE:
       pp_maybe_space (pp);
       pp_cxx_left_bracket (pp);
-      if (TYPE_DOMAIN (t) && TYPE_MAX_VALUE (TYPE_DOMAIN (t)))
+      /* C++ flexible array members have a null domain.  */
+      if (tree dtype = TYPE_DOMAIN (t))
 	{
-	  tree dtype = TYPE_DOMAIN (t);
 	  tree max = TYPE_MAX_VALUE (dtype);
+	  /* Zero-length arrays have an upper bound of SIZE_MAX.  */
 	  if (integer_all_onesp (max))
 	    pp_character (pp, '0');
 	  else if (tree_fits_shwi_p (max))
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 27dfdf86..1dea519 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -12846,14 +12846,9 @@  tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
       if (t == integer_type_node)
 	return t;
 
-      if (TREE_CODE (TYPE_MIN_VALUE (t)) == INTEGER_CST)
-        {
-          if (!TYPE_MAX_VALUE (t))
-            return compute_array_index_type (NULL_TREE, NULL_TREE, complain);
-          
-          if (TREE_CODE (TYPE_MAX_VALUE (t)) == INTEGER_CST)
-            return t;
-        }
+      if (TREE_CODE (TYPE_MIN_VALUE (t)) == INTEGER_CST
+          && TREE_CODE (TYPE_MAX_VALUE (t)) == INTEGER_CST)
+        return t;
 
       {
 	tree max, omax = TREE_OPERAND (TYPE_MAX_VALUE (t), 0);
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index 2bf37bca..3203aca 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -2586,8 +2586,19 @@  build_ctor_subob_ref (tree index, tree type, tree obj)
     obj = build_class_member_access_expr (obj, index, NULL_TREE,
 					  /*reference*/false, tf_none);
   if (obj)
-    gcc_assert (same_type_ignoring_top_level_qualifiers_p (type,
-							   TREE_TYPE (obj)));
+    {
+      tree objtype = TREE_TYPE (obj);
+      if (TREE_CODE (objtype) == ARRAY_TYPE && !TYPE_DOMAIN (objtype))
+	{
+	  /* When the destination object refers to a flexible array member
+	     verify that it matches the type of the source object except
+	     for its domain.  */
+	  gcc_assert (comptypes (type, objtype, COMPARE_REDECLARATION));
+	}
+      else
+	gcc_assert (same_type_ignoring_top_level_qualifiers_p (type, objtype));
+    }
+
   return obj;
 }
 
diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c
index ac2f3c3..419faa2 100644
--- a/gcc/cp/typeck2.c
+++ b/gcc/cp/typeck2.c
@@ -1015,14 +1015,13 @@  digest_init_r (tree type, tree init, bool nested, int flags,
      them if they were present.  */
   if (code == ARRAY_TYPE)
     {
-      if (nested
-	  && (!TYPE_DOMAIN (type) || !TYPE_MAX_VALUE (TYPE_DOMAIN (type))))
+      if (nested && !TYPE_DOMAIN (type))
 	{
-	  /* Flexible array members do not have an upper bound.  */
+	  /* C++ flexible array members have a null domain.  */
 	  pedwarn (EXPR_LOC_OR_LOC (init, input_location), OPT_Wpedantic,
 		   "initialization of a flexible array member");
 	}
-      
+
       tree typ1 = TYPE_MAIN_VARIANT (TREE_TYPE (type));
       if (char_type_p (typ1)
 	  /*&& init */
@@ -1061,9 +1060,7 @@  digest_init_r (tree type, tree init, bool nested, int flags,
 	      init = copy_node (init);
 	      TREE_TYPE (init) = type;
 	    }
-	  if (TYPE_DOMAIN (type)
-	      && TYPE_MAX_VALUE (TYPE_DOMAIN (type))
-	      && TREE_CONSTANT (TYPE_SIZE (type)))
+	  if (TYPE_DOMAIN (type) && TREE_CONSTANT (TYPE_SIZE (type)))
 	    {
 	      /* Not a flexible array member.  */
 	      int size = TREE_INT_CST_LOW (TYPE_SIZE (type));
@@ -1252,12 +1249,11 @@  process_init_constructor_array (tree type, tree init,
 
   if (TREE_CODE (type) == ARRAY_TYPE)
     {
+      /* C++ flexible array members have a null domain.  */
       tree domain = TYPE_DOMAIN (type);
-      /* Flexible array members have no upper bound.  */
-      tree maxval = domain ? TYPE_MAX_VALUE (domain) : NULL_TREE;
-      if (domain && maxval && TREE_CONSTANT (maxval))
-	len = wi::ext (wi::to_offset (maxval)
-		       - wi::to_offset (TYPE_MIN_VALUE (domain)) + 1,
+      if (domain && TREE_CONSTANT (TYPE_MAX_VALUE (domain)))
+	len = wi::ext (wi::to_offset (TYPE_MAX_VALUE (domain))
+                       - wi::to_offset (TYPE_MIN_VALUE (domain)) + 1,
 		       TYPE_PRECISION (TREE_TYPE (domain)),
 		       TYPE_SIGN (TREE_TYPE (domain))).to_uhwi ();
       else
@@ -1451,9 +1447,7 @@  process_init_constructor_record (tree type, tree init,
 	  /* Warn when some struct elements are implicitly initialized
 	     to zero.  However, avoid issuing the warning for flexible
 	     array members since they need not have any elements.  */
-	  if ((TREE_CODE (fldtype) != ARRAY_TYPE
-	       || (TYPE_DOMAIN (fldtype)
-		   && TYPE_MAX_VALUE (TYPE_DOMAIN (fldtype))))
+	  if ((TREE_CODE (fldtype) != ARRAY_TYPE || TYPE_DOMAIN (fldtype))
 	      && (complain & tf_warning)
 	      && !EMPTY_CONSTRUCTOR_P (init))
 	    warning (OPT_Wmissing_field_initializers,
diff --git a/gcc/testsuite/g++.dg/ext/flexarray-mangle-2.C b/gcc/testsuite/g++.dg/ext/flexarray-mangle-2.C
new file mode 100644
index 0000000..98bd5f5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/flexarray-mangle-2.C
@@ -0,0 +1,46 @@ 
+// PR c++/69277 - [6 Regression] ICE mangling a flexible array member
+// { dg-do compile { target c++11 } }
+
+struct A {
+  int n;
+  char a [];
+};
+
+// Declare but do not define function templates.
+template <class T>
+void foo ();
+
+template <typename T>
+void fooref (T&);
+
+// Rvalue references are a C++ 11 feature.
+template <typename T>
+void foorefref (T&&);
+
+void bar (A a)
+{
+  // Decltype is also a C++ 11 feature.
+  // Verify that decltype gets the right type and that foo is
+  // mangled correctly.
+  foo<decltype (a.a)>();
+
+  // Verify that function templates taking a reference and an rvalue
+  // references (as in PR c++/69277) are also mangled correctly.
+  fooref (a.a);
+  foorefref (a.a);
+}
+
+// In G++ versions prior to 6, flexible array members were incorrectly
+// mangled as arrays of zero elements.  Verify that flexible array
+// members are mangled correctly as arrays of an unspecified number
+// of elements.
+
+// void foo<char []>():
+// { dg-final { scan-assembler _Z3fooIA_cEvv } }
+
+// The following is derived from PR c++/69277:
+// void fooref<char []>(char (&) [])
+// { dg-final { scan-assembler _Z6foorefIA_cEvRT_ } }
+
+// void foorefref<char (&) []>(char (&) [])
+// { dg-final { scan-assembler _Z9foorefrefIRA_cEvOT_ } }
diff --git a/gcc/testsuite/g++.dg/ext/flexarray-mangle.C b/gcc/testsuite/g++.dg/ext/flexarray-mangle.C
new file mode 100644
index 0000000..d8a8c0a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/flexarray-mangle.C
@@ -0,0 +1,24 @@ 
+// PR c++/69277 - [6 Regression] ICE mangling a flexible array member
+// { dg-do compile }
+
+struct A {
+  int n;
+  char a [];
+};
+
+// Declare but do not define function templates.
+template <typename T>
+void fooref (T&);
+
+void bar (A a)
+{
+  fooref (a.a);
+}
+
+// In G++ versions prior to 6, flexible array members were incorrectly
+// mangled as arrays of zero elements.  Verify that flexible array
+// members are mangled correctly as arrays of an unspecified number
+// of elements.
+
+// void fooref<char []>(char (&) [])
+// { dg-final { scan-assembler _Z6foorefIA_cEvRT_ } }
diff --git a/gcc/testsuite/g++.dg/ext/flexarray-subst.C b/gcc/testsuite/g++.dg/ext/flexarray-subst.C
new file mode 100644
index 0000000..f644636
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/flexarray-subst.C
@@ -0,0 +1,33 @@ 
+// PR c++/69251 - [6 Regression] ICE (segmentation fault) in unify_array_domain
+// on i686-linux-gnu
+// { dg-do compile }
+
+struct A { int n; char a[]; };
+
+template <class>
+struct B;
+
+// The following definition shouldn't be needed but is provided to prevent
+// the test from failing with an error due to PR c++/69349 - template
+// substitution error for flexible array members.  (This doesn't compromise
+// the validity of this test since all it tests for is the absennce of
+// the ICE.)
+template <class>
+struct B { typedef int X; };
+
+template <class T>
+struct B<T[]> { typedef int X; };
+
+template <class T>
+struct C { typedef typename B<T>::X X; };
+
+template <class T>
+int foo (T&, typename C<T>::X = 0)
+{
+  return 0;
+}
+
+void bar (A *a)
+{
+  foo (a->a);
+}
diff --git a/gcc/testsuite/g++.dg/ext/flexary11.C b/gcc/testsuite/g++.dg/ext/flexary11.C
new file mode 100644
index 0000000..5bf774f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/flexary11.C
@@ -0,0 +1,19 @@ 
+// PR c++/69253 - [6 Regression] g++ ICE at -O0 on x86_64-linux-gnu
+//                in "cxx_incomplete_type_diagnostic"
+// { dg-do compile }
+
+struct A {
+  int n;
+  char a [];
+};
+
+void f ()
+{
+  // Compound literals and flexible array members are G++ extensions
+  // accepted for compatibility with C and GCC.
+
+  // The following use of a flexible array member in a compound literal
+  // is invalid in C and rejected by GCC in C mode and so it's also
+  // rejected in C++ mode.
+  (struct A){ 1, "" };   // { dg-error "forbids compound-literals|initialization of a flexible array member|invalid use of a flexible array member" }
+}
diff --git a/gcc/testsuite/g++.dg/ext/flexary12.C b/gcc/testsuite/g++.dg/ext/flexary12.C
new file mode 100644
index 0000000..3d8c805
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/flexary12.C
@@ -0,0 +1,63 @@ 
+// PR c++/69290 - [6 Regression] g++ ICE on invalid initialization
+//     of a flexible array member
+// { dg-do compile }
+
+// Suppress pedantic errors about initialization of a flexible array member.
+// { dg-options "-Wno-pedantic" }
+
+struct A {
+  int a [];  // { dg-error "flexible array member .A::a. in an otherwise empty .struct A." }
+};
+
+void f1 ()
+{
+  // This is the meat of the test from c++/69290:
+  struct A a
+    = { "c" };   // { dg-error "invalid conversion from .const char\\*. to .int." }
+
+  (void)&a;
+}
+
+
+// Exercise other forms of invalid initialization besides the one in the bug.
+struct B {
+  int n;
+  int a [];
+};
+
+void f2 ()
+{
+  struct B b1
+    = { 0, "c" };   // { dg-error "invalid conversion from .const char\\*. to .int." }
+
+  (void)&b1;
+
+  const char s[] = "c";
+  struct B b2
+    = { 0, s };   // { dg-error "invalid conversion from .const char\\*. to .int." }
+
+  (void)&b2;
+}
+
+struct D {
+  int a [];  // { dg-error "flexible array member .D::a. in an otherwise empty .struct D." }
+  D ();
+};
+
+D::D ():
+  a ("c")   // { dg-error "incompatible types in assignment of .const char \\\[2\\\]. to .int \\\[\\\]." }
+{ }
+
+
+template <class T>
+struct C {
+  T a [];  // { dg-error "flexible array member" }
+};
+
+void f3 ()
+{
+  struct C<double> cd
+    = { "c" };   // { dg-error "cannot convert .const char\\*. to .double." }
+
+  (void)&cd;
+}
diff --git a/gcc/testsuite/g++.dg/ext/flexary13.C b/gcc/testsuite/g++.dg/ext/flexary13.C
new file mode 100644
index 0000000..462ed65
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/flexary13.C
@@ -0,0 +1,64 @@ 
+// { dg-do compile }
+// { dg-options -Wno-pedantic }
+
+#define STR(s) #s
+#define ASSERT(exp) \
+  ((exp) ? (void)0 : (void)(__builtin_printf ("%s:%i: assertion %s failed\n", \
+                     __FILE__, __LINE__, STR(exp)), \
+                      __builtin_abort ()))
+
+struct Ax { int n, a[]; };
+struct AAx { int i; Ax ax; };
+
+int i = 12345678;
+
+int main ()
+{
+  {
+    Ax s = { 0 };
+    ASSERT (s.n == 0);
+  }
+  {
+    Ax s =
+      { 0, { } };   // dg-warning "initialization of a flexible array member" }
+    ASSERT (s.n == 0);
+  }
+  {
+    Ax s =
+      { 1, { 2 } };   // dg-warning "initialization of a flexible array member" }
+    ASSERT (s.n == 1 && s.a [0] == 2);
+  }
+  {
+    Ax s =
+      { 2, { 3, 4 } }; // dg-warning "initialization of a flexible array member" }
+    ASSERT (s.n = 2 && s.a [0] == 3 && s.a [1] == 4);
+  }
+  {
+    Ax s =
+      { 123, i };   // dg-warning "initialization of a flexible array member" }
+    ASSERT (s.n == 123 && s.a [0] == i);
+  }
+  {
+    Ax s =
+      { 456, { i } }; // dg-warning "initialization of a flexible array member" }
+    ASSERT (s.n == 456 && s.a [0] == i);
+  }
+  {
+    int j = i + 1, k = j + 1;
+    Ax s =
+      { 3, { i, j, k } }; // dg-warning "initialization of a flexible array member" }
+    ASSERT (s.n == 3 && s.a [0] == i && s.a [1] == j && s.a [2] == k);
+  }
+
+  {
+    AAx s =
+      { 1, { 2 } };   // dg-warning "initialization of a flexible array member" }
+    ASSERT (s.i == 1 && s.ax.n == 2);
+  }
+
+  {
+    AAx s =
+      { 1, { 2, { 3 } } };   // dg-warning "initialization of a flexible array member" }
+    ASSERT (s.i == 1 && s.ax.n == 2 && s.ax.a [0] == 3);
+  }
+}
diff --git a/gcc/testsuite/g++.dg/ext/flexary14.C b/gcc/testsuite/g++.dg/ext/flexary14.C
new file mode 100644
index 0000000..7365357
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/flexary14.C
@@ -0,0 +1,17 @@ 
+// PR c++/69349 - template substitution error for flexible array members
+// { dg-do compile }
+
+template <class>
+struct A;
+
+template <class T>
+struct A<T[]> { typedef int X; };
+
+template <class T> int foo (T&, typename A<T>::X = 0) { return 0; }
+
+struct B { int n, a[]; };
+
+void bar (B *b)
+{
+    foo (b->a);
+}
diff --git a/gcc/testsuite/g++.dg/other/dump-ada-spec-2.C b/gcc/testsuite/g++.dg/other/dump-ada-spec-2.C
index d1af7e0..608b5be 100644
--- a/gcc/testsuite/g++.dg/other/dump-ada-spec-2.C
+++ b/gcc/testsuite/g++.dg/other/dump-ada-spec-2.C
@@ -7,5 +7,5 @@  struct S
   __extension__ unsigned char data[];
 };
 
-/* { dg-final { scan-ada-spec "array \\(0 .. 0\\)" } } */
+/* { dg-final { scan-ada-spec "array \\(size_t\\)" } } */
 /* { dg-final { cleanup-ada-spec } } */