diff mbox

[2/6] scalar-storage-order merge: C front-end

Message ID 2396877.AqT21tpnmO@polaris
State New
Headers show

Commit Message

Eric Botcazou June 16, 2015, 8:54 a.m. UTC
This is the C front-end + C family part.

	* doc/extend.texi (type attributes): Document scalar_storage_order.
	* doc/invoke.texi (Warnings): Document -Wno-scalar-storage-order.
c-family/
	* c-common.c (c_common_attributes): Add scalar_storage_order.
	(handle_scalar_storage_order_attribute): New function.
	* c.opt (Wscalar-storage-order): New warning.
c/
	* c-decl.c (finish_struct): If the structure has reverse scalar storage
	order, rewrite the type of array fields with scalar component.
	* c-typeck.c (build_unary_op) <ADDR_EXPR>: Remove left-overs.  Issue
	errors on bit-fields and reverse SSO here and not...
	(c_mark_addressable): ...here.

 doc/extend.texi     |   47 +++++++++++++++++++++++++++++++++++++++++++++
 doc/invoke.texi     |    6 +++++
 c-family/c.opt      |    4 +++
 c-family/c-common.c |   54 +++++++++++++++++++++++++++++++++++++++++++++++++-
 c/c-typeck.c        |   53 +++++++++++++++++++++++++++++++-------------------
 c/c-decl.c          |   45 +++++++++++++++++++++++++++++--------------
 6 files changed, 175 insertions(+), 34 deletions(-)

Comments

Ramana Radhakrishnan June 16, 2015, 9:06 a.m. UTC | #1
On 16/06/15 09:54, Eric Botcazou wrote:
> This is the C front-end + C family part.
>
> 	* doc/extend.texi (type attributes): Document scalar_storage_order.
> 	* doc/invoke.texi (Warnings): Document -Wno-scalar-storage-order.
> c-family/
> 	* c-common.c (c_common_attributes): Add scalar_storage_order.
> 	(handle_scalar_storage_order_attribute): New function.
> 	* c.opt (Wscalar-storage-order): New warning.
> c/
> 	* c-decl.c (finish_struct): If the structure has reverse scalar storage
> 	order, rewrite the type of array fields with scalar component.
> 	* c-typeck.c (build_unary_op) <ADDR_EXPR>: Remove left-overs.  Issue
> 	errors on bit-fields and reverse SSO here and not...
> 	(c_mark_addressable): ...here.
>
>   doc/extend.texi     |   47 +++++++++++++++++++++++++++++++++++++++++++++
>   doc/invoke.texi     |    6 +++++
>   c-family/c.opt      |    4 +++
>   c-family/c-common.c |   54 +++++++++++++++++++++++++++++++++++++++++++++++++-
>   c/c-typeck.c        |   53 +++++++++++++++++++++++++++++++-------------------
>   c/c-decl.c          |   45 +++++++++++++++++++++++++++++--------------
>   6 files changed, 175 insertions(+), 34 deletions(-)
>

A very cursory glance at the patch set but should we restrict this 
attribute to apply only to scalar types rather than allow them on vector 
extensions.  I haven't had enough coffee this morning but a first 
thought is that if it does apply on vector type extensions, clarifying 
the lane ordering up front would be helpful especially as we now allow 
indexing into short vectors.


regards
Ramana
Andrew Pinski June 16, 2015, 9:10 a.m. UTC | #2
On Tue, Jun 16, 2015 at 2:06 AM, Ramana Radhakrishnan
<ramana.radhakrishnan@foss.arm.com> wrote:
>
>
> On 16/06/15 09:54, Eric Botcazou wrote:
>>
>> This is the C front-end + C family part.
>>
>>         * doc/extend.texi (type attributes): Document
>> scalar_storage_order.
>>         * doc/invoke.texi (Warnings): Document -Wno-scalar-storage-order.
>> c-family/
>>         * c-common.c (c_common_attributes): Add scalar_storage_order.
>>         (handle_scalar_storage_order_attribute): New function.
>>         * c.opt (Wscalar-storage-order): New warning.
>> c/
>>         * c-decl.c (finish_struct): If the structure has reverse scalar
>> storage
>>         order, rewrite the type of array fields with scalar component.
>>         * c-typeck.c (build_unary_op) <ADDR_EXPR>: Remove left-overs.
>> Issue
>>         errors on bit-fields and reverse SSO here and not...
>>         (c_mark_addressable): ...here.
>>
>>   doc/extend.texi     |   47 +++++++++++++++++++++++++++++++++++++++++++++
>>   doc/invoke.texi     |    6 +++++
>>   c-family/c.opt      |    4 +++
>>   c-family/c-common.c |   54
>> +++++++++++++++++++++++++++++++++++++++++++++++++-
>>   c/c-typeck.c        |   53
>> +++++++++++++++++++++++++++++++-------------------
>>   c/c-decl.c          |   45 +++++++++++++++++++++++++++++--------------
>>   6 files changed, 175 insertions(+), 34 deletions(-)
>>
>
> A very cursory glance at the patch set but should we restrict this attribute
> to apply only to scalar types rather than allow them on vector extensions.
> I haven't had enough coffee this morning but a first thought is that if it
> does apply on vector type extensions, clarifying the lane ordering up front
> would be helpful especially as we now allow indexing into short vectors.

