Erich Keane | 349636d | 2019-12-05 06:17:39 -0800 | [diff] [blame] | 1 | // RUN: %clang_cc1 -triple x86_64-linux-pc -fsyntax-only -verify -fexceptions -fcxx-exceptions %s -std=c++17 |
| 2 | // Note that this test depends on the size of long-long to be different from |
| 3 | // int, so it specifies a triple. |
| 4 | |
| 5 | using FourShorts = short __attribute__((__vector_size__(8))); |
| 6 | using TwoInts = int __attribute__((__vector_size__(8))); |
| 7 | using TwoUInts = unsigned __attribute__((__vector_size__(8))); |
| 8 | using FourInts = int __attribute__((__vector_size__(16))); |
| 9 | using FourUInts = unsigned __attribute__((__vector_size__(16))); |
| 10 | using TwoLongLong = long long __attribute__((__vector_size__(16))); |
| 11 | using FourLongLong = long long __attribute__((__vector_size__(32))); |
| 12 | using TwoFloats = float __attribute__((__vector_size__(8))); |
| 13 | using FourFloats = float __attribute__((__vector_size__(16))); |
| 14 | using TwoDoubles = double __attribute__((__vector_size__(16))); |
| 15 | using FourDoubles = double __attribute__((__vector_size__(32))); |
| 16 | |
| 17 | FourShorts four_shorts; |
| 18 | TwoInts two_ints; |
| 19 | TwoUInts two_uints; |
| 20 | FourInts four_ints; |
| 21 | FourUInts four_uints; |
| 22 | TwoLongLong two_ll; |
| 23 | FourLongLong four_ll; |
| 24 | TwoFloats two_floats; |
| 25 | FourFloats four_floats; |
| 26 | TwoDoubles two_doubles; |
| 27 | FourDoubles four_doubles; |
| 28 | |
| 29 | enum E {}; |
| 30 | enum class SE {}; |
| 31 | E e; |
| 32 | SE se; |
| 33 | |
| 34 | // Check the rules of the condition of the conditional operator. |
| 35 | void Condition() { |
| 36 | // Only int types are allowed here, the rest should fail to convert to bool. |
| 37 | (void)(four_floats ? 1 : 1); // expected-error {{is not contextually convertible to 'bool'}}} |
| 38 | (void)(two_doubles ? 1 : 1); // expected-error {{is not contextually convertible to 'bool'}}} |
| 39 | } |
| 40 | |
| 41 | // Check the rules of the LHS/RHS of the conditional operator. |
| 42 | void Operands() { |
| 43 | (void)(four_ints ? four_ints : throw 1); // expected-error {{GNU vector conditional operand cannot be a throw expression}} |
| 44 | (void)(four_ints ? throw 1 : four_ints); // expected-error {{GNU vector conditional operand cannot be a throw expression}} |
| 45 | (void)(four_ints ?: throw 1); // expected-error {{GNU vector conditional operand cannot be a throw expression}} |
| 46 | (void)(four_ints ? (void)1 : four_ints); // expected-error {{GNU vector conditional operand cannot be void}} |
| 47 | (void)(four_ints ?: (void)1); // expected-error {{GNU vector conditional operand cannot be void}} |
| 48 | |
| 49 | // Vector types must be the same element size as the condition. |
| 50 | (void)(four_ints ? two_ll : two_ll); // expected-error {{vector condition type 'FourInts' (vector of 4 'int' values) and result type 'TwoLongLong' (vector of 2 'long long' values) do not have the same number of elements}} |
| 51 | (void)(four_ints ? four_ll : four_ll); // expected-error {{vector condition type 'FourInts' (vector of 4 'int' values) and result type 'FourLongLong' (vector of 4 'long long' values) do not have elements of the same size}} |
| 52 | (void)(four_ints ? two_doubles : two_doubles); // expected-error {{vector condition type 'FourInts' (vector of 4 'int' values) and result type 'TwoDoubles' (vector of 2 'double' values) do not have the same number of elements}} |
| 53 | (void)(four_ints ? four_doubles : four_doubles); // expected-error {{vector condition type 'FourInts' (vector of 4 'int' values) and result type 'FourDoubles' (vector of 4 'double' values) do not have elements of the same size}} |
| 54 | (void)(four_ints ?: two_ints); // expected-error {{vector operands to the vector conditional must be the same type ('FourInts' (vector of 4 'int' values) and 'TwoInts' (vector of 2 'int' values)}} |
| 55 | (void)(four_ints ?: four_doubles); // expected-error {{vector operands to the vector conditional must be the same type ('FourInts' (vector of 4 'int' values) and 'FourDoubles' (vector of 4 'double' values)}} |
| 56 | |
| 57 | // Scalars are promoted, but must be the same element size. |
| 58 | (void)(four_ints ? 3.0f : 3.0); // expected-error {{vector condition type 'FourInts' (vector of 4 'int' values) and result type '__attribute__((__vector_size__(4 * sizeof(double)))) double' (vector of 4 'double' values) do not have elements of the same size}} |
| 59 | (void)(four_ints ? 5ll : 5); // expected-error {{vector condition type 'FourInts' (vector of 4 'int' values) and result type '__attribute__((__vector_size__(4 * sizeof(long long)))) long long' (vector of 4 'long long' values) do not have elements of the same size}} |
| 60 | (void)(four_ints ?: 3.0); // expected-error {{cannot convert between scalar type 'double' and vector type 'FourInts' (vector of 4 'int' values) as implicit conversion would cause truncation}} |
| 61 | (void)(four_ints ?: 5ll); // We allow this despite GCc not allowing this since we support integral->vector-integral conversions despite integer rank. |
| 62 | |
| 63 | // This one would be allowed in GCC, but we don't allow vectors of enum. Also, |
| 64 | // the error message isn't perfect, since it is only going to be a problem |
| 65 | // when both sides are an enum, otherwise it'll be promoted to whatever type |
| 66 | // the other side causes. |
| 67 | (void)(four_ints ? e : e); // expected-error {{enumeration type 'E' is not allowed in a vector conditional}} |
| 68 | (void)(four_ints ? se : se); // expected-error {{enumeration type 'SE' is not allowed in a vector conditional}} |
| 69 | (void)(four_shorts ? (short)5 : (unsigned short)5); // expected-error {{vector condition type 'FourShorts' (vector of 4 'short' values) and result type '__attribute__((__vector_size__(4 * sizeof(int)))) int' (vector of 4 'int' values) do not have elements of the same size}} |
| 70 | |
| 71 | // They must also be convertible. |
| 72 | (void)(four_ints ? 3.0f : 5u); |
| 73 | (void)(four_ints ? 3.0f : 5); |
| 74 | unsigned us = 5u; |
| 75 | int sint = 5; |
| 76 | short shrt = 5; |
| 77 | unsigned short uss = 5u; |
| 78 | // The following 2 error in GCC for truncation errors, but it seems |
| 79 | // unimportant and inconsistent to enforce that rule. |
| 80 | (void)(four_ints ? 3.0f : us); |
| 81 | (void)(four_ints ? 3.0f : sint); |
| 82 | |
| 83 | // Test promotion: |
| 84 | (void)(four_shorts ? uss : shrt); // expected-error {{vector condition type 'FourShorts' (vector of 4 'short' values) and result type '__attribute__((__vector_size__(4 * sizeof(int)))) int' (vector of 4 'int' values) do not have elements of the same size}} |
| 85 | (void)(four_shorts ? shrt : shrt); // should be fine. |
| 86 | (void)(four_ints ? uss : shrt); // should be fine, since they get promoted to int. |
| 87 | (void)(four_ints ? shrt : shrt); //expected-error {{vector condition type 'FourInts' (vector of 4 'int' values) and result type '__attribute__((__vector_size__(4 * sizeof(short)))) short' (vector of 4 'short' values) do not have elements of the same size}} |
| 88 | |
| 89 | // Vectors must be the same type as eachother. |
| 90 | (void)(four_ints ? four_uints : four_floats); // expected-error {{vector operands to the vector conditional must be the same type ('FourUInts' (vector of 4 'unsigned int' values) and 'FourFloats' (vector of 4 'float' values))}} |
| 91 | (void)(four_ints ? four_uints : four_ints); // expected-error {{vector operands to the vector conditional must be the same type ('FourUInts' (vector of 4 'unsigned int' values) and 'FourInts' (vector of 4 'int' values))}} |
| 92 | (void)(four_ints ? four_ints : four_uints); // expected-error {{vector operands to the vector conditional must be the same type ('FourInts' (vector of 4 'int' values) and 'FourUInts' (vector of 4 'unsigned int' values))}} |
| 93 | |
| 94 | // GCC rejects these, but our lax vector conversions don't seem to have a problem with them. Allow conversion of the float to an int as an extension. |
| 95 | (void)(four_ints ? four_uints : 3.0f); |
| 96 | (void)(four_ints ? four_ints : 3.0f); |
| 97 | |
| 98 | // When there is a vector and a scalar, conversions must be legal. |
| 99 | (void)(four_ints ? four_floats : 3); // should work, ints can convert to floats. |
Erich Keane | 9fbf998 | 2020-05-04 13:09:28 -0700 | [diff] [blame] | 100 | (void)(four_ints ? four_uints : e); // expected-error {{cannot convert between scalar type 'E' and vector type 'FourUInts'}} |
Erich Keane | 349636d | 2019-12-05 06:17:39 -0800 | [diff] [blame] | 101 | (void)(four_ints ? four_uints : se); // expected-error {{cannot convert between vector and non-scalar values ('FourUInts' (vector of 4 'unsigned int' values) and 'SE'}} |
| 102 | // GCC permits this, but our conversion rules reject this for truncation. |
| 103 | (void)(two_ints ? two_ints : us); // expected-error {{cannot convert between scalar type 'unsigned int' and vector type 'TwoInts'}} |
| 104 | (void)(four_shorts ? four_shorts : uss); // expected-error {{cannot convert between scalar type 'unsigned short' and vector type 'FourShorts'}} |
| 105 | (void)(four_ints ? four_floats : us); // expected-error {{cannot convert between scalar type 'unsigned int' and vector type 'FourFloats'}} |
| 106 | (void)(four_ints ? four_floats : sint); // expected-error {{cannot convert between scalar type 'int' and vector type 'FourFloats'}} |
| 107 | } |
| 108 | |
| 109 | template <typename T1, typename T2> |
| 110 | struct is_same { |
| 111 | static constexpr bool value = false; |
| 112 | }; |
| 113 | template <typename T> |
| 114 | struct is_same<T, T> { |
| 115 | static constexpr bool value = true; |
| 116 | }; |
| 117 | template <typename T1, typename T2> |
| 118 | constexpr bool is_same_v = is_same<T1, T2>::value; |
| 119 | template <typename T> |
| 120 | T &&declval(); |
| 121 | |
| 122 | // Check the result types when given two vector types. |
| 123 | void ResultTypes() { |
| 124 | // Vectors must be the same, but result is the type of the LHS/RHS. |
| 125 | static_assert(is_same_v<TwoInts, decltype(declval<TwoInts>() ? declval<TwoInts>() : declval<TwoInts>())>); |
| 126 | static_assert(is_same_v<TwoFloats, decltype(declval<TwoInts>() ? declval<TwoFloats>() : declval<TwoFloats>())>); |
| 127 | |
| 128 | // When both are scalars, converts to vectors of common type. |
| 129 | static_assert(is_same_v<TwoUInts, decltype(declval<TwoInts>() ? declval<int>() : declval<unsigned int>())>); |
| 130 | |
| 131 | // Constant is allowed since it doesn't truncate, and should promote to float. |
| 132 | static_assert(is_same_v<TwoFloats, decltype(declval<TwoInts>() ? declval<float>() : 5u)>); |
| 133 | static_assert(is_same_v<TwoFloats, decltype(declval<TwoInts>() ? 5 : declval<float>())>); |
| 134 | |
| 135 | // when only 1 is a scalar, it should convert to a compatible type. |
| 136 | static_assert(is_same_v<TwoFloats, decltype(declval<TwoInts>() ? declval<TwoFloats>() : declval<float>())>); |
| 137 | static_assert(is_same_v<TwoInts, decltype(declval<TwoInts>() ? declval<TwoInts>() : declval<int>())>); |
| 138 | static_assert(is_same_v<TwoFloats, decltype(declval<TwoInts>() ? declval<TwoFloats>() : 5)>); |
| 139 | |
| 140 | // For the Binary conditional operator, the result type is either the vector on the RHS (that fits the rules on size/count), or the scalar extended to the correct count. |
| 141 | static_assert(is_same_v<TwoInts, decltype(declval<TwoInts>() ?: declval<TwoInts>())>); |
| 142 | static_assert(is_same_v<TwoInts, decltype(declval<TwoInts>() ?: declval<int>())>); |
| 143 | } |
| 144 | |
| 145 | template <typename Cond> |
| 146 | void dependent_cond(Cond C) { |
| 147 | (void)(C ? 1 : 2); |
| 148 | } |
| 149 | |
| 150 | template <typename Operand> |
| 151 | void dependent_operand(Operand C) { |
| 152 | (void)(two_ints ? 1 : C); |
| 153 | (void)(two_ints ? C : 1); |
| 154 | (void)(two_ints ? C : C); |
| 155 | } |
| 156 | |
| 157 | template <typename Cond, typename LHS, typename RHS> |
| 158 | void all_dependent(Cond C, LHS L, RHS R) { |
| 159 | (void)(C ? L : R); |
| 160 | } |
| 161 | |
| 162 | // Check dependent cases. |
| 163 | void Templates() { |
| 164 | dependent_cond(two_ints); |
| 165 | dependent_operand(two_floats); |
| 166 | // expected-error@159 {{vector operands to the vector conditional must be the same type ('__attribute__((__vector_size__(4 * sizeof(unsigned int)))) unsigned int' (vector of 4 'unsigned int' values) and '__attribute__((__vector_size__(4 * sizeof(double)))) double' (vector of 4 'double' values))}}} |
| 167 | all_dependent(four_ints, four_uints, four_doubles); // expected-note {{in instantiation of}} |
| 168 | |
| 169 | // expected-error@159 {{vector operands to the vector conditional must be the same type ('__attribute__((__vector_size__(4 * sizeof(unsigned int)))) unsigned int' (vector of 4 'unsigned int' values) and '__attribute__((__vector_size__(2 * sizeof(unsigned int)))) unsigned int' (vector of 2 'unsigned int' values))}}} |
| 170 | all_dependent(four_ints, four_uints, two_uints); // expected-note {{in instantiation of}} |
| 171 | all_dependent(four_ints, four_uints, four_uints); |
| 172 | } |