diff mbox series

[C++] Make same_type_p return false for gnu_vector_type_p differences (PR 92789)

Message ID mptd0cty3ov.fsf@arm.com
State New
Headers show
Series [C++] Make same_type_p return false for gnu_vector_type_p differences (PR 92789) | expand

Commit Message

Richard Sandiford Dec. 12, 2019, 3:16 p.m. UTC
As Jason pointed out in the review of the C++ gnu_vector_type_p patch:

    https://gcc.gnu.org/ml/gcc-patches/2019-12/msg00173.html

the real fix for the XFAILs in acle/general-c++/gnu_vectors_*.C is to
make same_type_p return false for two types if one is gnu_vector_type_p
and the other isn't.  This patch does that and fixes the fallout in the
way Jason suggested above.

I'd said at the time that some of the tests require:

      /* If the constructor already has the array type, it's been through
	 digest_init, so we shouldn't try to do anything more.  */
      bool digested = same_type_p (atype, TREE_TYPE (init));

(build_vec_init) to be true for gnu vectors built from non-gnu vectors.
I can no longer reproduce that, maybe because my original same_type_p
change was bogus or because something in the later sizeless type
support made it moot (or something else :-)).

This means that sve-sizeless-2.C (the length-specific test) now reports
some errors for comparisons and pointer differences that sve-sizeless-1.C
(the length-agnostic test) already had.  I think requiring a cast is OK
for those cases, since there's no reason to mix GNU and non-GNU versions
of the same vector in the same object.  Even -flax-vector-conversions
would require a cast for different vector types here, for both C and C++.

same_type_p had:

  else if (strict == COMPARE_STRUCTURAL)
    return structural_comptypes (t1, t2, COMPARE_STRICT);
  else
    return structural_comptypes (t1, t2, strict);

Since structural_comptypes ignored the COMPARE_STRUCTURAL bit of "strict"
before the patch, the "else if" was harmless but AFAICT unnecessary.

Tested on aarch64-linux-gnu and x86_64-linux-gnu.  OK to install?

Richard


2019-12-12  Richard Sandiford  <richard.sandiford@arm.com>

gcc/c-family/
	PR c++/92789
	* c-common.c (vector_targets_convertible_p): Handle types that
	differ in gnu_vector_type_p but are otherwise identical.

gcc/cp/
	PR c++/92789
	* typeck.c (structural_comptypes): For strict checking, make sure
	that two vector types agree on gnu_vector_type_p.
	(comptypes): Pass the original strictness argument to
	structural_comptypes.
	(similar_type_p): Use a structural comparision for vectors.

gcc/testsuite/
	PR c++/92789
	* g++.dg/ext/sve-sizeless-2.C (statements): Expect pointer
	difference and comparisons between GNU and non-GNU types
	to be rejected.  Expect __is_same to be false for such pairs.
	* g++.target/aarch64/sve/acle/general-c++/gnu_vectors_1.C: Remove
	XFAILs.
	* g++.target/aarch64/sve/acle/general-c++/gnu_vectors_2.C: Likewise.

Comments

Jason Merrill Dec. 16, 2019, 11:08 p.m. UTC | #1
On 12/12/19 10:16 AM, Richard Sandiford wrote:
> As Jason pointed out in the review of the C++ gnu_vector_type_p patch:
> 
>      https://gcc.gnu.org/ml/gcc-patches/2019-12/msg00173.html
> 
> the real fix for the XFAILs in acle/general-c++/gnu_vectors_*.C is to
> make same_type_p return false for two types if one is gnu_vector_type_p
> and the other isn't.  This patch does that and fixes the fallout in the
> way Jason suggested above.
> 
> I'd said at the time that some of the tests require:
> 
>        /* If the constructor already has the array type, it's been through
> 	 digest_init, so we shouldn't try to do anything more.  */
>        bool digested = same_type_p (atype, TREE_TYPE (init));
> 
> (build_vec_init) to be true for gnu vectors built from non-gnu vectors.
> I can no longer reproduce that, maybe because my original same_type_p
> change was bogus or because something in the later sizeless type
> support made it moot (or something else :-)).
> 
> This means that sve-sizeless-2.C (the length-specific test) now reports
> some errors for comparisons and pointer differences that sve-sizeless-1.C
> (the length-agnostic test) already had.  I think requiring a cast is OK
> for those cases, since there's no reason to mix GNU and non-GNU versions
> of the same vector in the same object.  Even -flax-vector-conversions
> would require a cast for different vector types here, for both C and C++.
> 
> same_type_p had:
> 
>    else if (strict == COMPARE_STRUCTURAL)
>      return structural_comptypes (t1, t2, COMPARE_STRICT);
>    else
>      return structural_comptypes (t1, t2, strict);
> 
> Since structural_comptypes ignored the COMPARE_STRUCTURAL bit of "strict"
> before the patch, the "else if" was harmless but AFAICT unnecessary.

The comment in cp-tree.h has

> #define COMPARE_STRUCTURAL    8 /* The comparison is intended to be                                            
>                                    structural. The actual comparison                                           
>                                    will be identical to                                                        
>                                    COMPARE_STRICT.  */

So introducing differences between COMPARE_STRUCTURAL and COMPARE_STRICT 
other than that the first always calls structural_comptypes and the 
second sometimes compares TYPE_CANONICAL instead is to be avoided.

Do you want to use vector_types_convertible_p in similar_type_p?