I think it applies to vector types but really it acts the same way as
we apply attributes on arrays, that is on the inner scalar type
instead.

Thanks,
Andrew

>
>
> regards
> Ramana
>
>
>
Richard Sandiford June 16, 2015, 11:28 a.m. UTC | #3
Eric Botcazou <ebotcazou@adacore.com> writes:
> This is the C front-end + C family part.
>
> 	* doc/extend.texi (type attributes): Document scalar_storage_order.
> 	* doc/invoke.texi (Warnings): Document -Wno-scalar-storage-order.
> c-family/
> 	* c-common.c (c_common_attributes): Add scalar_storage_order.
> 	(handle_scalar_storage_order_attribute): New function.
> 	* c.opt (Wscalar-storage-order): New warning.
> c/
> 	* c-decl.c (finish_struct): If the structure has reverse scalar storage
> 	order, rewrite the type of array fields with scalar component.
> 	* c-typeck.c (build_unary_op) <ADDR_EXPR>: Remove left-overs.  Issue
> 	errors on bit-fields and reverse SSO here and not...
> 	(c_mark_addressable): ...here.
>
>  doc/extend.texi     |   47 +++++++++++++++++++++++++++++++++++++++++++++
>  doc/invoke.texi     |    6 +++++
>  c-family/c.opt      |    4 +++
>  c-family/c-common.c |   54 +++++++++++++++++++++++++++++++++++++++++++++++++-
>  c/c-typeck.c        |   53 +++++++++++++++++++++++++++++++-------------------
>  c/c-decl.c          |   45 +++++++++++++++++++++++++++++--------------
>  6 files changed, 175 insertions(+), 34 deletions(-)

Sorry for the nit, but:

> +@itemize
> +@item Taking the address of a scalar field of a @code{union} or a
> +@code{struct} with reverse scalar storage order is illegal and will
> +yield an error
> +@item Taking the address of an array field, whose component is scalar, of
> +a @code{union} or a @code{struct} with reverse scalar storage order is
> +permitted but will yield a warning, unless @option{-Wno-scalar-storage-order}
> +is specified
> +@item Taking the address of a @code{union} or a @code{struct} with reverse
> +scalar storage order is permitted
> +@end itemize

"illegal" -> "invalid" or "not permitted"

Thanks,
Richard
Joseph Myers June 16, 2015, 9:23 p.m. UTC | #4
On Tue, 16 Jun 2015, Eric Botcazou wrote:

> +@item unused
> +@cindex @code{unused} type attribute
> +When attached to a type (including a @code{union} or a @code{struct}),
> +this attribute means that variables of that type are meant to appear
> +possibly unused.  GCC does not produce a warning for any variables of
> +that type, even if the variable appears to do nothing.  This is often
> +the case with lock or thread classes, which are usually defined and then
> +not referenced, but contain constructors and destructors that have
> +nontrivial bookkeeping functions.

You appear to be duplicating the documentation of an unrelated attribute.

What happens when typeof is applied to a field with reversed storage 
order?

