1 // PR c++/70507 - integer overflow builtins not constant expressions 2 // { dg-do compile { target c++11 } } 3 4 #define SCHAR_MAX __SCHAR_MAX__ 5 #define SHRT_MAX __SHRT_MAX__ 6 #define INT_MAX __INT_MAX__ 7 #define LONG_MAX __LONG_MAX__ 8 #define LLONG_MAX __LONG_LONG_MAX__ 9 10 #define SCHAR_MIN (-__SCHAR_MAX__ - 1) 11 #define SHRT_MIN (-__SHRT_MAX__ - 1) 12 #define INT_MIN (-__INT_MAX__ - 1) 13 #define LONG_MIN (-__LONG_MAX__ - 1) 14 #define LLONG_MIN (-__LONG_LONG_MAX__ - 1) 15 16 #define UCHAR_MAX (SCHAR_MAX * 2U + 1) 17 #define USHRT_MAX (SHRT_MAX * 2U + 1) 18 #define UINT_MAX (INT_MAX * 2U + 1) 19 #define ULONG_MAX (LONG_MAX * 2LU + 1) 20 #define ULLONG_MAX (LLONG_MAX * 2LLU + 1) 21 22 #define USCHAR_MIN (-__USCHAR_MAX__ - 1) 23 #define USHRT_MIN (-__USHRT_MAX__ - 1) 24 #define UINT_MIN (-__UINT_MAX__ - 1) 25 #define ULONG_MIN (-__ULONG_MAX__ - 1) 26 #define ULLONG_MIN (-__ULONG_LONG_MAX__ - 1) 27 28 #define Assert(expr) static_assert ((expr), #expr) 29 30 #if __cplusplus >= 201402L 31 template <class T> 32 constexpr T add (T x, T y, T z = T ()) 33 { 34 return __builtin_add_overflow (x, y, &z) ? 0 : z; 35 } 36 37 template <class T> 38 constexpr T sub (T x, T y, T z = T ()) 39 { 40 return __builtin_sub_overflow (x, y, &z) ? 0 : z; 41 } 42 43 template <class T> 44 constexpr T mul (T x, T y, T z = T ()) 45 { 46 return __builtin_mul_overflow (x, y, &z) ? 0 : z; 47 } 48 49 #define TEST_ADD(T, x, y, z) Assert (z == add<T>(x, y)) 50 #define TEST_SUB(T, x, y, z) Assert (z == sub<T>(x, y)) 51 #define TEST_MUL(T, x, y, z) Assert (z == mul<T>(x, y)) 52 #else 53 #define TEST_ADD(T, x, y, z) Assert (true) 54 #define TEST_SUB(T, x, y, z) Assert (true) 55 #define TEST_MUL(T, x, y, z) Assert (true) 56 #endif 57 58 59 TEST_ADD (signed char, 0, 0, 0); 60 TEST_ADD (signed char, 0, SCHAR_MAX, SCHAR_MAX); 61 TEST_ADD (signed char, 1, SCHAR_MAX, 0); // overflow 62 TEST_ADD (signed char, SCHAR_MAX, SCHAR_MAX, 0); // overflow 63 TEST_ADD (signed char, 0, SCHAR_MIN, SCHAR_MIN); 64 TEST_ADD (signed char, -1, SCHAR_MIN, 0); // overflow 65 66 TEST_ADD (short, 0, 0, 0); 67 TEST_ADD (short, 0, SHRT_MAX, SHRT_MAX); 68 TEST_ADD (short, 1, SHRT_MAX, 0); // overflow 69 TEST_ADD (short, SHRT_MAX, SHRT_MAX, 0); // overflow 70 TEST_ADD (short, 0, SHRT_MIN, SHRT_MIN); 71 TEST_ADD (short, -1, SHRT_MIN, 0); // overflow 72 TEST_ADD (short, SHRT_MIN, SHRT_MIN, 0); // overflow 73 74 TEST_ADD (int, 0, 0, 0); 75 TEST_ADD (int, 0, INT_MAX, INT_MAX); 76 TEST_ADD (int, 1, INT_MAX, 0); // overflow 77 TEST_ADD (int, INT_MAX, INT_MAX, 0); // overflow 78 TEST_ADD (int, 0, INT_MIN, INT_MIN); 79 TEST_ADD (int, -1, INT_MIN, 0); // overflow 80 TEST_ADD (int, INT_MIN, INT_MIN, 0); // overflow 81 82 TEST_ADD (long, 0, 0, 0); 83 TEST_ADD (long, 0, LONG_MAX, LONG_MAX); 84 TEST_ADD (long, 1, LONG_MAX, 0); // overflow 85 TEST_ADD (long, LONG_MAX, LONG_MAX, 0); // overflow 86 TEST_ADD (long, 0, LONG_MIN, LONG_MIN); 87 TEST_ADD (long, -1, LONG_MIN, 0); // overflow 88 TEST_ADD (long, LONG_MIN, LONG_MIN, 0); // overflow 89 90 TEST_ADD (long long, 0, 0, 0); 91 TEST_ADD (long long, 0, LLONG_MAX, LLONG_MAX); 92 TEST_ADD (long long, 1, LLONG_MAX, 0); // overflow 93 TEST_ADD (long long, LLONG_MAX, LLONG_MAX, 0); // overflow 94 TEST_ADD (long long, 0, LLONG_MIN, LLONG_MIN); 95 TEST_ADD (long long, -1, LLONG_MIN, 0); // overflow 96 TEST_ADD (long long, LLONG_MIN, LLONG_MIN, 0); // overflow 97 98 TEST_ADD (unsigned char, 0, 0, 0); 99 TEST_ADD (unsigned char, 0, UCHAR_MAX, UCHAR_MAX); 100 TEST_ADD (unsigned char, 1, UCHAR_MAX, 0); // overflow 101 102 TEST_ADD (unsigned char, UCHAR_MAX, UCHAR_MAX, 0); // overflow 103 TEST_ADD (unsigned short, 0, 0, 0); 104 TEST_ADD (unsigned short, 0, USHRT_MAX, USHRT_MAX); 105 TEST_ADD (unsigned short, 1, USHRT_MAX, 0); // overflow 106 TEST_ADD (unsigned short, USHRT_MAX, USHRT_MAX, 0); // overflow 107 108 TEST_ADD (unsigned, 0, 0, 0); 109 TEST_ADD (unsigned, 0, UINT_MAX, UINT_MAX); 110 TEST_ADD (unsigned, 1, UINT_MAX, 0); // overflow 111 TEST_ADD (unsigned, UINT_MAX, UINT_MAX, 0); // overflow 112 113 TEST_ADD (unsigned long, 0, 0, 0); 114 TEST_ADD (unsigned long, 0, ULONG_MAX, ULONG_MAX); 115 TEST_ADD (unsigned long, 1, ULONG_MAX, 0); // overflow 116 TEST_ADD (unsigned long, ULONG_MAX, ULONG_MAX, 0); // overflow 117 118 TEST_ADD (unsigned long long, 0, 0, 0); 119 TEST_ADD (unsigned long long, 0, ULLONG_MAX, ULLONG_MAX); 120 TEST_ADD (unsigned long long, 1, ULLONG_MAX, 0); // overflow 121 TEST_ADD (unsigned long long, ULLONG_MAX, ULLONG_MAX, 0); // overflow 122 123 124 // Make sure the built-ins are accepted in the following contexts 125 // where constant expressions are required and that they return 126 // the expected overflow value. 127 128 namespace Enum { 129 130 enum Add { 131 a0 = __builtin_add_overflow_p ( 1, 1, 0), 132 a1 = __builtin_add_overflow_p (INT_MAX, 1, 0) 133 }; 134 135 Assert (a0 == 0); 136 Assert (a1 == 1); 137 138 enum Sub { 139 s0 = __builtin_sub_overflow_p ( 1, 1, 0), 140 s1 = __builtin_sub_overflow_p (INT_MIN, 1, 0) 141 }; 142 143 Assert (s0 == 0); 144 Assert (s1 == 1); 145 146 enum Mul { 147 m0 = __builtin_add_overflow_p ( 1, 1, 0), 148 m1 = __builtin_add_overflow_p (INT_MAX, INT_MAX, 0) 149 }; 150 151 Assert (m0 == 0); 152 Assert (m1 == 1); 153 154 } // namespace Enum 155 156 namespace TemplateArg { 157 158 template <class T, class U, class V, 159 T x, U y, bool v, bool z = __builtin_add_overflow_p (x, y, V ())> 160 struct Add { 161 Assert (z == v); 162 }; 163 164 template <class T, class U, class V, 165 T x, U y, bool v, bool z = __builtin_sub_overflow_p (x, y, V ())> 166 struct Sub { 167 Assert (z == v); 168 }; 169 170 template <class T, class U, class V, 171 T x, U y, bool v, bool z = __builtin_mul_overflow_p (x, y, V ())> 172 struct Mul { 173 Assert (z == v); 174 }; 175 176 template struct Add<int, int, int, 1, 1, false>; 177 template struct Add<int, int, int, 1, INT_MAX, true>; 178 179 template struct Sub<int, int, int, 1, 1, false>; 180 template struct Sub<int, int, int, -2, INT_MAX, true>; 181 182 template struct Mul<int, int, int, 1, 1, false>; 183 template struct Mul<int, int, int, 2, INT_MAX / 2 + 1, true>; 184 185 } // namespace TemplateArg 186 187 #if __cplusplus >= 201402L 188 189 namespace Initializer { 190 191 struct Result { 192 int res; 193 bool vflow; 194 }; 195 196 constexpr Result 197 add_vflow (int a, int b) 198 { 199 #if 1 200 Result res = { a + b, __builtin_add_overflow_p (a, b, int ()) }; 201 #else 202 // The following fails to compile because of c++/71391 - error 203 // on aggregate initialization with side-effects in a constexpr 204 // function 205 int c = 0; 206 Result res = { 0, __builtin_add_overflow (a, b, &c) }; 207 res.c = c; 208 #endif 209 return res; 210 } 211 212 constexpr Result sum = add_vflow (123, 456); 213 Assert (sum.res == 123 + 456); 214 Assert (!sum.vflow); 215 216 } // namespace Initializer 217 218 #endif // __cplusplus >= 201402L 219