tree returned_attrs = NULL_TREE;
   bool bitfield = width != NULL;
   tree element_type;
+  tree orig_qual_type = NULL;
+  size_t orig_qual_indirect = 0;
   struct c_arg_info *arg_info = 0;
   addr_space_t as1, as2, address_space;
   location_t loc = UNKNOWN_LOCATION;
        case cdk_function:
        case cdk_pointer:
          funcdef_syntax = (decl->kind == cdk_function);
-         decl = decl->declarator;
          if (first_non_attr_kind == cdk_attrs)
            first_non_attr_kind = decl->kind;
+         decl = decl->declarator;
          break;
 
        case cdk_attrs:
   if ((TREE_CODE (type) == ARRAY_TYPE
        || first_non_attr_kind == cdk_array)
       && TYPE_QUALS (element_type))
-    type = TYPE_MAIN_VARIANT (type);
+    {
+      orig_qual_type = type;
+      type = TYPE_MAIN_VARIANT (type);
+    }
   type_quals = ((constp ? TYPE_QUAL_CONST : 0)
                | (restrictp ? TYPE_QUAL_RESTRICT : 0)
                | (volatilep ? TYPE_QUAL_VOLATILE : 0)
                | (atomicp ? TYPE_QUAL_ATOMIC : 0)
                | ENCODE_QUAL_ADDR_SPACE (address_space));
+  if (type_quals != TYPE_QUALS (element_type))
+    orig_qual_type = NULL_TREE;
 
   /* Applying the _Atomic qualifier to an array type (through the use
      of typedefs or typeof) must be detected here.  If the qualifier
                array_ptr_attrs = NULL_TREE;
                array_parm_static = 0;
              }
+           orig_qual_indirect++;
            break;
          }
        case cdk_function:
               attributes.  */
            bool really_funcdef = false;
            tree arg_types;
+           orig_qual_type = NULL_TREE;
            if (funcdef_flag)
              {
                const struct c_declarator *t = declarator->declarator;
              pedwarn (loc, OPT_Wpedantic,
                       "ISO C forbids qualified function types");
            if (type_quals)
-             type = c_build_qualified_type (type, type_quals);
+             type = c_build_qualified_type (type, type_quals, orig_qual_type,
+                                            orig_qual_indirect);
+           orig_qual_type = NULL_TREE;
            size_varies = false;
 
            /* When the pointed-to type involves components of variable size,
        pedwarn (loc, OPT_Wpedantic,
                 "ISO C forbids qualified function types");
       if (type_quals)
-       type = c_build_qualified_type (type, type_quals);
+       type = c_build_qualified_type (type, type_quals, orig_qual_type,
+                                      orig_qual_indirect);
       decl = build_decl (declarator->id_loc,
                         TYPE_DECL, declarator->u.id, type);
       if (declspecs->explicit_signed_p)
        pedwarn (loc, OPT_Wpedantic,
                 "ISO C forbids const or volatile function types");
       if (type_quals)
-       type = c_build_qualified_type (type, type_quals);
+       type = c_build_qualified_type (type, type_quals, orig_qual_type,
+                                      orig_qual_indirect);
       return type;
     }
 
            /* Transfer const-ness of array into that of type pointed to.  */
            type = TREE_TYPE (type);
            if (type_quals)
-             type = c_build_qualified_type (type, type_quals);
+             type = c_build_qualified_type (type, type_quals, orig_qual_type,
+                                            orig_qual_indirect);
            type = c_build_pointer_type (type);
            type_quals = array_ptr_quals;
            if (type_quals)
            TYPE_DOMAIN (type) = build_range_type (sizetype, size_zero_node,
                                                   NULL_TREE);
          }
-       type = c_build_qualified_type (type, type_quals);
+       type = c_build_qualified_type (type, type_quals, orig_qual_type,
+                                      orig_qual_indirect);
        decl = build_decl (declarator->id_loc,
                           FIELD_DECL, declarator->u.id, type);
        DECL_NONADDRESSABLE_P (decl) = bitfield;
        /* An uninitialized decl with `extern' is a reference.  */
        int extern_ref = !initialized && storage_class == csc_extern;
 
-       type = c_build_qualified_type (type, type_quals);
+       type = c_build_qualified_type (type, type_quals, orig_qual_type,
+                                      orig_qual_indirect);
 
        /* C99 6.2.2p7: It is invalid (compile-time undefined
           behavior) to create an 'extern' declaration for a
 
 }
 
 /* Make a variant type in the proper way for C/C++, propagating qualifiers
-   down to the element type of an array.  */
+   down to the element type of an array.  If ORIG_QUAL_TYPE is not
+   NULL, then it should be used as the qualified type
+   ORIG_QUAL_INDIRECT levels down in array type derivation (to
+   preserve information about the typedef name from which an array
+   type was derived).  */
 
 tree
-c_build_qualified_type (tree type, int type_quals)
+c_build_qualified_type (tree type, int type_quals, tree orig_qual_type,
+                       size_t orig_qual_indirect)
 {
   if (type == error_mark_node)
     return type;
     {
       tree t;
       tree element_type = c_build_qualified_type (TREE_TYPE (type),
-                                                 type_quals);
+                                                 type_quals, orig_qual_type,
+                                                 orig_qual_indirect - 1);
 
       /* See if we already have an identically qualified type.  */
-      for (t = TYPE_MAIN_VARIANT (type); t; t = TYPE_NEXT_VARIANT (t))
-       {
-         if (TYPE_QUALS (strip_array_types (t)) == type_quals
-             && TYPE_NAME (t) == TYPE_NAME (type)
-             && TYPE_CONTEXT (t) == TYPE_CONTEXT (type)
-             && attribute_list_equal (TYPE_ATTRIBUTES (t),
-                                      TYPE_ATTRIBUTES (type)))
-           break;
-       }
+      if (orig_qual_type && orig_qual_indirect == 0)
+       t = orig_qual_type;
+      else
+       for (t = TYPE_MAIN_VARIANT (type); t; t = TYPE_NEXT_VARIANT (t))
+         {
+           if (TYPE_QUALS (strip_array_types (t)) == type_quals
+               && TYPE_NAME (t) == TYPE_NAME (type)
+               && TYPE_CONTEXT (t) == TYPE_CONTEXT (type)
+               && attribute_list_equal (TYPE_ATTRIBUTES (t),
+                                        TYPE_ATTRIBUTES (type)))
+             break;
+         }
       if (!t)
        {
           tree domain = TYPE_DOMAIN (type);
       type_quals &= ~TYPE_QUAL_RESTRICT;
     }
 
-  tree var_type = build_qualified_type (type, type_quals);
+  tree var_type = (orig_qual_type && orig_qual_indirect == 0
+                  ? orig_qual_type
+                  : build_qualified_type (type, type_quals));
   /* A variant type does not inherit the list of incomplete vars from the
      type main variant.  */
   if (RECORD_OR_UNION_TYPE_P (var_type))