On 05/19/2016 07:30 AM, Jason Merrill wrote:
On 05/18/2016 09:40 PM, Martin Sebor wrote:
The handling of flexible array members whose element type was
dependent tried to deal with the case when the element type
was not yet completed but it did it wrong.  The attached patch
corrects the handling by trying to complete the element type
first.

How about changing complete_type to complete the element type even for
an array of unknown bound?  It seems to me that it would be useful to do
that to set alignment and 'structor flags even if we can't set TYPE_SIZE.

It would also be useful to have a 'complete type or array of unknown
bound of complete type' predicate to use here and in layout_var_decl,
grokdeclarator, and type_with_alias_set_p.

Thanks for the suggestions.  I implemented them in the attached
update to the the patch.  The macro I added evaluates its argument
multiple times.  That normally isn't a problem unless it's invoked
with a non-trivial argument like a call to complete_type() that's
passed to COMPLETE_TYPE_P() in grokdeclarator.  One way to avoid
possible problems due to evaluating the macro argument more than
once is to introduce a helper inline functionn.  I haven't seen
it done in tree.h so I didn't introduce one in this patch either,
but it might be worth considering for the new macro and any other
non-trivial macros like it.

Martin
PR c++/71147 - [6 Regression] Flexible array member wrongly rejected in template

gcc/ChangeLog:
2016-05-23  Martin Sebor  <mse...@redhat.com>

	PR c++/71147
	* gcc/tree.h (COMPLETE_OR_ARRAY_TYPE_P): New macro.

gcc/testsuite/ChangeLog:
2016-05-23  Martin Sebor  <mse...@redhat.com>

	PR c++/71147
	* g++.dg/ext/flexary16.C: New test.

gcc/cp/ChangeLog:
2016-05-23  Martin Sebor  <mse...@redhat.com>

	PR c++/71147
	* decl.c (layout_var_decl, grokdeclarator): Use COMPLETE_OR_ARRAY_TYPE_P.
	* pt.c (instantiate_class_template_1): Try to complete the element
	type of a flexible array member.
	(can_complete_type_without_circularity): Handle arrays of unknown bound.
	* typeck.c (complete_type): Also complete the type of the elements of
	arrays with an unspecified bound.

diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 7a69711..82bbe19 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -5305,10 +5305,7 @@ layout_var_decl (tree decl)
     complete_type (type);
   if (!DECL_SIZE (decl)
       && TREE_TYPE (decl) != error_mark_node
-      && (COMPLETE_TYPE_P (type)
-	  || (TREE_CODE (type) == ARRAY_TYPE
-	      && !TYPE_DOMAIN (type)
-	      && COMPLETE_TYPE_P (TREE_TYPE (type)))))
+      && COMPLETE_OR_ARRAY_TYPE_P (type))
     layout_decl (decl, 0);
 
   if (!DECL_EXTERNAL (decl) && DECL_SIZE (decl) == NULL_TREE)
@@ -11165,8 +11162,7 @@ grokdeclarator (const cp_declarator *declarator,
 	  }
 	else if (!staticp && !dependent_type_p (type)
 		 && !COMPLETE_TYPE_P (complete_type (type))
-		 && (TREE_CODE (type) != ARRAY_TYPE
-		     || !COMPLETE_TYPE_P (TREE_TYPE (type))
+		 && (!COMPLETE_OR_ARRAY_TYPE_P (type)
 		     || initialized == 0))
 	  {
 	    if (TREE_CODE (type) != ARRAY_TYPE
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 2bba571..04ae378 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -9554,7 +9554,7 @@ can_complete_type_without_circularity (tree type)
     return 0;
   else if (COMPLETE_TYPE_P (type))
     return 1;
-  else if (TREE_CODE (type) == ARRAY_TYPE && TYPE_DOMAIN (type))
+  else if (TREE_CODE (type) == ARRAY_TYPE)
     return can_complete_type_without_circularity (TREE_TYPE (type));
   else if (CLASS_TYPE_P (type)
 	   && TYPE_BEING_DEFINED (TYPE_MAIN_VARIANT (type)))
@@ -10119,17 +10119,12 @@ instantiate_class_template_1 (tree type)
 			  if (can_complete_type_without_circularity (rtype))
 			    complete_type (rtype);
 
-                          if (TREE_CODE (r) == FIELD_DECL
-                              && TREE_CODE (rtype) == ARRAY_TYPE
-                              && COMPLETE_TYPE_P (TREE_TYPE (rtype))
-                              && !COMPLETE_TYPE_P (rtype))
-                            {
-                              /* Flexible array mmembers of elements
-                                 of complete type have an incomplete type
-                                 and that's okay.  */
-                            }
-                          else if (!COMPLETE_TYPE_P (rtype))
+			  if (!COMPLETE_OR_ARRAY_TYPE_P (rtype))
 			    {
+			      /* If R's type couldn't be completed and
+				 it isn't a flexible array member (whose
+				 type is incomplete by definition) give
+				 an error.  */
 			      cxx_incomplete_type_error (r, rtype);
 			      TREE_TYPE (r) = error_mark_node;
 			    }
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index cd058fa..2688ab4 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -112,7 +112,7 @@ complete_type (tree type)
 
   if (type == error_mark_node || COMPLETE_TYPE_P (type))
     ;
-  else if (TREE_CODE (type) == ARRAY_TYPE && TYPE_DOMAIN (type))
+  else if (TREE_CODE (type) == ARRAY_TYPE)
     {
       tree t = complete_type (TREE_TYPE (type));
       unsigned int needs_constructing, has_nontrivial_dtor;
diff --git a/gcc/testsuite/g++.dg/ext/flexary16.C b/gcc/testsuite/g++.dg/ext/flexary16.C
new file mode 100644
index 0000000..a3e040d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/flexary16.C
@@ -0,0 +1,37 @@
+// PR c++/71147 - [6 Regression] Flexible array member wrongly rejected
+//   in template
+// { dg-do compile }
+
+template <typename>
+struct container
+{
+  struct elem {
+    unsigned u;
+  };
+
+  struct incomplete {
+    int x;
+    elem array[];
+  };
+};
+
+unsigned f (container<void>::incomplete* i)
+{
+  return i->array [0].u;
+}
+
+
+template <typename T>
+struct D: container<T>
+{
+  struct S {
+    int x;
+    typename container<T>::elem array[];
+  };
+};
+
+
+unsigned g (D<void>::S *s)
+{
+  return s->array [0].u;
+}
diff --git a/gcc/tree.h b/gcc/tree.h
index 2510d16..d18ba9e 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -607,6 +607,12 @@ extern void omp_clause_range_check_failed (const_tree, const char *, int,
 /* Nonzero if this type is a complete type.  */
 #define COMPLETE_TYPE_P(NODE) (TYPE_SIZE (NODE) != NULL_TREE)
 
+/* Nonzero if this is a complete type or an array of unknown bound
+   (whose type is incomplete but) whose elements have complete type.  */
+#define COMPLETE_OR_ARRAY_TYPE_P(NODE)					\
+  (COMPLETE_TYPE_P (NODE)						\
+   || (TREE_CODE (NODE) == ARRAY_TYPE && COMPLETE_TYPE_P (TREE_TYPE (NODE))))
+
 /* Nonzero if this type is a pointer bounds type.  */
 #define POINTER_BOUNDS_TYPE_P(NODE) \
   (TREE_CODE (NODE) == POINTER_BOUNDS_TYPE)

Reply via email to