> +      else if (TYPE_REVERSE_STORAGE_ORDER (t)
> +	       && TREE_CODE (field) == FIELD_DECL
> +	       && TREE_CODE (TREE_TYPE (field)) == ARRAY_TYPE)
> +	{
> +	  tree ftype = TREE_TYPE (field);
> +	  do
> +	    ftype = TREE_TYPE (ftype);
> +	  while (TREE_CODE (ftype) == ARRAY_TYPE);
> +	  if (!RECORD_OR_UNION_TYPE_P (ftype))
> +	    {
> +	      tree *ftypep = &TREE_TYPE (field);
> +	      do {
> +		*ftypep = build_distinct_type_copy (*ftypep);
> +		TYPE_REVERSE_STORAGE_ORDER (*ftypep) = 1;
> +		ftypep = &TREE_TYPE (*ftypep);
> +	      } while (TREE_CODE (*ftypep) == ARRAY_TYPE);

I don't think this type construction is safe when the array type has 
qualified element type.  The following invariant is meant to hold: for an 
array type whose element type (possibly after going down through several 
levels of array types) is qualified, the TYPE_MAIN_VARIANT is a 
corresponding array type whose element type is unqualified.  So in that 
case you need to build two sequences of array types, not one: the main 
variants with unqualified element type, and the versions with qualified 
element type.  See c_build_qualified_type.
Eric Botcazou June 18, 2015, 7:08 p.m. UTC | #5
> A very cursory glance at the patch set but should we restrict this
> attribute to apply only to scalar types rather than allow them on vector
> extensions.  I haven't had enough coffee this morning but a first
> thought is that if it does apply on vector type extensions, clarifying
> the lane ordering up front would be helpful especially as we now allow
> indexing into short vectors.

That's reasonable, and the name would sort of imply it, although the current 
implementation doesn't do that (but wasn't really tested with vector types).
Eric Botcazou June 18, 2015, 7:16 p.m. UTC | #6
> "illegal" -> "invalid" or "not permitted"

The ISO standard for Ada contains this (1.1.2 Structure):

Legality Rules
27 Rules that are enforced at compile time. A construct is legal if it obeys 
all of the Legality Rules. 

and "illegal" is documented in the Index.

But the standard for C doesn't, so I'll change the wording, thanks.
Eric Botcazou June 19, 2015, 9:27 a.m. UTC | #7
> You appear to be duplicating the documentation of an unrelated attribute.

Merge glitch, now fixed, thanks.

> What happens when typeof is applied to a field with reversed storage
> order?

You mean a scalar field contained in an aggregate type with reverse SSO?  Then 
nothing, nothing is changed for scalars on an individual basis, only their 
presence inside an aggregate type with reverse SSO changes something.

> I don't think this type construction is safe when the array type has
> qualified element type.  The following invariant is meant to hold: for an
> array type whose element type (possibly after going down through several
> levels of array types) is qualified, the TYPE_MAIN_VARIANT is a
> corresponding array type whose element type is unqualified.  So in that
> case you need to build two sequences of array types, not one: the main
> variants with unqualified element type, and the versions with qualified
> element type.  See c_build_qualified_type.

I see, will adjust, thanks for the tip.
diff mbox

Patch

Index: gcc/doc/extend.texi
===================================================================
--- gcc/doc/extend.texi	(.../trunk)	(revision 224461)
+++ gcc/doc/extend.texi	(.../branches/scalar-storage-order)	(revision 224467)
@@ -6064,6 +6064,53 @@  S *p = (S *)malloc (sizeof(S) + 100);
 p->data[10] = 0; //OK
 @end smallexample
 
+@item scalar_storage_order
+@itemx scalar_storage_order ("@var{endianness}")
+@cindex @code{scalar_storage_order} type attribute
+When attached to a @code{union} or a @code{struct}, this attribute sets
+the storage order, aka endianness, of the scalar fields of the type, as
+well as the array fields whose component is scalar.  The supported
+endianness are @code{big-endian} and @code{little-endian}.  The attribute
+has no effects on fields which are themselves a @code{union}, a @code{struct}
+or an array whose component is a @code{union} or a @code{struct}, and it is
+possible to have fields with a different scalar storage order than the
+enclosing type.
+
+This attribute is supported only for targets that use a uniform default
+scalar storage order (fortunately, most of them), i.e. targets that store
+the scalars either all in big-endian or all in little-endian.
+
+Additional restrictions are enforced for types with the reverse scalar
+storage order with regard to the scalar storage order of the target:
+
+@itemize
+@item Taking the address of a scalar field of a @code{union} or a
+@code{struct} with reverse scalar storage order is illegal and will
+yield an error
+@item Taking the address of an array field, whose component is scalar, of
+a @code{union} or a @code{struct} with reverse scalar storage order is
+permitted but will yield a warning, unless @option{-Wno-scalar-storage-order}
+is specified
+@item Taking the address of a @code{union} or a @code{struct} with reverse
+scalar storage order is permitted
+@end itemize
+
+These restrictions exist because the storage order attribute is lost when
+the address of a scalar or the address of an array with scalar component
+is taken, so storing indirectly through this address will generally not work.
+The second case is nevertheless allowed to be able to perform a block copy
+from or to the array.
+
+@item unused
+@cindex @code{unused} type attribute
+When attached to a type (including a @code{union} or a @code{struct}),
+this attribute means that variables of that type are meant to appear
+possibly unused.  GCC does not produce a warning for any variables of
+that type, even if the variable appears to do nothing.  This is often
+the case with lock or thread classes, which are usually defined and then
+not referenced, but contain constructors and destructors that have
+nontrivial bookkeeping functions.
+
 @item deprecated
 @itemx deprecated (@var{msg})
 @cindex @code{deprecated} type attribute
Index: gcc/doc/invoke.texi
===================================================================
--- gcc/doc/invoke.texi	(.../trunk)	(revision 224461)
+++ gcc/doc/invoke.texi	(.../branches/scalar-storage-order)	(revision 224467)
@@ -275,6 +275,7 @@  Objective-C and Objective-C++ Dialects}.
 -Wreturn-type  -Wsequence-point  -Wshadow  -Wno-shadow-ivar @gol
 -Wshift-count-negative -Wshift-count-overflow -Wshift-negative-value @gol
 -Wsign-compare  -Wsign-conversion -Wfloat-conversion @gol