Jason
Richard Sandiford Dec. 19, 2019, 4:52 p.m. UTC | #2
Jason Merrill <jason@redhat.com> writes:
> On 12/12/19 10:16 AM, Richard Sandiford wrote:
>> As Jason pointed out in the review of the C++ gnu_vector_type_p patch:
>> 
>>      https://gcc.gnu.org/ml/gcc-patches/2019-12/msg00173.html
>> 
>> the real fix for the XFAILs in acle/general-c++/gnu_vectors_*.C is to
>> make same_type_p return false for two types if one is gnu_vector_type_p
>> and the other isn't.  This patch does that and fixes the fallout in the
>> way Jason suggested above.
>> 
>> I'd said at the time that some of the tests require:
>> 
>>        /* If the constructor already has the array type, it's been through
>> 	 digest_init, so we shouldn't try to do anything more.  */
>>        bool digested = same_type_p (atype, TREE_TYPE (init));
>> 
>> (build_vec_init) to be true for gnu vectors built from non-gnu vectors.
>> I can no longer reproduce that, maybe because my original same_type_p
>> change was bogus or because something in the later sizeless type
>> support made it moot (or something else :-)).
>> 
>> This means that sve-sizeless-2.C (the length-specific test) now reports
>> some errors for comparisons and pointer differences that sve-sizeless-1.C
>> (the length-agnostic test) already had.  I think requiring a cast is OK
>> for those cases, since there's no reason to mix GNU and non-GNU versions
>> of the same vector in the same object.  Even -flax-vector-conversions
>> would require a cast for different vector types here, for both C and C++.
>> 
>> same_type_p had:
>> 
>>    else if (strict == COMPARE_STRUCTURAL)
>>      return structural_comptypes (t1, t2, COMPARE_STRICT);
>>    else
>>      return structural_comptypes (t1, t2, strict);
>> 
>> Since structural_comptypes ignored the COMPARE_STRUCTURAL bit of "strict"
>> before the patch, the "else if" was harmless but AFAICT unnecessary.
>
> The comment in cp-tree.h has
>
>> #define COMPARE_STRUCTURAL    8 /* The comparison is intended to be                                            
>>                                    structural. The actual comparison                                           
>>                                    will be identical to                                                        
>>                                    COMPARE_STRICT.  */
>
> So introducing differences between COMPARE_STRUCTURAL and COMPARE_STRICT 
> other than that the first always calls structural_comptypes and the 
> second sometimes compares TYPE_CANONICAL instead is to be avoided.

OK.

> Do you want to use vector_types_convertible_p in similar_type_p?

The problem then is that we'll apply -flax-vector-conversion rules too,
which seems to be going too far beyond what [conv.qual] says.

But that's probably a sign that I was wanting the wrong behaviour here.
The main point is to ensure that similar GNU and non-GNU vectors remain
interconveritble without -flax-vector-conversions, and without any
warnings.  There's no specific requirement to extend that to pointers,
it just seemed like the natural thing to do at the time.

So on reflection, I guess we should just accept the consequences of
making the types !same_type_p.

Tested on aarch64-linux-gnu and x86_64-linux-gnu.  OK to install?
If so, I'll follow up with a corresponding patch for C.

Thanks,
Richard


2019-12-19  Richard Sandiford  <richard.sandiford@arm.com>

gcc/cp/
	PR c++/92789
	* typeck.c (structural_comptypes): Make sure that two vector types
	agree on gnu_vector_type_p.

gcc/testsuite/
	PR c++/92789
	* g++.dg/ext/sve-sizeless-2.C (statements): Expect pointer
	difference and comparisons between GNU and non-GNU types
	to be rejected.  Expect __is_same to be false for such pairs.
	* g++.target/aarch64/sve/acle/general-c++/gnu_vectors_1.C: Remove
	XFAILs.  Expect conversions between SVE vector pointers and
	GNU vector pointers to be rejected.  Test references.
	* g++.target/aarch64/sve/acle/general-c++/gnu_vectors_2.C: Likewise.

