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