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