1 /* Test valid usage of C23 nullptr. */
2 /* { dg-do run } */
3 /* { dg-options "-std=c2x -pedantic-errors -Wall -Wextra -Wno-unused-variable" } */
4
5 #include <stdarg.h>
6
7 typedef __typeof__(nullptr) nullptr_t;
8
9 void f1 (nullptr_t) { }
10 void f2 (int *) { }
11 void f3 (_Bool) { }
12 nullptr_t cmp (void) { return nullptr; }
13
14 /* The type nullptr_t shall not be converted to any type other than void, bool
15 or a pointer type. No type other than nullptr_t or a null pointer constant
16 shall be converted to nullptr_t. */
17 void
18 test1 (void)
19 {
20 const nullptr_t nptr = nullptr;
21 static nullptr_t static_nptr;
22 int *p1 = nullptr;
23 void *p2 = nullptr;
24 float *p3 = nullptr;
25 void (*p4)(int) = nullptr;
26 int (*p5)[10] = nullptr;
27 int *p6 = nptr;
28 void *p7 = nptr;
29 float *p8 = nptr;
30 void (*p9)(int) = nptr;
31 int (*p10)[10] = nptr;
32 int *p11 = (int *) nullptr;
33 int *p12 = (int *) nptr;
34 int *p13 = (nullptr);
35 int *p14 = _Generic(0, int : nullptr);
36 if (nullptr || p1 || p2 || p3 || p4 || p5 || p6 || p7 || p8 || p9 || p10
37 || p11 || p12 || p13 || p14)
38 __builtin_abort ();
39
40 _Bool b1 = nullptr;
41 _Bool b2 = (_Bool) nullptr;
42 _Bool b3 = nptr;
43 _Bool b4 = (_Bool) nptr;
44 _Bool b5 = _Generic(0, int : nullptr);
45 if (b1 || b2 || b3 || b4 || b5 || (_Bool) nullptr || (_Bool) nptr)
46 __builtin_abort ();
47
48 __auto_type a1 = nullptr;
49 __auto_type a2 = nptr;
50
51 /* We can convert nullptr_t to nullptr_t. */
52 __typeof__(nullptr) x = nullptr;
53 f1 (x);
54 f1 (nullptr);
55 f1 (_Generic(0, int : nullptr));
56 f2 (x);
57 f2 (nullptr);
58 f3 (nullptr);
59
60 const nullptr_t np1 = nullptr;
61 const nullptr_t np2 = np1;
62 (void) nullptr;
63 (void) np1;
64 (void) np2;
65 (void) cmp ();
66 (void)(nullptr_t) nullptr;
67
68 const nullptr_t n = 0;
69 (void) (nullptr_t) 0;
70
71 f1 (0);
72 f1 ((void *) 0);
73 f1 (0L);
74 nullptr_t n2;
75 n2 = (void *) 0;
76 n2 = 123 - 123;
77 (void) n2;
78 }
79
80 /* Test valid comparison. */
81 void
82 test2 (int *p)
83 {
84 /* If both operands have type nullptr_t or one operand has type nullptr_t
85 and the other is a null pointer constant, they compare equal. */
86 const nullptr_t nptr = nullptr;
87 int r = 0;
88
89 /* Both operands have type nullptr_t. */
90 r |= nullptr != nullptr;
91 r |= cmp () != nullptr;
92 r |= nullptr != cmp ();
93 r |= !(nullptr == nullptr);
94 r |= !(cmp () == nullptr);
95 r |= !(nullptr == cmp ());
96 r |= nptr != nptr;
97 r |= cmp () != nptr;
98 r |= nptr != cmp ();
99 r |= !(nptr == nptr);
100 r |= !(cmp () == nptr);
101 r |= !(nptr == cmp ());
102
103 /* One operand has type nullptr_t and the other is a null pointer constant. */
104 r |= nullptr != (void *) 0;
105 r |= _Generic(0, int : nullptr) != (void *) 0;
106 r |= (nullptr) != (void *) 0;
107 r |= !(nullptr == (void *) 0);
108 r |= (void *) 0 != nullptr;
109 r |= (void *) 0 != (nullptr);
110 r |= !((void *) 0 == nullptr);
111 r |= nullptr != 0;
112 r |= _Generic(0, int : nullptr) != 0;
113 r |= (nullptr) != 0;
114 r |= 0 != nullptr;
115 r |= 0 != (nullptr);
116 r |= !(nullptr == 0);
117 r |= !(0 == nullptr);
118 r |= nullptr != 0u;
119 r |= 0u != nullptr;
120 r |= !(nullptr == 0u);
121 r |= !(0u == nullptr);
122 r |= nptr != (void *) 0;
123 r |= !(nptr == (void *) 0);
124 r |= (void *) 0 != nptr;
125 r |= !((void *) 0 == nptr);
126 r |= nptr != 0;
127 r |= 0 != nptr;
128 r |= !(nptr == 0);
129 r |= !(0 == nptr);
130 r |= nptr != 0u;
131 r |= 0u != nptr;
132 r |= !(nptr == 0u);
133 r |= !(0u == nptr);
134 r |= nptr != _Generic(0, int : nullptr);
135 r |= _Generic(0, int : nullptr) != nptr;
136 if (r)
137 __builtin_abort ();
138
139 /* One operand is a pointer and the other is a null pointer constant. */
140 (void) (p == nullptr);
141 (void) (p != nullptr);
142 (void) (nullptr == p);
143 (void) (nullptr != p);
144 (void) (p == (nullptr));
145 (void) (p != (nullptr));
146 (void) ((nullptr) == p);
147 (void) ((nullptr) != p);
148 (void) ((void *)nullptr == nullptr);
149 (void) ((void *)nullptr != nullptr);
150 (void) (nullptr == (void *)nullptr);
151 (void) (nullptr != (void *)nullptr);
152 (void) (p == _Generic(0, int : nullptr));
153 (void) (p != _Generic(0, int : nullptr));
154 (void) (_Generic(0, int : nullptr) == p);
155 (void) (_Generic(0, int : nullptr) != p);
156
157 /* "(nullptr_t)nullptr" has type nullptr_t but isn't an NPC; these
158 comparisons are valid after C2X CD comments GB-071 and FR-073 were
159 resolved by the wording in N3077. */
160 (void) ((nullptr_t)nullptr == p);
161 (void) ((nullptr_t)nullptr != p);
162 (void) (p == (nullptr_t)nullptr);
163 (void) (p != (nullptr_t)nullptr);
164 (void) (cmp () == p);
165 (void) (cmp () != p);
166 (void) (p == cmp ());
167 (void) (p != cmp ());
168 /* "(void *)nullptr" is not an NPC, either. */
169 (void) ((void *)nullptr == cmp ());
170 (void) ((void *)nullptr != cmp ());
171 (void) (cmp () == (void *)nullptr);
172 (void) (cmp () != (void *)nullptr);
173 }
174
175 /* Test ?:. */
176 void
177 test3 (int *p, _Bool b)
178 {
179 int x = nullptr ? 1 : 2;
180 (void) x;
181 const nullptr_t nptr = nullptr;
182 /* One of the following shall hold for the second and third operands:
183 -- both operands have nullptr_t type. */
184 __auto_type r1 = b ? nullptr : nullptr;
185 __auto_type r2 = b ? nptr : nptr;
186 /* -- one operand is a pointer and the other is a null pointer constant
187 or has type nullptr_t; */
188 __auto_type r3 = b ? p : nullptr;
189 __auto_type r4 = b ? nullptr : p;
190 __auto_type r5 = b ? nptr : p;
191 __auto_type r6 = b ? p : nptr;
192 __auto_type r7 = b ? 0 : p;
193 __auto_type r8 = b ? p : 0;
194 __auto_type r9 = b ? p : cmp ();
195 __auto_type r10 = b ? cmp () : p;
196 __auto_type r11 = b ? p : _Generic(0, int : nullptr);
197 __auto_type r12 = b ? _Generic(0, int : nullptr) : p;
198 }
199
200 void test_arg1 (const nullptr_t, _Atomic nullptr_t, volatile nullptr_t) { }
201 void test_arg2 (_Atomic int *, const int *, volatile int *) { }
202 void test_arg3 (_Atomic _Bool, const _Bool, volatile _Bool) { }
203 nullptr_t retn (void) { return nullptr; }
204 _Atomic int *ai (void) { return nullptr; }
205 const int *ci (void) { return nullptr; }
206 volatile int *vi (void) { return nullptr; }
207 _Bool retb (void) { return nullptr; }
208
209 /* Simple assignment. */
210 void
211 test4 (void)
212 {
213 /* -- the left operand has an atomic, qualified, or unqualified version of
214 the nullptr_t type and the type of the right is nullptr_t; */
215 nullptr_t n1;
216 const nullptr_t n2 = nullptr;
217 _Atomic nullptr_t n3 = nullptr;
218 volatile nullptr_t n4 = nullptr;
219 _Atomic volatile nullptr_t n5 = nullptr;
220 n1 = nullptr;
221 n3 = nullptr;
222 n4 = nullptr;
223 n5 = nullptr;
224 n5 = _Generic(0, int : nullptr);
225 /* -- the left operand is an atomic, qualified, or unqualified pointer,
226 and the type of the right is nullptr_t; */
227 int *p1 = cmp ();
228 _Atomic int *p2 = cmp ();
229 const int *volatile p3 = cmp ();
230 const int *const *const p4 = cmp ();
231 double (*const p5)(void) = n1;
232 p2 = _Generic(0, int : nullptr);
233 p3 = nullptr;
234 /* -- the left operand is an atomic, qualified, or unqualified bool, and
235 the type of the right is nullptr_t; */
236 _Bool b1;
237 b1 = cmp ();
238 const _Bool b2 = nullptr;
239 _Atomic _Bool b3;
240 b3 = n1;
241 (void) b1;
242 (void) b3;
243 (void) n3;
244 (void) n4;
245 (void) n5;
246 (void) p2;
247 (void) p3;
248
249 test_arg1 (nullptr, nullptr, nullptr);
250 test_arg2 (nullptr, nullptr, nullptr);
251 test_arg3 (nullptr, nullptr, nullptr);
252 }
253
254 /* var_arg etc. */
255 static void
256 test5 (int i, ...)
257 {
258 (void) i;
259 va_list ap;
260 va_start (ap, i);
261 if (va_arg (ap, void *))
262 __builtin_abort ();
263 }
264
265 /* Operand of alignas, sizeof or typeof operators. */
266 void
267 test6 (void)
268 {
269 _Static_assert (sizeof (nullptr) == sizeof (void *), "sizeof (nullptr)");
270 _Static_assert (sizeof (nullptr_t) == sizeof (void *), "sizeof (nullptr_t)");
271 _Static_assert (sizeof (nullptr) == sizeof (char *), "sizeof (nullptr)");
272 _Static_assert (sizeof (nullptr_t) == sizeof (char *), "sizeof (nullptr_t)");
273 _Static_assert (_Alignof (nullptr_t) == _Alignof (char *), "_Alignof (nullptr_t)");
274 __typeof__(nullptr) t = nullptr;
275 f1 (t);
276 _Alignas (nullptr_t) char i1 = 'q';
277
278 _Static_assert (_Generic (nullptr, nullptr_t: 1, default: 0) == 1, "_Generic");
279 _Static_assert (_Generic (t, nullptr_t: 1, default: 0) == 1, "_Generic");
280 _Static_assert (_Generic (cmp (), nullptr_t: 1, default: 0) == 1, "_Generic");
281 _Static_assert (_Generic (0, nullptr_t: 1, int: 2, default: 0) == 2, "_Generic");
282 _Static_assert (_Generic ((void *)0, nullptr_t: 1, void *: 2, default: 0) == 2, "_Generic");
283 _Static_assert (_Generic (nullptr, nullptr_t: 1, void *: 2, default: 0) == 1, "_Generic");
284 }
285
286 /* Play with !, ||, &&. */
287 void
288 test7 (void)
289 {
290 if (nullptr)
291 __builtin_abort ();
292 if (1 && nullptr)
293 __builtin_abort ();
294 if (0 || nullptr)
295 __builtin_abort ();
296 if (nullptr && 1)
297 __builtin_abort ();
298 if (nullptr || 0)
299 __builtin_abort ();
300 if (!nullptr)
301 {
302 }
303 else
304 __builtin_abort ();
305 while (nullptr)
306 __builtin_abort ();
307 int i = 0;
308 do
309 ++i;
310 while (nullptr);
311 if (i != 1)
312 __builtin_abort ();
313 for (;nullptr;)
314 __builtin_abort ();
315 }
316
317 int
318 main (void)
319 {
320 int i = 42;
321 test1 ();
322 test2 (&i);
323 test3 (&i, 0);
324 test4 ();
325 test5 (42, nullptr);
326 test6 ();
327 test7 ();
328 }