1 // Test exercising SFINAE depending on the well-definedness of constexpr
2 // functions.
3 // { dg-do compile { target c++14 } }
4
5 #define Assert(e) static_assert ((e), #e)
6
7 // Exercise SFINAE based on the absence of integer division by zero.
8 namespace DivByZero {
9
10 // Define a pair of functions that have undefined and well-defined
11 // behavior, respectively, due to division by zero, depending on
12 // their arguments.
13
14 // The following function is undefined when I is zero, well defined
15 // otherwise.
div_zero_0(int i,int j)16 constexpr bool div_zero_0 (int i, int j) { return 1 + j / (i == 0); }
17
18 // The following function is undefined when I is non-zero, and well
19 // defined otherwise.
div_zero_1(int i,int j)20 constexpr bool div_zero_1 (int i, int j) { return 1 + j / (i != 0); }
21
22 // Define a pair of overfloads each of which is viable when the constexpr
23 // function it invokes has well-defined semantics and not otherwise.
24 template <int I>
25 constexpr int f (int (*)[div_zero_0 (I, 0)] = 0) { return 0; }
26
27 template <int I>
28 constexpr int f (int (*)[div_zero_1 (I, 0)] = 0) { return 1; }
29
30 // Verify that the correct overload is selected based on the template
31 // argument and without triggering a compilation error for the undefined
32 // behavior in the non-viable constexpr function above.
33 Assert (f<0>() == 0);
34 Assert (f<1>() == 1);
35
36 }
37
38 // Exercise SFINAE based on the absence of signed integer overflow
39 // in addition.
40 namespace IntAddOverflow {
41
42 constexpr int a [] = { 1234, __INT_MAX__ / 2 };
43
vflow_0(int i)44 constexpr int vflow_0 (int i) { return a [!i] * 7; }
vflow_1(int i)45 constexpr int vflow_1 (int i) { return a [i] * 11; }
46
47 template <int I>
48 constexpr int f (int (*)[vflow_0 (I)] = 0) { return 1; }
49
50 template <int I>
51 constexpr int f (int (*)[vflow_1 (I)] = 0) { return 0; }
52
53 constexpr int n0 = f<0>();
54 constexpr int n1 = f<1>();
55
56 Assert (n0 == 0);
57 Assert (n1 == 1);
58
59 }
60
61 // Exercise SFINAE based on the absence of signed integer overflow
62 // in multiplication.
63 namespace IntMulOverflow {
64
65 constexpr long a [] = { 1234, __LONG_MAX__ / 2 };
66
vflow_0(int i)67 constexpr long vflow_0 (int i) { return a [!i] * 3; }
vflow_1(int i)68 constexpr long vflow_1 (int i) { return a [i] * 7; }
69
70 template <int I>
71 constexpr int f (int (*)[vflow_0 (I)] = 0) { return 1; }
72
73 template <int I>
74 constexpr int f (int (*)[vflow_1 (I)] = 0) { return 0; }
75
76 constexpr int n0 = f<0>();
77 constexpr int n1 = f<1>();
78
79 Assert (n0 == 0);
80 Assert (n1 == 1);
81
82 }
83
84 // Exercise SFINAE based on the absence of undefined pointer arithmetic
85 // involving null pointers. Subtracting one null pointer from another
86 // is well-defined, but subtracting a null pointer from a non-null one
87 // is not.
88 namespace NullPointerArithmetic {
89
90 constexpr int i = 0;
91 constexpr const int* a[] = { 0, &i };
92
93 // Well-defined core constant expressions involving null pointers.
94 constexpr __PTRDIFF_TYPE__ d00 = a [0] - a [0];
95 constexpr __PTRDIFF_TYPE__ d11 = a [1] - a [1];
96
97 // Undefined core constant expressions involving null pointers.
98 // constexpr __PTRDIFF_TYPE__ d01 = a [0] - a [1];
99 // constexpr __PTRDIFF_TYPE__ d10 = a [1] - a [0];
100
101 // Valid when i == j.
102 constexpr bool
nullptr_sub_0(bool i,bool j)103 nullptr_sub_0 (bool i, bool j) { return 1 + a [!i] - a [!j]; }
104
105 // Valid when i != j.
106 constexpr bool
nullptr_sub_1(bool i,bool j)107 nullptr_sub_1 (bool i, bool j) { return 1 + a [i] - a [!j]; }
108
109 // Selected when I == 0.
110 template <bool I>
111 constexpr int f (int (*)[nullptr_sub_0 (I, 0)] = 0) { return 0; }
112
113 // Selected when I != 0.
114 template <bool I>
115 constexpr int f (int (*)[nullptr_sub_1 (I, 0)] = 0) { return 1; }
116
117 constexpr int n0 = f<0>();
118 constexpr int n1 = f<1>();
119
120 Assert (n0 == 0);
121 Assert (n1 == 1);
122
123 }
124
125 // Exercise SFINAE based on the absence of undefined pointer arithmetic
126 // involving null poiinters. Subtracting one null pointer from another
127 // is well-defined, but subtracting a null pointer from a non-null one
128 // is not.
129 namespace NullPointerDereference {
130
131 struct S { int a, b; };
132
133 constexpr S s = { };
134 constexpr const S* a[] = { 0, &s };
135
nullptr_ref_0(int i)136 constexpr bool nullptr_ref_0 (int i) { return &a [i != 0]->b == &s.b; }
nullptr_ref_1(int i)137 constexpr bool nullptr_ref_1 (int i) { return &a [i == 0]->b == &s.b; }
138
139 template <int I>
140 constexpr int f (int (*)[nullptr_ref_0 (I)] = 0) { return 1; }
141
142 template <int I>
143 constexpr int f (int (*)[nullptr_ref_1 (I)] = 0) { return 0; }
144
145 constexpr int n0 = f<0>();
146 constexpr int n1 = f<1>();
147
148 Assert (n0 == 0);
149 Assert (n1 == 1);
150
151 }
152
153 // Exercise SFINAE based on whether or not two constexpr function
154 // calls have a circular depency on one another such that a call
155 // to one would not terminate.
156 namespace CircularDependency {
157
call_me(int i,bool (* f)(int))158 constexpr bool call_me (int i, bool (*f)(int)) { return f (i); }
159
undefined_if_0(int i)160 constexpr bool undefined_if_0 (int i) {
161 return i ? 1 : call_me (i, undefined_if_0);
162 }
163
undefined_if_1(int i)164 constexpr bool undefined_if_1 (int i) {
165 return i ? call_me (i, undefined_if_1) : 1;
166 }
167
168 template <int I>
169 constexpr int f (int (*)[undefined_if_0 (I)] = 0) { return 0; }
170
171 template <int I>
172 constexpr int f (int (*)[undefined_if_1 (I)] = 0) { return 1; }
173
174 constexpr int n0 = f<0>();
175 constexpr int n1 = f<1>();
176
177 Assert (n0 == 1);
178 Assert (n1 == 0);
179
180 }
181
182 // Exercise SFINAE based on whether constexpr functions flow off
183 // the end without returning a value.
184 namespace FlowOffTheEnd {
185
undefined_if_0(int i)186 constexpr bool undefined_if_0 (int i) { switch (i) case 1: return 1; }
undefined_if_1(int i)187 constexpr bool undefined_if_1 (int i) { switch (i) case 0: return 1; }
188
189 template <int I>
190 constexpr int f (int (*)[undefined_if_0 (I)] = 0) { return 1; }
191
192 template <int I>
193 constexpr int f (int (*)[undefined_if_1 (I)] = 0) { return 0; }
194
195 constexpr int n0 = f<0>();
196 constexpr int n1 = f<1>();
197
198 Assert (n0 == 0);
199 Assert (n1 == 1);
200
201 }
202
203 // Exercise SFINAE based on the presence and absence of a left shift
204 // expression with a negative second operand.
205 namespace NegativeLeftShift {
206
207 constexpr int a [] = { -1, 1 };
208
undefined_if_0(int i)209 constexpr int undefined_if_0 (int i) { return 1 << a [i]; }
undefined_if_1(int i)210 constexpr int undefined_if_1 (int i) { return 1 << a [!i]; }
211
212 template <int I>
213 constexpr int f (int (*)[undefined_if_0 (I)] = 0) { return 0; }
214
215 template <int I>
216 constexpr int f (int (*)[undefined_if_1 (I)] = 0) { return 1; }
217
218 constexpr int n0 = f<0>();
219 constexpr int n1 = f<1>();
220
221 Assert (n0 == 1);
222 Assert (n1 == 0);
223
224 }
225
226 // Exercise SFINAE based on the presence and absence of a right shift
227 // expression with a negative second operand.
228 namespace NegativeRightShift {
229
230 constexpr int a [] = { -1, 1 };
231
undefined_if_0(int i)232 constexpr int undefined_if_0 (int i) { return 2 >> a [i]; }
undefined_if_1(int i)233 constexpr int undefined_if_1 (int i) { return 2 >> a [!i]; }
234
235 template <int I>
236 constexpr int f (int (*)[undefined_if_0 (I)] = 0) { return 0; }
237
238 template <int I>
239 constexpr int f (int (*)[undefined_if_1 (I)] = 0) { return 1; }
240
241 constexpr int n0 = f<0>();
242 constexpr int n1 = f<1>();
243
244 Assert (n0 == 1);
245 Assert (n1 == 0);
246
247 }
248
249 // Exercise SFINAE based on the absence of signed integer overflow
250 // in a signed left shift expression.
251 namespace LeftShiftOverflow {
252
253 constexpr int a[] = { 1234, 1 };
254
undefined_if_0(int i)255 constexpr int undefined_if_0 (int i) { return 1 << a [i]; }
undefined_if_1(int i)256 constexpr int undefined_if_1 (int i) { return 1 << a [!i]; }
257
258 template <int I>
259 constexpr int f (int (*)[undefined_if_0 (I)] = 0) { return 0; }
260
261 template <int I>
262 constexpr int f (int (*)[undefined_if_1 (I)] = 0) { return 1; }
263
264 constexpr int n0 = f<0>();
265 constexpr int n1 = f<1>();
266
267 Assert (n0 == 1);
268 Assert (n1 == 0);
269
270 }
271
272 // Exercise SFINAE based on the absence of using a negative array
273 // index.
274 namespace NegativeArrayIndex {
275
276 constexpr int a [] = { -1, 1 };
277
undefined_if_0(int i)278 constexpr int undefined_if_0 (int i) { return 2 + a [a [i]]; }
undefined_if_1(int i)279 constexpr int undefined_if_1 (int i) { return 2 + a [a [!i]]; }
280
281 template <int I>
282 constexpr int f (int (*)[undefined_if_0 (I)] = 0) { return 0; }
283
284 template <int I>
285 constexpr int f (int (*)[undefined_if_1 (I)] = 0) { return 1; }
286
287 constexpr int n0 = f<0>();
288 constexpr int n1 = f<1>();
289
290 Assert (n0 == 1);
291 Assert (n1 == 0);
292
293 }
294