+-Wno-scalar-storage-order @gol
 -Wsizeof-pointer-memaccess  -Wsizeof-array-argument @gol
 -Wstack-protector -Wstack-usage=@var{len} -Wstrict-aliasing @gol
 -Wstrict-aliasing=n @gol -Wstrict-overflow -Wstrict-overflow=@var{n} @gol
@@ -4938,6 +4939,11 @@  This includes conversions from real to i
 real to lower precision real values.  This option is also enabled by
 @option{-Wconversion}.
 
+@item -Wno-scalar-storage-order
+@opindex -Wno-scalar-storage-order
+@opindex -Wscalar-storage-order
+Do not warn on suspicious constructs involving reverse scalar storage order.
+
 @item -Wsized-deallocation @r{(C++ and Objective-C++ only)}
 @opindex Wsized-deallocation
 @opindex Wno-sized-deallocation
Index: gcc/c-family/c.opt
===================================================================
--- gcc/c-family/c.opt	(.../trunk)	(revision 224461)
+++ gcc/c-family/c.opt	(.../branches/scalar-storage-order)	(revision 224467)
@@ -768,6 +768,10 @@  Wreturn-type
 C ObjC C++ ObjC++ Var(warn_return_type) Warning LangEnabledBy(C ObjC C++ ObjC++,Wall)
 Warn whenever a function's return type defaults to \"int\" (C), or about inconsistent return types (C++)
 
+Wscalar-storage-order
+C ObjC C++ ObjC++ Init(1) Warning
+Warn on suspicious constructs involving reverse scalar storage order
+
 Wselector
 ObjC ObjC++ Var(warn_selector) Warning
 Warn if a selector has multiple methods
Index: gcc/c-family/c-common.c
===================================================================
--- gcc/c-family/c-common.c	(.../trunk)	(revision 224461)
+++ gcc/c-family/c-common.c	(.../branches/scalar-storage-order)	(revision 224467)
@@ -346,6 +346,8 @@  static tree handle_no_reorder_attribute
 static tree handle_const_attribute (tree *, tree, tree, int, bool *);
 static tree handle_transparent_union_attribute (tree *, tree, tree,
 						int, bool *);
+static tree handle_scalar_storage_order_attribute (tree *, tree, tree,
+						   int, bool *);
 static tree handle_constructor_attribute (tree *, tree, tree, int, bool *);
 static tree handle_destructor_attribute (tree *, tree, tree, int, bool *);
 static tree handle_mode_attribute (tree *, tree, tree, int, bool *);
@@ -690,6 +692,8 @@  const struct attribute_spec c_common_att
 			      handle_const_attribute, false },
   { "transparent_union",      0, 0, false, false, false,
 			      handle_transparent_union_attribute, false },
