aboutsummaryrefslogtreecommitdiff
path: root/gcc/testsuite/g++.dg/cpp0x/constexpr-arith-overflow.C
blob: a63c0a1ef540d96ba82c8bcaa3963c3f7b3a91e7 (plain)
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
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
// PR c++/70507 - integer overflow builtins not constant expressions
// { dg-do compile { target c++11 } }

#define SCHAR_MAX    __SCHAR_MAX__
#define SHRT_MAX     __SHRT_MAX__
#define INT_MAX	     __INT_MAX__
#define LONG_MAX     __LONG_MAX__
#define LLONG_MAX    __LONG_LONG_MAX__
	
#define SCHAR_MIN    (-__SCHAR_MAX__ - 1)
#define SHRT_MIN     (-__SHRT_MAX__ - 1)
#define INT_MIN	     (-__INT_MAX__ - 1)
#define LONG_MIN     (-__LONG_MAX__ - 1)
#define LLONG_MIN    (-__LONG_LONG_MAX__ - 1)
	
#define UCHAR_MAX    (SCHAR_MAX * 2U + 1)
#define USHRT_MAX    (SHRT_MAX * 2U + 1)
#define UINT_MAX     (INT_MAX * 2U + 1)
#define ULONG_MAX    (LONG_MAX * 2LU + 1)
#define ULLONG_MAX   (LLONG_MAX * 2LLU + 1)
	
#define USCHAR_MIN   (-__USCHAR_MAX__ - 1)
#define USHRT_MIN    (-__USHRT_MAX__ - 1)
#define UINT_MIN     (-__UINT_MAX__ - 1)
#define ULONG_MIN    (-__ULONG_MAX__ - 1)
#define ULLONG_MIN   (-__ULONG_LONG_MAX__ - 1)

#define Assert(expr) static_assert ((expr), #expr)

template <class T>
constexpr T add (T x, T y, T z = T ())
{
  return __builtin_add_overflow (x, y, &z) ? 0 : z;
}

template <class T>
constexpr T sub (T x, T y, T z = T ())
{
  return __builtin_sub_overflow (x, y, &z) ? 0 : z;
}

template <class T>
constexpr T mul (T x, T y, T z = T ())
{
  return __builtin_mul_overflow (x, y, &z) ? 0 : z;
}

#define TEST_ADD(T, x, y, z) Assert (z == add<T>(x, y))
#define TEST_SUB(T, x, y, z) Assert (z == sub<T>(x, y))
#define TEST_MUL(T, x, y, z) Assert (z == mul<T>(x, y))


TEST_ADD (signed char,  0,         0,         0);
TEST_ADD (signed char,  0,         SCHAR_MAX, SCHAR_MAX);
TEST_ADD (signed char,  1,         SCHAR_MAX, 0);           // overflow
TEST_ADD (signed char,  SCHAR_MAX, SCHAR_MAX, 0);           // overflow
TEST_ADD (signed char,  0,         SCHAR_MIN, SCHAR_MIN);
TEST_ADD (signed char, -1,         SCHAR_MIN, 0);           // overflow

TEST_ADD (short,        0,         0,         0);
TEST_ADD (short,        0,         SHRT_MAX,  SHRT_MAX);
TEST_ADD (short,        1,         SHRT_MAX,  0);           // overflow
TEST_ADD (short,        SHRT_MAX,  SHRT_MAX,  0);           // overflow
TEST_ADD (short,        0,         SHRT_MIN,  SHRT_MIN);
TEST_ADD (short,       -1,         SHRT_MIN,  0);           // overflow
TEST_ADD (short,        SHRT_MIN,  SHRT_MIN,  0);           // overflow

TEST_ADD (int,          0,         0,         0);
TEST_ADD (int,          0,         INT_MAX,   INT_MAX);
TEST_ADD (int,          1,         INT_MAX,   0);           // overflow
TEST_ADD (int,          INT_MAX,   INT_MAX,   0);           // overflow
TEST_ADD (int,          0,         INT_MIN,   INT_MIN);
TEST_ADD (int,         -1,         INT_MIN,   0);           // overflow
TEST_ADD (int,          INT_MIN,   INT_MIN,   0);           // overflow

TEST_ADD (long,         0,         0,         0);
TEST_ADD (long,         0,         LONG_MAX,  LONG_MAX);
TEST_ADD (long,         1,         LONG_MAX,  0);           // overflow
TEST_ADD (long,         LONG_MAX,  LONG_MAX,  0);           // overflow
TEST_ADD (long,         0,         LONG_MIN,  LONG_MIN);
TEST_ADD (long,        -1,         LONG_MIN,  0);           // overflow
TEST_ADD (long,         LONG_MIN,  LONG_MIN,  0);           // overflow

