Compiling this testcase with -march=armv8.2-a+sve
-msve-vector-bits=512:

----------------------------------------------------------
typedef __SVFloat32_t foo;
typedef foo bar __attribute__((arm_sve_vector_bits(512)));
template<typename T> struct s { T x; };
extern s<bar> a;
bar &b = a.x;
----------------------------------------------------------

gave the bogus error:

  cannot bind non-const lvalue reference of type ‘bar&’ to an rvalue
  of type ‘bar’

The testcase works if the attribute is applied directly
to __SVFloat32_t instead of via foo.

This shows a more general problem with the way that we were handling
the arm_sve_vector_bits attribute: we started by building a distinct
copy of the type to which the attribute was applied, instead of starting
with its main variant.  This new type then became its own main variant,
meaning that the relationship between types that have the attribute
could be different from the relationship between types that don't have
the attribute.

This patch instead copies the main variant of the original type and then
reapplies all the differences.

Tested on aarch64-linux-gnu and pushed to master.  Will backport
to gcc-10 soon.

Richard


2020-05-14  Richard Sandiford  <richard.sandif...@arm.com>

gcc/
        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.

gcc/testsuite/
        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.
---
 gcc/config/aarch64/aarch64-sve-builtins.cc    |  35 +++--
 .../sve/acle/general-c++/attributes_1.C       | 122 ++++++++++++++++++
 .../aarch64/sve/acle/general/attributes_8.c   | 101 +++++++++++++++
 3 files changed, 248 insertions(+), 10 deletions(-)
 create mode 100644 
gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/attributes_1.C
 create mode 100644 
gcc/testsuite/gcc.target/aarch64/sve/acle/general/attributes_8.c

diff --git a/gcc/config/aarch64/aarch64-sve-builtins.cc 
b/gcc/config/aarch64/aarch64-sve-builtins.cc
index 8511382351c..bdb04e8170d 100644
--- a/gcc/config/aarch64/aarch64-sve-builtins.cc
+++ b/gcc/config/aarch64/aarch64-sve-builtins.cc
@@ -3676,24 +3676,39 @@ handle_arm_sve_vector_bits_attribute (tree *node, tree, 
tree args, int,
      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;
 }
 
diff --git 
a/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/attributes_1.C 
b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/attributes_1.C
new file mode 100644
index 00000000000..befd494cd13
--- /dev/null
+++ b/gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/attributes_1.C
@@ -0,0 +1,122 @@
+/* { 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;
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/attributes_8.c 
b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/attributes_8.c
new file mode 100644
index 00000000000..f302927c55b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/attributes_8.c
@@ -0,0 +1,101 @@
+/* { 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);

Reply via email to