+  { "scalar_storage_order",   1, 1, false, false, false,
+			      handle_scalar_storage_order_attribute, false },
   { "constructor",            0, 1, true,  false, false,
 			      handle_constructor_attribute, false },
   { "destructor",             0, 1, true,  false, false,
@@ -7502,7 +7506,6 @@  handle_transparent_union_attribute (tree
 
   *no_add_attrs = true;
 
-
   if (TREE_CODE (*node) == TYPE_DECL
       && ! (flags & ATTR_FLAG_CXX11))
     node = &TREE_TYPE (*node);
@@ -7542,6 +7545,55 @@  handle_transparent_union_attribute (tree
       return NULL_TREE;
     }
 
+ ignored:
+  warning (OPT_Wattributes, "%qE attribute ignored", name);
+  return NULL_TREE;
+}
+
+/* Handle a "scalar_storage_order" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+static tree
+handle_scalar_storage_order_attribute (tree *node, tree name, tree args,
+				       int flags, bool *no_add_attrs)
+{
+  tree id = TREE_VALUE (args);
+  tree type;
+
+  *no_add_attrs = true;
+
+  if (TREE_CODE (*node) == TYPE_DECL
+      && ! (flags & ATTR_FLAG_CXX11))
+    node = &TREE_TYPE (*node);
+  type = *node;
+
+  if (BYTES_BIG_ENDIAN != WORDS_BIG_ENDIAN)
+    error ("scalar_storage_order is not supported");
+
+  if (RECORD_OR_UNION_TYPE_P (type))
+    {
+      if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE))
+	goto ignored;
+
+      if (TREE_CODE (id) == STRING_CST
+	  && strcmp (TREE_STRING_POINTER (id), "big-endian") == 0)
+	{
+	  if (!BYTES_BIG_ENDIAN)
+	    TYPE_REVERSE_STORAGE_ORDER (type) = 1;
+	}
+      else if (TREE_CODE (id) == STRING_CST
+	       && strcmp (TREE_STRING_POINTER (id), "little-endian") == 0)
+	{
+	  if (BYTES_BIG_ENDIAN)
+	    TYPE_REVERSE_STORAGE_ORDER (type) = 1;
+	}
+      else
+	error ("scalar_storage_order argument must be one of \"big-endian\" "
+	       "or \"little-endian\"");
+
+      return NULL_TREE;
+    }
+
  ignored:
   warning (OPT_Wattributes, "%qE attribute ignored", name);
   return NULL_TREE;
Index: gcc/c/c-typeck.c
===================================================================
--- gcc/c/c-typeck.c	(.../trunk)	(revision 224461)
+++ gcc/c/c-typeck.c	(.../branches/scalar-storage-order)	(revision 224467)
@@ -4163,18 +4163,10 @@  build_unary_op (location_t location,
 	  goto return_build_unary_op;
 	}
 
-      /* For &x[y], return x+y */
-      if (TREE_CODE (arg) == ARRAY_REF)
-	{
-	  tree op0 = TREE_OPERAND (arg, 0);
-	  if (!c_mark_addressable (op0))
-	    return error_mark_node;
-	}
-
       /* Anything not already handled and not a true memory reference
 	 or a non-lvalue array is an error.  */
-      else if (typecode != FUNCTION_TYPE && !flag
-	       && !lvalue_or_else (location, arg, lv_addressof))
+      if (typecode != FUNCTION_TYPE && !flag
+	  && !lvalue_or_else (location, arg, lv_addressof))
 	return error_mark_node;
 
       /* Move address operations inside C_MAYBE_CONST_EXPR to simplify
@@ -4212,6 +4204,38 @@  build_unary_op (location_t location,
 	  argtype = c_build_qualified_type (argtype, quals);
 	}
 
+      switch (TREE_CODE (arg))
+	{
+	case COMPONENT_REF:
+	  if (DECL_C_BIT_FIELD (TREE_OPERAND (arg, 1)))
+	    {
+	      error ("cannot take address of bit-field %qD",
+		     TREE_OPERAND (arg, 1));
+	      return error_mark_node;
+	    }
+
+	  /* ... fall through ...  */
+
+	case ARRAY_REF:
+	  if (TYPE_REVERSE_STORAGE_ORDER (TREE_TYPE (TREE_OPERAND (arg, 0))))
+	    {
+	      if (!AGGREGATE_TYPE_P (TREE_TYPE (arg)))
+		{
+		  error ("cannot take address of scalar with reverse storage "
+			 "order");
+		  return error_mark_node;
+		}
+
+	      if (TREE_CODE (TREE_TYPE (arg)) == ARRAY_TYPE
+		  && TYPE_REVERSE_STORAGE_ORDER (TREE_TYPE (arg)))
+		warning (OPT_Wscalar_storage_order, "address of array with "
+			"reverse scalar storage order requested");
+	    }
+
+	default:
+	  break;
+	}
+
       if (!c_mark_addressable (arg))
 	return error_mark_node;
 