TEST_ADD (long long,    0,         0,          0);
TEST_ADD (long long,    0,         LLONG_MAX,  LLONG_MAX);
TEST_ADD (long long,    1,         LLONG_MAX,  0);          // overflow
TEST_ADD (long long,    LLONG_MAX, LLONG_MAX,  0);          // overflow
TEST_ADD (long long,    0,         LLONG_MIN,  LLONG_MIN);
TEST_ADD (long long,   -1,         LLONG_MIN,  0);          // overflow
TEST_ADD (long long,    LLONG_MIN, LLONG_MIN,  0);          // overflow

TEST_ADD (unsigned char,  0,         0,         0);
TEST_ADD (unsigned char,  0,         UCHAR_MAX, UCHAR_MAX);
TEST_ADD (unsigned char,  1,         UCHAR_MAX, 0);         // overflow

TEST_ADD (unsigned char,  UCHAR_MAX, UCHAR_MAX, 0);         // overflow
TEST_ADD (unsigned short, 0,         0,          0);
TEST_ADD (unsigned short, 0,         USHRT_MAX,  USHRT_MAX);
TEST_ADD (unsigned short, 1,         USHRT_MAX,  0);        // overflow
TEST_ADD (unsigned short, USHRT_MAX, USHRT_MAX,  0);        // overflow

TEST_ADD (unsigned,       0,         0,          0);
TEST_ADD (unsigned,       0,         UINT_MAX,   UINT_MAX);
TEST_ADD (unsigned,       1,         UINT_MAX,   0);        // overflow
TEST_ADD (unsigned,       UINT_MAX,  UINT_MAX,   0);        // overflow

TEST_ADD (unsigned long,  0,         0,         0);
TEST_ADD (unsigned long,  0,         ULONG_MAX, ULONG_MAX);
TEST_ADD (unsigned long,  1,         ULONG_MAX, 0);         // overflow
TEST_ADD (unsigned long,  ULONG_MAX, ULONG_MAX, 0);         // overflow

TEST_ADD (unsigned long long,  0,          0,          0);
TEST_ADD (unsigned long long,  0,          ULLONG_MAX, ULLONG_MAX);
TEST_ADD (unsigned long long,  1,          ULLONG_MAX, 0);  // overflow
TEST_ADD (unsigned long long,  ULLONG_MAX, ULLONG_MAX, 0);  // overflow


// Make sure the built-ins are accepted in the following contexts
// where constant expressions are required and that they return
// the expected overflow value.

namespace Enum {

enum Add {
  a0 = __builtin_add_overflow_p (      1, 1, 0),
  a1 = __builtin_add_overflow_p (INT_MAX, 1, 0)
};

Assert (a0 == 0);
Assert (a1 == 1);

enum Sub {
  s0 = __builtin_sub_overflow_p (      1, 1, 0),
  s1 = __builtin_sub_overflow_p (INT_MIN, 1, 0)
};

Assert (s0 == 0);
Assert (s1 == 1);

enum Mul {
  m0 = __builtin_add_overflow_p (      1,       1, 0),
  m1 = __builtin_add_overflow_p (INT_MAX, INT_MAX, 0)
};

Assert (m0 == 0);
Assert (m1 == 1);

}   // namespace Enum

namespace TemplateArg {

template <class T, class U, class V,
	  T x, U y, bool v, bool z = __builtin_add_overflow_p (x, y, V ())>
struct Add {
  Assert (z == v);
};

template <class T, class U, class V,
	  T x, U y, bool v, bool z = __builtin_sub_overflow_p (x, y, V ())>
struct Sub {
  Assert (z == v);
};

template <class T, class U, class V,
	  T x, U y, bool v, bool z = __builtin_mul_overflow_p (x, y, V ())>
struct Mul {
  Assert (z == v);
};

template struct Add<int, int, int,  1,       1, false>;
template struct Add<int, int, int,  1, INT_MAX, true>;

template struct Sub<int, int, int,  1,       1, false>;
template struct Sub<int, int, int, -2, INT_MAX, true>;

template struct Mul<int, int, int,  1,               1, false>;
template struct Mul<int, int, int,  2, INT_MAX / 2 + 1, true>;

}   // namespace TemplateArg

#if __cplusplus >= 201402L

namespace Initializer {

struct Result {
  int res;
  bool vflow;
};

constexpr Result
add_vflow (int a, int b)
{
#if 1
  Result res = { a + b, __builtin_add_overflow_p (a, b, int ()) };
#else
  // The following fails to compile because of c++/71391 - error
  // on aggregate initialization with side-effects in a constexpr
  // function
  int c = 0;
  Result res = { 0, __builtin_add_overflow (a, b, &c) };
  res.c = c;
#endif
  return res;
}

constexpr Result sum = add_vflow (123, 456);
Assert (sum.res == 123 + 456);
Assert (!sum.vflow);

}   // namespace Initializer

#endif   // __cplusplus >= 201402L