111
|
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
|
145
|
30 #if __cplusplus >= 201402L
|
111
|
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))
|
145
|
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
|
111
|
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
|