+2020-05-14  Richard Sandiford  <richard.sandiford@arm.com>
+
+       PR target/95105
+       * config/aarch64/aarch64-sve-builtins.cc
+       (handle_arm_sve_vector_bits_attribute): Create a copy of the
+       original type's TYPE_MAIN_VARIANT, then reapply all the differences
+       between the original type and its main variant.
+
 2020-05-14  Richard Biener  <rguenther@suse.de>
 
        PR middle-end/95118
 
      svbool_t and its fixed-length variants.  Using a type variant
      avoids that but means that we treat some ambiguous combinations
      as valid.  */
+  tree new_type;
+  tree base_type = TYPE_MAIN_VARIANT (type);
   if (lang_GNU_C () && VECTOR_BOOLEAN_TYPE_P (type))
-    type = build_variant_type_copy (type);
+    new_type = build_variant_type_copy (base_type);
   else
-    type = build_distinct_type_copy (type);
+    new_type = build_distinct_type_copy (base_type);
+
+  /* Allow the GNU vector extensions to be applied to vectors.
+     The extensions aren't yet defined for packed predicates,
+     so continue to treat them as abstract entities for now.  */
+  if (!VECTOR_BOOLEAN_TYPE_P (new_type))
+    TYPE_INDIVISIBLE_P (new_type) = 0;
 
   /* The new type is a normal sized type; it doesn't have the same
      restrictions as sizeless types.  */
-  TYPE_ATTRIBUTES (type)
+  TYPE_ATTRIBUTES (new_type)
     = remove_attribute ("SVE sizeless type",
-                       copy_list (TYPE_ATTRIBUTES (type)));
+                       copy_list (TYPE_ATTRIBUTES (new_type)));
 
-  /* Allow the GNU vector extensions to be applied to vectors.
-     The extensions aren't yet defined for packed predicates,
-     so continue to treat them as abstract entities for now.  */
-  if (!VECTOR_BOOLEAN_TYPE_P (type))
-    TYPE_INDIVISIBLE_P (type) = 0;
+  /* Apply the relevant attributes, qualifiers and alignment of TYPE,
+     if they differ from the original (sizeless) BASE_TYPE.  */
+  if (TYPE_ATTRIBUTES (base_type) != TYPE_ATTRIBUTES (type)
+      || TYPE_QUALS (base_type) != TYPE_QUALS (type))
+    {
+      tree attrs = remove_attribute ("SVE sizeless type",
+                                    copy_list (TYPE_ATTRIBUTES (type)));
+      new_type = build_type_attribute_qual_variant (new_type, attrs,
+                                                   TYPE_QUALS (type));
+    }
+  if (TYPE_ALIGN (base_type) != TYPE_ALIGN (type))
+    new_type = build_aligned_type (new_type, TYPE_ALIGN (type));
 
-  *node = type;
+  *node = new_type;
   return NULL_TREE;
 }
 
 
+2020-05-14  Richard Sandiford  <richard.sandiford@arm.com>
+
+       PR target/95105
+       * gcc.target/aarch64/sve/acle/general/attributes_8.c: New test.
+       * g++.target/aarch64/sve/acle/general-c++/attributes_1.C: Likewise.
+
 2020-05-14  Richard Biener  <rguenther@suse.de>
 
        PR testsuite/94703
 