@@ -4354,15 +4378,6 @@  c_mark_addressable (tree exp)
     switch (TREE_CODE (x))
       {
       case COMPONENT_REF:
-	if (DECL_C_BIT_FIELD (TREE_OPERAND (x, 1)))
-	  {
-	    error
-	      ("cannot take address of bit-field %qD", TREE_OPERAND (x, 1));
-	    return false;
-	  }
-
-	/* ... fall through ...  */
-
       case ADDR_EXPR:
       case ARRAY_REF:
       case REALPART_EXPR:
Index: gcc/c/c-decl.c
===================================================================
--- gcc/c/c-decl.c	(.../trunk)	(revision 224461)
+++ gcc/c/c-decl.c	(.../branches/scalar-storage-order)	(revision 224467)
@@ -7732,27 +7732,44 @@  finish_struct (location_t loc, tree t, t
       && !valid_constant_size_p (TYPE_SIZE_UNIT (t)))
     error ("type %qT is too large", t);
 
-  /* Give bit-fields their proper types.  */
-  {
-    tree *fieldlistp = &fieldlist;
-    while (*fieldlistp)
-      if (TREE_CODE (*fieldlistp) == FIELD_DECL && DECL_INITIAL (*fieldlistp)
-	  && TREE_TYPE (*fieldlistp) != error_mark_node)
+  /* Give bit-fields their proper types and rewrite the type of array fields
+     if the enclosing type has reverse storage order.  */
+  for (tree field = fieldlist; field; field = DECL_CHAIN (field))
+    {
+      if (TREE_CODE (field) == FIELD_DECL
+	  && DECL_INITIAL (field)
+	  && TREE_TYPE (field) != error_mark_node)
 	{
 	  unsigned HOST_WIDE_INT width
-	    = tree_to_uhwi (DECL_INITIAL (*fieldlistp));
-	  tree type = TREE_TYPE (*fieldlistp);
+	    = tree_to_uhwi (DECL_INITIAL (field));
+	  tree type = TREE_TYPE (field);
 	  if (width != TYPE_PRECISION (type))
 	    {
-	      TREE_TYPE (*fieldlistp)
+	      TREE_TYPE (field)
 		= c_build_bitfield_integer_type (width, TYPE_UNSIGNED (type));
-	      DECL_MODE (*fieldlistp) = TYPE_MODE (TREE_TYPE (*fieldlistp));
+	      DECL_MODE (field) = TYPE_MODE (TREE_TYPE (field));
 	    }
-	  DECL_INITIAL (*fieldlistp) = 0;
+	  DECL_INITIAL (field) = 0;
 	}
-      else
-	fieldlistp = &DECL_CHAIN (*fieldlistp);
-  }
+      else if (TYPE_REVERSE_STORAGE_ORDER (t)
+	       && TREE_CODE (field) == FIELD_DECL
+	       && TREE_CODE (TREE_TYPE (field)) == ARRAY_TYPE)
+	{
+	  tree ftype = TREE_TYPE (field);
+	  do
+	    ftype = TREE_TYPE (ftype);
+	  while (TREE_CODE (ftype) == ARRAY_TYPE);
+	  if (!RECORD_OR_UNION_TYPE_P (ftype))
+	    {
+	      tree *ftypep = &TREE_TYPE (field);
+	      do {
+		*ftypep = build_distinct_type_copy (*ftypep);
+		TYPE_REVERSE_STORAGE_ORDER (*ftypep) = 1;
+		ftypep = &TREE_TYPE (*ftypep);
+	      } while (TREE_CODE (*ftypep) == ARRAY_TYPE);
+	    }
+	}
+    }
 
   /* Now we have the truly final field list.
      Store it in this type and in the variants.  */