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