--- /dev/null
+/* { dg-options "-msve-vector-bits=256 -W -Wall" } */
+
+#include <arm_sve.h>
+
+#define N __ARM_FEATURE_SVE_BITS
+#define FIXED_ATTR __attribute__ ((arm_sve_vector_bits (N)))
+
+template<typename T> struct foo { T var; };
+
+typedef svint8_t var1;
+typedef __SVInt8_t var2;
+
+typedef const var1 const_var1;
+typedef const var2 const_var2;
+
+typedef svint8_t fixed1 FIXED_ATTR;
+typedef svint8_t fixed1_alias FIXED_ATTR;
+typedef __SVInt8_t fixed2 FIXED_ATTR;
+
+typedef const_var1 const_fixed1 FIXED_ATTR;
+typedef const var1 const_fixed1_alias FIXED_ATTR;
+typedef const_var2 const_fixed2 FIXED_ATTR;
+
+extern fixed1 extern1;
+extern fixed1_alias extern1_alias;
+extern fixed2 extern2;
+
+extern foo<fixed1> extern1_foo;
+extern foo<fixed1_alias> extern1_alias_foo;
+extern foo<fixed2> extern2_foo;
+
+extern const_fixed1 const_extern1;
+extern const_fixed1_alias const_extern1_alias;
+extern const_fixed2 const_extern2;
+
+extern foo<const_fixed1> const_extern1_foo;
+extern foo<const_fixed1_alias> const_extern1_alias_foo;
+extern foo<const_fixed2> const_extern2_foo;
+
+fixed1 &ref1a = extern1;
+fixed1_alias &ref1b = extern1;
+fixed2 &ref1c = extern1;
+
+fixed1 &ref2a = extern1_alias;
+fixed1_alias &ref2b = extern1_alias;
+fixed2 &ref2c = extern1_alias;
+
+fixed1 &ref3a = extern2;
+fixed1_alias &ref3b = extern2;
+fixed2 &ref3c = extern2;
+
+fixed1 &ref1a_foo = extern1_foo.var;
+fixed1_alias &ref1b_foo = extern1_foo.var;
+fixed2 &ref1c_foo = extern1_foo.var;
+
+fixed1 &ref2a_foo = extern1_alias_foo.var;
+fixed1_alias &ref2b_foo = extern1_alias_foo.var;
+fixed2 &ref2c_foo = extern1_alias_foo.var;
+
+fixed1 &ref3a_foo = extern2_foo.var;
+fixed1_alias &ref3b_foo = extern2_foo.var;
+fixed2 &ref3c_foo = extern2_foo.var;
+
+fixed1 &ref4a = const_extern1;              // { dg-error {discards qualifiers} }
+fixed1_alias &ref4b = const_extern1; // { dg-error {discards qualifiers} }
+fixed2 &ref4c = const_extern1;       // { dg-error {discards qualifiers} }
+
+fixed1 &ref4a_foo = const_extern1_foo.var;          // { dg-error {discards qualifiers} }
+fixed1_alias &ref4b_foo = const_extern1_foo.var; // { dg-error {discards qualifiers} }
+fixed2 &ref4c_foo = const_extern1_foo.var;       // { dg-error {discards qualifiers} }
+
+const fixed1 &ref5a = const_extern2;
+const fixed1_alias &ref5b = const_extern2;
+const fixed2 &ref5c = const_extern2;
+
+const_fixed1 &const_ref1a = extern1;
+const_fixed1_alias &const_ref1b = extern1;
+const_fixed2 &const_ref1c = extern1;
+
+const_fixed1 &const_ref2a = extern1_alias;
+const_fixed1_alias &const_ref2b = extern1_alias;
+const_fixed2 &const_ref2c = extern1_alias;
+
+const_fixed1 &const_ref3a = extern2;
+const_fixed1_alias &const_ref3b = extern2;
+const_fixed2 &const_ref3c = extern2;
+
+const_fixed1 &const_ref1a_foo = extern1_foo.var;
+const_fixed1_alias &const_ref1b_foo = extern1_foo.var;
+const_fixed2 &const_ref1c_foo = extern1_foo.var;
+
+const_fixed1 &const_ref2a_foo = extern1_alias_foo.var;
+const_fixed1_alias &const_ref2b_foo = extern1_alias_foo.var;
+const_fixed2 &const_ref2c_foo = extern1_alias_foo.var;
+
+const_fixed1 &const_ref3a_foo = extern2_foo.var;
+const_fixed1_alias &const_ref3b_foo = extern2_foo.var;
+const_fixed2 &const_ref3c_foo = extern2_foo.var;
+
+const_fixed1 &const_ref4a = const_extern1;
+const_fixed1_alias &const_ref4b = const_extern1;
+const_fixed2 &const_ref4c = const_extern1;
+
+const_fixed1 &const_ref5a = const_extern1_alias;
+const_fixed1_alias &const_ref5b = const_extern1_alias;
+const_fixed2 &const_ref5c = const_extern1_alias;
+
+const_fixed1 &const_ref6a = const_extern2;
+const_fixed1_alias &const_ref6b = const_extern2;
+const_fixed2 &const_ref6c = const_extern2;
+
+const_fixed1 &const_ref4a_foo = const_extern1_foo.var;
+const_fixed1_alias &const_ref4b_foo = const_extern1_foo.var;
+const_fixed2 &const_ref4c_foo = const_extern1_foo.var;
+
+const_fixed1 &const_ref5a_foo = const_extern1_alias_foo.var;
+const_fixed1_alias &const_ref5b_foo = const_extern1_alias_foo.var;
+const_fixed2 &const_ref5c_foo = const_extern1_alias_foo.var;
+
+const_fixed1 &const_ref6a_foo = const_extern2_foo.var;
+const_fixed1_alias &const_ref6b_foo = const_extern2_foo.var;
+const_fixed2 &const_ref6c_foo = const_extern2_foo.var;
 