Index: gcc/cp/typeck.c
===================================================================
--- gcc/cp/typeck.c	2019-12-19 16:28:40.344411888 +0000
+++ gcc/cp/typeck.c	2019-12-19 16:43:03.490702766 +0000
@@ -1425,7 +1425,8 @@ structural_comptypes (tree t1, tree t2,
       break;
 
     case VECTOR_TYPE:
-      if (maybe_ne (TYPE_VECTOR_SUBPARTS (t1), TYPE_VECTOR_SUBPARTS (t2))
+      if (gnu_vector_type_p (t1) != gnu_vector_type_p (t2)
+	  || maybe_ne (TYPE_VECTOR_SUBPARTS (t1), TYPE_VECTOR_SUBPARTS (t2))
 	  || !same_type_p (TREE_TYPE (t1), TREE_TYPE (t2)))
 	return false;
       break;
Index: gcc/testsuite/g++.dg/ext/sve-sizeless-2.C
===================================================================
--- gcc/testsuite/g++.dg/ext/sve-sizeless-2.C	2019-12-13 10:21:18.000000000 +0000
+++ gcc/testsuite/g++.dg/ext/sve-sizeless-2.C	2019-12-19 16:43:03.490702766 +0000
@@ -183,8 +183,8 @@ statements (int n)
 
   // Pointer assignment.
 
-  gnu_sc_ptr = sve_sc_ptr;
-  sve_sc_ptr = gnu_sc_ptr;
+  gnu_sc_ptr = sve_sc_ptr; // { dg-error {invalid conversion from 'svint8_t\*' to 'int8x32_t\*'} }
+  sve_sc_ptr = gnu_sc_ptr; // { dg-error {invalid conversion from 'int8x32_t\*'[^\n]* to 'svint8_t\*'} }
 
   // Pointer arithmetic.
 
@@ -197,8 +197,8 @@ statements (int n)
   sve_sc_ptr -= 0; // { dg-error {arithmetic on pointer to SVE type 'svint8_t'} }
   sve_sc_ptr -= 1; // { dg-error {arithmetic on pointer to SVE type 'svint8_t'} }
   sve_sc_ptr - sve_sc_ptr; // { dg-error {arithmetic on pointer to SVE type 'svint8_t'} }
-  gnu_sc_ptr - sve_sc_ptr; // { dg-error {arithmetic on pointer to SVE type 'svint8_t'} }
-  sve_sc_ptr - gnu_sc_ptr; // { dg-error {arithmetic on pointer to SVE type 'svint8_t'} }
+  gnu_sc_ptr - sve_sc_ptr; // { dg-error {invalid operands of types 'int8x32_t\*'[^\n]* and 'svint8_t\*' to binary 'operator-'} }
+  sve_sc_ptr - gnu_sc_ptr; // { dg-error {invalid operands of types 'svint8_t\*' and 'int8x32_t\*'[^\n]* to binary 'operator-'} }
   sve_sc1 = sve_sc_ptr[0]; // { dg-error {arithmetic on pointer to SVE type 'svint8_t'} }
   sve_sc1 = sve_sc_ptr[1]; // { dg-error {arithmetic on pointer to SVE type 'svint8_t'} }
 
@@ -210,18 +210,18 @@ statements (int n)
   sve_sc_ptr <= &sve_sc1;
   sve_sc_ptr > &sve_sc1;
   sve_sc_ptr >= &sve_sc1;
-  gnu_sc_ptr == sve_sc_ptr;
-  gnu_sc_ptr != sve_sc_ptr;
-  gnu_sc_ptr < sve_sc_ptr;
-  gnu_sc_ptr <= sve_sc_ptr;
-  gnu_sc_ptr > sve_sc_ptr;
-  gnu_sc_ptr >= sve_sc_ptr;
-  sve_sc_ptr == gnu_sc_ptr;
-  sve_sc_ptr != gnu_sc_ptr;
-  sve_sc_ptr < gnu_sc_ptr;
-  sve_sc_ptr <= gnu_sc_ptr;
-  sve_sc_ptr > gnu_sc_ptr;
-  sve_sc_ptr >= gnu_sc_ptr;
+  gnu_sc_ptr == sve_sc_ptr; // { dg-error {comparison between distinct pointer types [^\n]*lacks a cast} }
+  gnu_sc_ptr != sve_sc_ptr; // { dg-error {comparison between distinct pointer types [^\n]*lacks a cast} }
+  gnu_sc_ptr < sve_sc_ptr; // { dg-error {comparison between distinct pointer types [^\n]*lacks a cast} }
+  gnu_sc_ptr <= sve_sc_ptr; // { dg-error {comparison between distinct pointer types [^\n]*lacks a cast} }
+  gnu_sc_ptr > sve_sc_ptr; // { dg-error {comparison between distinct pointer types [^\n]*lacks a cast} }
+  gnu_sc_ptr >= sve_sc_ptr; // { dg-error {comparison between distinct pointer types [^\n]*lacks a cast} }
+  sve_sc_ptr == gnu_sc_ptr; // { dg-error {comparison between distinct pointer types [^\n]*lacks a cast} }
+  sve_sc_ptr != gnu_sc_ptr; // { dg-error {comparison between distinct pointer types [^\n]*lacks a cast} }
+  sve_sc_ptr < gnu_sc_ptr; // { dg-error {comparison between distinct pointer types [^\n]*lacks a cast} }
+  sve_sc_ptr <= gnu_sc_ptr; // { dg-error {comparison between distinct pointer types [^\n]*lacks a cast} }
+  sve_sc_ptr > gnu_sc_ptr; // { dg-error {comparison between distinct pointer types [^\n]*lacks a cast} }
+  sve_sc_ptr >= gnu_sc_ptr; // { dg-error {comparison between distinct pointer types [^\n]*lacks a cast} }
 
   // New and delete.
 
@@ -243,8 +243,8 @@ statements (int n)
   0 ? 0 : sve_sc1; // { dg-error {different types 'int' and 'svint8_t'} }
   0 ? sve_sc1 : sve_sc1;
   0 ? sve_sc_ptr : sve_sc_ptr;
-  0 ? sve_sc_ptr : gnu_sc_ptr;
-  0 ? gnu_sc_ptr : sve_sc_ptr;
+  0 ? sve_sc_ptr : gnu_sc_ptr; // { dg-error {conditional expression between distinct pointer types [^\n]*lacks a cast} }
+  0 ? gnu_sc_ptr : sve_sc_ptr; // { dg-error {conditional expression between distinct pointer types [^\n]*lacks a cast} }
 
   // Function arguments.
 
@@ -321,11 +321,11 @@ statements (int n)
   { typedef int f[__is_pod (svint8_t) ? 1 : -1]; }
   { typedef int f[!__is_polymorphic (svint8_t) ? 1 : -1]; }
   { typedef int f[__is_same_as (svint8_t, svint8_t) ? 1 : -1]; }
-  { typedef int f[__is_same_as (svint8_t, int8x32_t) ? 1 : -1]; }
-  { typedef int f[__is_same_as (int8x32_t, svint8_t) ? 1 : -1]; }
+  { typedef int f[!__is_same_as (svint8_t, int8x32_t) ? 1 : -1]; }
+  { typedef int f[!__is_same_as (int8x32_t, svint8_t) ? 1 : -1]; }
   { typedef int f[__is_same_as (svint8_t *, svint8_t *) ? 1 : -1]; }
-  { typedef int f[__is_same_as (svint8_t *, int8x32_t *) ? 1 : -1]; }
-  { typedef int f[__is_same_as (int8x32_t *, svint8_t *) ? 1 : -1]; }
+  { typedef int f[!__is_same_as (svint8_t *, int8x32_t *) ? 1 : -1]; }
+  { typedef int f[!__is_same_as (int8x32_t *, svint8_t *) ? 1 : -1]; }
   { typedef int f[!__is_same_as (svint8_t, int) ? 1 : -1]; }
   { typedef int f[!__is_same_as (svint8_t, svint16_t) ? 1 : -1]; }
   { typedef int f[__is_trivial (svint8_t) ? 1 : -1]; }
Index: gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/gnu_vectors_1.C
===================================================================
--- gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/gnu_vectors_1.C	2019-12-13 10:21:18.000000000 +0000
+++ gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/gnu_vectors_1.C	2019-12-19 16:43:03.490702766 +0000
@@ -36,14 +36,14 @@ f (svuint8_t sve_u1, svint8_t sve_s1,
 
   gnu_uint8_t init_gnu_u1 = 0; // { dg-error {cannot convert 'int' to 'gnu_uint8_t'[^\n]* in initialization} }
   gnu_uint8_t init_gnu_u2 = {};
-  gnu_uint8_t init_gnu_u3 = { sve_u1 };
+  gnu_uint8_t init_gnu_u3 = { sve_u1 }; // { dg-error {cannot convert 'svuint8_t' to 'unsigned char' in initialization} }
   gnu_uint8_t init_gnu_u4 = { gnu_u1 };
   gnu_uint8_t init_gnu_u5 = { sve_s1 }; // { dg-error {cannot convert 'svint8_t' to 'unsigned char' in initialization} }
   gnu_uint8_t init_gnu_u6 = { gnu_s1 }; // { dg-error {cannot convert 'gnu_int8_t'[^\n]* to 'unsigned char' in initialization} }
   gnu_uint8_t init_gnu_u7 = { 0 };
   gnu_uint8_t init_gnu_u8 = { sve_u1, sve_u1 }; // { dg-error {cannot convert 'svuint8_t' to 'unsigned char' in initialization} }
   gnu_uint8_t init_gnu_u9 = { gnu_u1, gnu_u1 }; // { dg-error {cannot convert 'gnu_uint8_t'[^\n]* to 'unsigned char' in initialization} }
-  gnu_uint8_t init_gnu_u10 { sve_u1 };
+  gnu_uint8_t init_gnu_u10 { sve_u1 }; // { dg-error {cannot convert 'svuint8_t' to 'unsigned char' in initialization} }
   gnu_uint8_t init_gnu_u11 { gnu_u1 };
   gnu_uint8_t init_gnu_u12 { sve_s1 }; // { dg-error {cannot convert 'svint8_t' to 'unsigned char' in initialization} }
   gnu_uint8_t init_gnu_u13 { gnu_s1 }; // { dg-error {cannot convert 'gnu_int8_t'[^\n]* to 'unsigned char' in initialization} }
@@ -69,7 +69,7 @@ f (svuint8_t sve_u1, svint8_t sve_s1,
 
   (gnu_uint8_t) {};
   (gnu_uint8_t) { 0 };
-  (gnu_uint8_t) { sve_u1 };
+  (gnu_uint8_t) { sve_u1 }; // { dg-error {cannot convert 'svuint8_t' to 'unsigned char' in initialization} }
   (gnu_uint8_t) { gnu_u1 };
   (gnu_uint8_t) { sve_s1 }; // { dg-error {cannot convert 'svint8_t' to 'unsigned char' in initialization} }
   (gnu_uint8_t) { gnu_s1 }; // { dg-error {cannot convert 'gnu_int8_t'[^\n]* to 'unsigned char' in initialization} }
@@ -434,8 +434,8 @@ f (svuint8_t sve_u1, svint8_t sve_s1,
   // Conditional expressions.
 
   uc ? sve_u1 : sve_u1;
-  uc ? gnu_u1 : sve_u1; // { dg-error {operands to '\?:' have different types 'gnu_uint8_t'[^\n]* and 'svuint8_t'} "" { xfail *-*-* } }
-  uc ? sve_u1 : gnu_u1; // { dg-error {operands to '\?:' have different types 'svuint8_t' and 'gnu_uint8_t'} "" { xfail *-*-* } }
+  uc ? gnu_u1 : sve_u1; // { dg-error {operands to '\?:' have different types 'gnu_uint8_t'[^\n]* and 'svuint8_t'} }
+  uc ? sve_u1 : gnu_u1; // { dg-error {operands to '\?:' have different types 'svuint8_t' and 'gnu_uint8_t'} }
   uc ? gnu_u1 : gnu_u1;
 
   sve_u1 ? sve_u1 : sve_u1; // { dg-error {could not convert 'sve_u1' from 'svuint8_t' to 'bool'} }
@@ -474,15 +474,29 @@ f (svuint8_t sve_u1, svint8_t sve_s1,
   static_assert(__is_literal_type(svuint8_t));
   static_assert(__is_literal_type(gnu_uint8_t));
 
+  // Pointers.
+
   svuint8_t *sve_ptr1 = &sve_u1;
-  svuint8_t *sve_ptr2 = &gnu_u1;
+  svuint8_t *sve_ptr2 = &gnu_u1; // { dg-error {invalid conversion} }
   svuint8_t *sve_ptr3 = &sve_s1; // { dg-error {cannot convert 'svint8_t\*' to 'svuint8_t\*' in initialization} }
   svuint8_t *sve_ptr4 = &gnu_s1; // { dg-error {cannot convert 'gnu_int8_t\*'[^\n]* to 'svuint8_t\*' in initialization} }
 
-  gnu_uint8_t *gnu_ptr1 = &sve_u1;
+  gnu_uint8_t *gnu_ptr1 = &sve_u1; // { dg-error {invalid conversion} }
   gnu_uint8_t *gnu_ptr2 = &gnu_u1;
   gnu_uint8_t *gnu_ptr3 = &sve_s1; // { dg-error {cannot convert 'svint8_t\*' to 'gnu_uint8_t\*'} }
   gnu_uint8_t *gnu_ptr4 = &gnu_s1; // { dg-error {cannot convert 'gnu_int8_t\*'[^\n]* to 'gnu_uint8_t\*'} }
+
+  // References.
+
+  svuint8_t &sve_ref1 = sve_u1;
+  svuint8_t &sve_ref2 = gnu_u1; // { dg-error {cannot bind non-const lvalue reference} }
+  svuint8_t &sve_ref3 = sve_s1; // { dg-error {invalid initialization of reference of type 'svuint8_t\&' from expression of type 'svint8_t'} }
+  svuint8_t &sve_ref4 = gnu_s1; // { dg-error {invalid initialization of reference of type 'svuint8_t\&' from expression of type 'gnu_int8_t'} }
+
+  gnu_uint8_t &gnu_ref1 = sve_u1; // { dg-error {cannot bind non-const lvalue reference} }
+  gnu_uint8_t &gnu_ref2 = gnu_u1;
+  gnu_uint8_t &gnu_ref3 = sve_s1; // { dg-error {invalid initialization of reference of type 'gnu_uint8_t\&} }
+  gnu_uint8_t &gnu_ref4 = gnu_s1; // { dg-error {invalid initialization of reference of type 'gnu_uint8_t\&} }
 }
 
 constexpr svuint8_t const1 (svuint8_t x) { return x; }
Index: gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/gnu_vectors_2.C
===================================================================
--- gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/gnu_vectors_2.C	2019-12-13 10:21:18.000000000 +0000
+++ gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/gnu_vectors_2.C	2019-12-19 16:43:03.490702766 +0000
@@ -36,14 +36,14 @@ f (svuint8_t sve_u1, svint8_t sve_s1,
 
   gnu_uint8_t init_gnu_u1 = 0; // { dg-error {cannot convert 'int' to 'gnu_uint8_t'[^\n]* in initialization} }
   gnu_uint8_t init_gnu_u2 = {};
-  gnu_uint8_t init_gnu_u3 = { sve_u1 };
+  gnu_uint8_t init_gnu_u3 = { sve_u1 }; // { dg-error {cannot convert 'svuint8_t' to 'unsigned char' in initialization} }
   gnu_uint8_t init_gnu_u4 = { gnu_u1 };
   gnu_uint8_t init_gnu_u5 = { sve_s1 }; // { dg-error {cannot convert 'svint8_t' to 'unsigned char' in initialization} }
   gnu_uint8_t init_gnu_u6 = { gnu_s1 }; // { dg-error {cannot convert 'gnu_int8_t'[^\n]* to 'unsigned char' in initialization} }
   gnu_uint8_t init_gnu_u7 = { 0 };
   gnu_uint8_t init_gnu_u8 = { sve_u1, sve_u1 }; // { dg-error {cannot convert 'svuint8_t' to 'unsigned char' in initialization} }
   gnu_uint8_t init_gnu_u9 = { gnu_u1, gnu_u1 }; // { dg-error {cannot convert 'gnu_uint8_t'[^\n]* to 'unsigned char' in initialization} }
-  gnu_uint8_t init_gnu_u10 { sve_u1 };
+  gnu_uint8_t init_gnu_u10 { sve_u1 }; // { dg-error {cannot convert 'svuint8_t' to 'unsigned char' in initialization} }
   gnu_uint8_t init_gnu_u11 { gnu_u1 };
   gnu_uint8_t init_gnu_u12 { sve_s1 }; // { dg-error {cannot convert 'svint8_t' to 'unsigned char' in initialization} }
   gnu_uint8_t init_gnu_u13 { gnu_s1 }; // { dg-error {cannot convert 'gnu_int8_t'[^\n]* to 'unsigned char' in initialization} }
@@ -69,7 +69,7 @@ f (svuint8_t sve_u1, svint8_t sve_s1,
 
   (gnu_uint8_t) {};
   (gnu_uint8_t) { 0 };
-  (gnu_uint8_t) { sve_u1 };
+  (gnu_uint8_t) { sve_u1 }; // { dg-error {cannot convert 'svuint8_t' to 'unsigned char' in initialization} }
   (gnu_uint8_t) { gnu_u1 };
   (gnu_uint8_t) { sve_s1 }; // { dg-error {cannot convert 'svint8_t' to 'unsigned char' in initialization} }
   (gnu_uint8_t) { gnu_s1 }; // { dg-error {cannot convert 'gnu_int8_t'[^\n]* to 'unsigned char' in initialization} }
@@ -434,8 +434,8 @@ f (svuint8_t sve_u1, svint8_t sve_s1,
   // Conditional expressions.
 
   uc ? sve_u1 : sve_u1;
-  uc ? gnu_u1 : sve_u1; // { dg-error {operands to '\?:' have different types 'gnu_uint8_t'[^\n]* and 'svuint8_t'} "" { xfail *-*-* } }
-  uc ? sve_u1 : gnu_u1; // { dg-error {operands to '\?:' have different types 'svuint8_t' and 'gnu_uint8_t'} "" { xfail *-*-* } }
+  uc ? gnu_u1 : sve_u1; // { dg-error {operands to '\?:' have different types 'gnu_uint8_t'[^\n]* and 'svuint8_t'} }
+  uc ? sve_u1 : gnu_u1; // { dg-error {operands to '\?:' have different types 'svuint8_t' and 'gnu_uint8_t'} }
   uc ? gnu_u1 : gnu_u1;
 
   sve_u1 ? sve_u1 : sve_u1; // { dg-error {could not convert 'sve_u1' from 'svuint8_t' to 'bool'} }
@@ -474,15 +474,29 @@ f (svuint8_t sve_u1, svint8_t sve_s1,
   static_assert(__is_literal_type(svuint8_t));
   static_assert(__is_literal_type(gnu_uint8_t));
 
+  // Pointers.
+
   svuint8_t *sve_ptr1 = &sve_u1;
-  svuint8_t *sve_ptr2 = &gnu_u1;
+  svuint8_t *sve_ptr2 = &gnu_u1; // { dg-error {invalid conversion} }
   svuint8_t *sve_ptr3 = &sve_s1; // { dg-error {invalid conversion from 'svint8_t\*' to 'svuint8_t\*'} }
   svuint8_t *sve_ptr4 = &gnu_s1; // { dg-error {invalid conversion from 'gnu_int8_t\*'[^\n]* to 'svuint8_t\*'} }
 
-  gnu_uint8_t *gnu_ptr1 = &sve_u1;
+  gnu_uint8_t *gnu_ptr1 = &sve_u1; // { dg-error {invalid conversion} }
   gnu_uint8_t *gnu_ptr2 = &gnu_u1;
   gnu_uint8_t *gnu_ptr3 = &sve_s1; // { dg-error {invalid conversion from 'svint8_t\*' to 'gnu_uint8_t\*'} }
   gnu_uint8_t *gnu_ptr4 = &gnu_s1; // { dg-error {invalid conversion from 'gnu_int8_t\*'[^\n]* to 'gnu_uint8_t\*'} }
+
+  // References.
+
+  svuint8_t &sve_ref1 = sve_u1;
+  svuint8_t &sve_ref2 = gnu_u1; // { dg-error {cannot bind non-const lvalue reference} }
+  svuint8_t &sve_ref3 = sve_s1; // { dg-error {cannot bind non-const lvalue reference} }
+  svuint8_t &sve_ref4 = gnu_s1; // { dg-error {cannot bind non-const lvalue reference} }
+
+  gnu_uint8_t &gnu_ref1 = sve_u1; // { dg-error {cannot bind non-const lvalue reference} }
+  gnu_uint8_t &gnu_ref2 = gnu_u1;
+  gnu_uint8_t &gnu_ref3 = sve_s1; // { dg-error {cannot bind non-const lvalue reference} }
+  gnu_uint8_t &gnu_ref4 = gnu_s1; // { dg-error {cannot bind non-const lvalue reference} }
 }
 
 constexpr svuint8_t const1 (svuint8_t x) { return x; }
Jason Merrill Dec. 19, 2019, 7:09 p.m. UTC | #3
On Thu, Dec 19, 2019 at 11:52 AM Richard Sandiford <
richard.sandiford@arm.com> wrote:

> Jason Merrill <jason@redhat.com> writes:
> > On 12/12/19 10:16 AM, Richard Sandiford wrote:
> >> As Jason pointed out in the review of the C++ gnu_vector_type_p patch:
> >>
> >>      https://gcc.gnu.org/ml/gcc-patches/2019-12/msg00173.html
> >>
> >> the real fix for the XFAILs in acle/general-c++/gnu_vectors_*.C is to
> >> make same_type_p return false for two types if one is gnu_vector_type_p
> >> and the other isn't.  This patch does that and fixes the fallout in the
> >> way Jason suggested above.
> >>
> >> I'd said at the time that some of the tests require:
> >>
> >>        /* If the constructor already has the array type, it's been
> through
> >>       digest_init, so we shouldn't try to do anything more.  */
> >>        bool digested = same_type_p (atype, TREE_TYPE (init));
> >>
> >> (build_vec_init) to be true for gnu vectors built from non-gnu vectors.
> >> I can no longer reproduce that, maybe because my original same_type_p
> >> change was bogus or because something in the later sizeless type
> >> support made it moot (or something else :-)).
> >>
> >> This means that sve-sizeless-2.C (the length-specific test) now reports
> >> some errors for comparisons and pointer differences that
> sve-sizeless-1.C
> >> (the length-agnostic test) already had.  I think requiring a cast is OK
> >> for those cases, since there's no reason to mix GNU and non-GNU versions
> >> of the same vector in the same object.  Even -flax-vector-conversions
> >> would require a cast for different vector types here, for both C and
> C++.
> >>
> >> same_type_p had:
> >>
> >>    else if (strict == COMPARE_STRUCTURAL)
> >>      return structural_comptypes (t1, t2, COMPARE_STRICT);
> >>    else
> >>      return structural_comptypes (t1, t2, strict);
> >>
> >> Since structural_comptypes ignored the COMPARE_STRUCTURAL bit of
> "strict"
> >> before the patch, the "else if" was harmless but AFAICT unnecessary.
> >
> > The comment in cp-tree.h has
> >
> >> #define COMPARE_STRUCTURAL    8 /* The comparison is intended to be
>
> >>                                    structural. The actual comparison
>
> >>                                    will be identical to
>
> >>                                    COMPARE_STRICT.  */
> >
> > So introducing differences between COMPARE_STRUCTURAL and COMPARE_STRICT
> > other than that the first always calls structural_comptypes and the
> > second sometimes compares TYPE_CANONICAL instead is to be avoided.
>
> OK.
>
> > Do you want to use vector_types_convertible_p in similar_type_p?
>
> The problem then is that we'll apply -flax-vector-conversion rules too,
> which seems to be going too far beyond what [conv.qual] says.
>
> But that's probably a sign that I was wanting the wrong behaviour here.
> The main point is to ensure that similar GNU and non-GNU vectors remain
> interconveritble without -flax-vector-conversions, and without any
> warnings.  There's no specific requirement to extend that to pointers,
> it just seemed like the natural thing to do at the time.
>
> So on reflection, I guess we should just accept the consequences of
> making the types !same_type_p.
>
> Tested on aarch64-linux-gnu and x86_64-linux-gnu.  OK to install?
> If so, I'll follow up with a corresponding patch for C.
>

OK.

>
>
diff mbox series

Patch

Index: gcc/c-family/c-common.c
===================================================================
--- gcc/c-family/c-common.c	2019-12-06 10:31:11.286433308 +0000
+++ gcc/c-family/c-common.c	2019-12-12 15:13:55.789913884 +0000
@@ -923,11 +923,18 @@  bool_promoted_to_int_p (tree t)
 bool
 vector_targets_convertible_p (const_tree t1, const_tree t2)
 {
-  if (VECTOR_TYPE_P (t1) && VECTOR_TYPE_P (t2)
-      && (TYPE_VECTOR_OPAQUE (t1) || TYPE_VECTOR_OPAQUE (t2))
+  if (!VECTOR_TYPE_P (t1) || !VECTOR_TYPE_P (t2))
+    return false;
+
+  if ((TYPE_VECTOR_OPAQUE (t1) || TYPE_VECTOR_OPAQUE (t2))
       && tree_int_cst_equal (TYPE_SIZE (t1), TYPE_SIZE (t2)))
     return true;
 
+  if (gnu_vector_type_p (t1) != gnu_vector_type_p (t2)
+      && known_eq (TYPE_VECTOR_SUBPARTS (t1), TYPE_VECTOR_SUBPARTS (t2))
+      && lang_hooks.types_compatible_p (TREE_TYPE (t1), TREE_TYPE (t2)))
+    return true;
+
   return false;
 }
 
Index: gcc/cp/typeck.c
===================================================================
--- gcc/cp/typeck.c	2019-12-10 09:17:17.668010318 +0000
+++ gcc/cp/typeck.c	2019-12-12 15:13:55.789913884 +0000
@@ -1429,6 +1429,9 @@  structural_comptypes (tree t1, tree t2,
       if (maybe_ne (TYPE_VECTOR_SUBPARTS (t1), TYPE_VECTOR_SUBPARTS (t2))
 	  || !same_type_p (TREE_TYPE (t1), TREE_TYPE (t2)))
 	return false;
+      if (strict == COMPARE_STRICT
+	  && gnu_vector_type_p (t1) != gnu_vector_type_p (t2))
+	return false;
       break;
 
     case TYPE_PACK_EXPANSION:
@@ -1526,8 +1529,6 @@  comptypes (tree t1, tree t2, int strict)
       else
 	return structural_comptypes (t1, t2, strict);
     }
-  else if (strict == COMPARE_STRUCTURAL)
-    return structural_comptypes (t1, t2, COMPARE_STRICT);
   else
     return structural_comptypes (t1, t2, strict);
 }
@@ -1556,6 +1557,9 @@  similar_type_p (tree type1, tree type2)
   if (type1 == error_mark_node || type2 == error_mark_node)
     return false;
 
+  if (type1 == type2)
+    return true;
+
   /* Informally, two types are similar if, ignoring top-level cv-qualification:
      * they are the same type; or
      * they are both pointers, and the pointed-to types are similar; or
@@ -1564,8 +1568,18 @@  similar_type_p (tree type1, tree type2)
      * they are both arrays of the same size or both arrays of unknown bound,
        and the array element types are similar.  */
 
-  if (same_type_ignoring_top_level_qualifiers_p (type1, type2))
-    return true;
+  tree unqual_type1 = cp_build_qualified_type (type1, TYPE_UNQUALIFIED);
+  tree unqual_type2 = cp_build_qualified_type (type2, TYPE_UNQUALIFIED);
+  if (VECTOR_TYPE_P (unqual_type1) && VECTOR_TYPE_P (unqual_type2))
+    {
+      if (comptypes (unqual_type1, unqual_type2, COMPARE_STRUCTURAL))
+	return true;
+    }
+  else
+    {
+      if (same_type_p (unqual_type1, unqual_type2))
+	return true;
+    }
 
   if ((TYPE_PTR_P (type1) && TYPE_PTR_P (type2))
       || (TYPE_PTRDATAMEM_P (type1) && TYPE_PTRDATAMEM_P (type2))
Index: gcc/testsuite/g++.dg/ext/sve-sizeless-2.C
===================================================================
--- gcc/testsuite/g++.dg/ext/sve-sizeless-2.C	2019-12-06 18:22:12.084859448 +0000
+++ gcc/testsuite/g++.dg/ext/sve-sizeless-2.C	2019-12-12 15:13:55.793913855 +0000
@@ -197,8 +197,8 @@  statements (int n)
   sve_sc_ptr -= 0; // { dg-error {arithmetic on pointer to SVE type 'svint8_t'} }
   sve_sc_ptr -= 1; // { dg-error {arithmetic on pointer to SVE type 'svint8_t'} }
   sve_sc_ptr - sve_sc_ptr; // { dg-error {arithmetic on pointer to SVE type 'svint8_t'} }
-  gnu_sc_ptr - sve_sc_ptr; // { dg-error {arithmetic on pointer to SVE type 'svint8_t'} }
-  sve_sc_ptr - gnu_sc_ptr; // { dg-error {arithmetic on pointer to SVE type 'svint8_t'} }
+  gnu_sc_ptr - sve_sc_ptr; // { dg-error {invalid operands of types 'int8x32_t\*'[^\n]* and 'svint8_t\*' to binary 'operator-'} }
+  sve_sc_ptr - gnu_sc_ptr; // { dg-error {invalid operands of types 'svint8_t\*' and 'int8x32_t\*'[^\n]* to binary 'operator-'} }
   sve_sc1 = sve_sc_ptr[0]; // { dg-error {arithmetic on pointer to SVE type 'svint8_t'} }
   sve_sc1 = sve_sc_ptr[1]; // { dg-error {arithmetic on pointer to SVE type 'svint8_t'} }
 
@@ -210,18 +210,18 @@  statements (int n)
   sve_sc_ptr <= &sve_sc1;
   sve_sc_ptr > &sve_sc1;
   sve_sc_ptr >= &sve_sc1;
-  gnu_sc_ptr == sve_sc_ptr;
-  gnu_sc_ptr != sve_sc_ptr;
-  gnu_sc_ptr < sve_sc_ptr;
-  gnu_sc_ptr <= sve_sc_ptr;
-  gnu_sc_ptr > sve_sc_ptr;
-  gnu_sc_ptr >= sve_sc_ptr;
-  sve_sc_ptr == gnu_sc_ptr;
-  sve_sc_ptr != gnu_sc_ptr;
-  sve_sc_ptr < gnu_sc_ptr;
-  sve_sc_ptr <= gnu_sc_ptr;
-  sve_sc_ptr > gnu_sc_ptr;
-  sve_sc_ptr >= gnu_sc_ptr;
+  gnu_sc_ptr == sve_sc_ptr; // { dg-error {comparison between distinct pointer types [^\n]*lacks a cast} }
+  gnu_sc_ptr != sve_sc_ptr; // { dg-error {comparison between distinct pointer types [^\n]*lacks a cast} }
+  gnu_sc_ptr < sve_sc_ptr; // { dg-error {comparison between distinct pointer types [^\n]*lacks a cast} }
+  gnu_sc_ptr <= sve_sc_ptr; // { dg-error {comparison between distinct pointer types [^\n]*lacks a cast} }
+  gnu_sc_ptr > sve_sc_ptr; // { dg-error {comparison between distinct pointer types [^\n]*lacks a cast} }
+  gnu_sc_ptr >= sve_sc_ptr; // { dg-error {comparison between distinct pointer types [^\n]*lacks a cast} }
+  sve_sc_ptr == gnu_sc_ptr; // { dg-error {comparison between distinct pointer types [^\n]*lacks a cast} }
+  sve_sc_ptr != gnu_sc_ptr; // { dg-error {comparison between distinct pointer types [^\n]*lacks a cast} }
+  sve_sc_ptr < gnu_sc_ptr; // { dg-error {comparison between distinct pointer types [^\n]*lacks a cast} }
+  sve_sc_ptr <= gnu_sc_ptr; // { dg-error {comparison between distinct pointer types [^\n]*lacks a cast} }
+  sve_sc_ptr > gnu_sc_ptr; // { dg-error {comparison between distinct pointer types [^\n]*lacks a cast} }
+  sve_sc_ptr >= gnu_sc_ptr; // { dg-error {comparison between distinct pointer types [^\n]*lacks a cast} }
 
   // New and delete.
 
@@ -243,8 +243,8 @@  statements (int n)
   0 ? 0 : sve_sc1; // { dg-error {different types 'int' and 'svint8_t'} }
   0 ? sve_sc1 : sve_sc1;
   0 ? sve_sc_ptr : sve_sc_ptr;
-  0 ? sve_sc_ptr : gnu_sc_ptr;
-  0 ? gnu_sc_ptr : sve_sc_ptr;
+  0 ? sve_sc_ptr : gnu_sc_ptr; // { dg-error {conditional expression between distinct pointer types [^\n]*lacks a cast} }
+  0 ? gnu_sc_ptr : sve_sc_ptr; // { dg-error {conditional expression between distinct pointer types [^\n]*lacks a cast} }
 
   // Function arguments.
 
@@ -321,11 +321,11 @@  statements (int n)
   { typedef int f[__is_pod (svint8_t) ? 1 : -1]; }
   { typedef int f[!__is_polymorphic (svint8_t) ? 1 : -1]; }
   { typedef int f[__is_same_as (svint8_t, svint8_t) ? 1 : -1]; }
-  { typedef int f[__is_same_as (svint8_t, int8x32_t) ? 1 : -1]; }
-  { typedef int f[__is_same_as (int8x32_t, svint8_t) ? 1 : -1]; }
+  { typedef int f[!__is_same_as (svint8_t, int8x32_t) ? 1 : -1]; }
+  { typedef int f[!__is_same_as (int8x32_t, svint8_t) ? 1 : -1]; }
   { typedef int f[__is_same_as (svint8_t *, svint8_t *) ? 1 : -1]; }
-  { typedef int f[__is_same_as (svint8_t *, int8x32_t *) ? 1 : -1]; }
-  { typedef int f[__is_same_as (int8x32_t *, svint8_t *) ? 1 : -1]; }
+  { typedef int f[!__is_same_as (svint8_t *, int8x32_t *) ? 1 : -1]; }
+  { typedef int f[!__is_same_as (int8x32_t *, svint8_t *) ? 1 : -1]; }
   { typedef int f[!__is_same_as (svint8_t, int) ? 1 : -1]; }
   { typedef int f[!__is_same_as (svint8_t, svint16_t) ? 1 : -1]; }
   { typedef int f[__is_trivial (svint8_t) ? 1 : -1]; }
Index: gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/gnu_vectors_1.C
===================================================================
--- gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/gnu_vectors_1.C	2019-12-04 09:17:59.654022577 +0000
+++ gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/gnu_vectors_1.C	2019-12-12 15:13:55.793913855 +0000
@@ -434,8 +434,8 @@  f (svuint8_t sve_u1, svint8_t sve_s1,
   // Conditional expressions.
 
   uc ? sve_u1 : sve_u1;
-  uc ? gnu_u1 : sve_u1; // { dg-error {operands to '\?:' have different types 'gnu_uint8_t'[^\n]* and 'svuint8_t'} "" { xfail *-*-* } }
-  uc ? sve_u1 : gnu_u1; // { dg-error {operands to '\?:' have different types 'svuint8_t' and 'gnu_uint8_t'} "" { xfail *-*-* } }
+  uc ? gnu_u1 : sve_u1; // { dg-error {operands to '\?:' have different types 'gnu_uint8_t'[^\n]* and 'svuint8_t'} }
+  uc ? sve_u1 : gnu_u1; // { dg-error {operands to '\?:' have different types 'svuint8_t' and 'gnu_uint8_t'} }
   uc ? gnu_u1 : gnu_u1;
 
   sve_u1 ? sve_u1 : sve_u1; // { dg-error {could not convert 'sve_u1' from 'svuint8_t' to 'bool'} }
Index: gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/gnu_vectors_2.C
===================================================================
--- gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/gnu_vectors_2.C	2019-12-04 09:17:59.654022577 +0000
+++ gcc/testsuite/g++.target/aarch64/sve/acle/general-c++/gnu_vectors_2.C	2019-12-12 15:13:55.793913855 +0000
@@ -434,8 +434,8 @@  f (svuint8_t sve_u1, svint8_t sve_s1,
   // Conditional expressions.
 
   uc ? sve_u1 : sve_u1;
-  uc ? gnu_u1 : sve_u1; // { dg-error {operands to '\?:' have different types 'gnu_uint8_t'[^\n]* and 'svuint8_t'} "" { xfail *-*-* } }
-  uc ? sve_u1 : gnu_u1; // { dg-error {operands to '\?:' have different types 'svuint8_t' and 'gnu_uint8_t'} "" { xfail *-*-* } }
+  uc ? gnu_u1 : sve_u1; // { dg-error {operands to '\?:' have different types 'gnu_uint8_t'[^\n]* and 'svuint8_t'} }
+  uc ? sve_u1 : gnu_u1; // { dg-error {operands to '\?:' have different types 'svuint8_t' and 'gnu_uint8_t'} }
   uc ? gnu_u1 : gnu_u1;
 
   sve_u1 ? sve_u1 : sve_u1; // { dg-error {could not convert 'sve_u1' from 'svuint8_t' to 'bool'} }