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