--- /dev/null
+/* { dg-options "-msve-vector-bits=256 -W -Wall" } */
+
+#include <arm_sve.h>
+
+#define N __ARM_FEATURE_SVE_BITS
+#define FIXED_ATTR __attribute__ ((arm_sve_vector_bits (N)))
+#define ALIGNED_ATTR __attribute__((aligned(N / 8)))
+
+typedef svint8_t var1;
+typedef __SVInt8_t var2;
+
+typedef const var1 const_var1;
+typedef const var2 const_var2;
+
+typedef var1 aligned_var1 ALIGNED_ATTR;
+typedef var2 aligned_var2 ALIGNED_ATTR;
+
+typedef var1 fixed1 FIXED_ATTR;
+typedef var1 fixed1_alias FIXED_ATTR;
+typedef var2 fixed2 FIXED_ATTR;
+
+typedef const_var1 const_fixed1 FIXED_ATTR;
+typedef const var1 const_fixed1_alias FIXED_ATTR;
+typedef const_var2 const_fixed2 FIXED_ATTR;
+
+typedef aligned_var1 aligned_fixed1 FIXED_ATTR;
+typedef var1 aligned_fixed1_alias FIXED_ATTR ALIGNED_ATTR;
+typedef aligned_var2 aligned_fixed2 FIXED_ATTR;
+
+extern fixed1 extern1;
+extern fixed1_alias extern1_alias;
+extern fixed2 extern2;
+
+extern const_fixed1 const_extern1;
+extern const_fixed1_alias const_extern1_alias;
+extern const_fixed2 const_extern2;
+
+fixed1 *ptr1a = &extern1;
+fixed1_alias *ptr1b = &extern1;
+fixed2 *ptr1c = &extern1;
+
+fixed1 *ptr2a = &extern1_alias;
+fixed1_alias *ptr2b = &extern1_alias;
+fixed2 *ptr2c = &extern1_alias;
+
+fixed1 *ptr3a = &extern2;
+fixed1_alias *ptr3b = &extern2;
+fixed2 *ptr3c = &extern2;
+
+fixed1 *ptr4a = &const_extern1;        // { dg-error {invalid conversion} "c++" { target c++ } }
+                                       // { dg-warning {discards 'const' qualifier} "c" { target c } .-1 }
+fixed1_alias *ptr4b = &const_extern1;  // { dg-error {invalid conversion} "c++" { target c++ } }
+                                       // { dg-warning {discards 'const' qualifier} "c" { target c } .-1 }
+fixed2 *ptr4c = &const_extern1;        // { dg-error {invalid conversion} "c++" { target c++ } }
+                                       // { dg-warning {discards 'const' qualifier} "c" { target c } .-1 }
+
+const fixed1 *ptr5a = &const_extern2;
+const fixed1_alias *ptr5b = &const_extern2;
+const fixed2 *ptr5c = &const_extern2;
+
+const_fixed1 *const_ptr1a = &extern1;
+const_fixed1_alias *const_ptr1b = &extern1;
+const_fixed2 *const_ptr1c = &extern1;
+
+const_fixed1 *const_ptr2a = &extern1_alias;
+const_fixed1_alias *const_ptr2b = &extern1_alias;
+const_fixed2 *const_ptr2c = &extern1_alias;
+
+const_fixed1 *const_ptr3a = &extern2;
+const_fixed1_alias *const_ptr3b = &extern2;
+const_fixed2 *const_ptr3c = &extern2;
+
+const_fixed1 *const_ptr4a = &const_extern1;
+const_fixed1_alias *const_ptr4b = &const_extern1;
+const_fixed2 *const_ptr4c = &const_extern1;
+
+const_fixed1 *const_ptr5a = &const_extern1_alias;
+const_fixed1_alias *const_ptr5b = &const_extern1_alias;
+const_fixed2 *const_ptr5c = &const_extern1_alias;
+
+const_fixed1 *const_ptr6a = &const_extern2;
+const_fixed1_alias *const_ptr6b = &const_extern2;
+const_fixed2 *const_ptr6c = &const_extern2;
+
+struct normal1 { int x; fixed1 y; };
+struct normal1_alias { int x; fixed1_alias y; };
+struct normal2 { int x; fixed2 y; };
+
+struct aligned1 { int x; aligned_fixed1 y; };
+struct aligned1_alias { int x; aligned_fixed1_alias y; };
+struct aligned2 { int x; aligned_fixed2 y; };
+
+#define ASSERT(NAME, TEST) typedef int NAME[(TEST) ? 1 : -1]
+
+ASSERT (check_normal1, sizeof (struct normal1) == N / 8 + 16);
+ASSERT (check_normal1_alias, sizeof (struct normal1_alias) == N / 8 + 16);
+ASSERT (check_normal2, sizeof (struct normal2) == N / 8 + 16);
+
+ASSERT (check_aligned1, sizeof (struct aligned1) == N / 4);
+ASSERT (check_aligned1_alias, sizeof (struct aligned1_alias) == N / 4);
+ASSERT (check_aligned2, sizeof (struct aligned2) == N / 4);