aboutsummaryrefslogtreecommitdiff
path: root/gcc/testsuite/gcc.dg/c2x-nullptr-1.c
blob: 4e440234d52a852802d62aa521a53467f832f0cd (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
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
/* Test valid usage of C23 nullptr.  */
/* { dg-do run } */
/* { dg-options "-std=c2x -pedantic-errors -Wall -Wextra -Wno-unused-variable" } */

#include <stdarg.h>

typedef __typeof__(nullptr) nullptr_t;

void f1 (nullptr_t) { }
void f2 (int *) { }
void f3 (_Bool) { }
nullptr_t cmp (void) { return nullptr; }

/* The type nullptr_t shall not be converted to any type other than void, bool
   or a pointer type.  No type other than nullptr_t or a null pointer constant
   shall be converted to nullptr_t.  */
void
test1 (void)
{
  const nullptr_t nptr = nullptr;
  static nullptr_t static_nptr;
  int *p1 = nullptr;
  void *p2 = nullptr;
  float *p3 = nullptr;
  void (*p4)(int) = nullptr;
  int (*p5)[10] = nullptr;
  int *p6 = nptr;
  void *p7 = nptr;
  float *p8 = nptr;
  void (*p9)(int) = nptr;
  int (*p10)[10] = nptr;
  int *p11 = (int *) nullptr;
  int *p12 = (int *) nptr;
  int *p13 = (nullptr);
  int *p14 = _Generic(0, int : nullptr);
  if (nullptr || p1 || p2 || p3 || p4 || p5 || p6 || p7 || p8 || p9 || p10
      || p11 || p12 || p13 || p14)
    __builtin_abort ();

  _Bool b1 = nullptr;
  _Bool b2 = (_Bool) nullptr;
  _Bool b3 = nptr;
  _Bool b4 = (_Bool) nptr;
  _Bool b5 = _Generic(0, int : nullptr);
  if (b1 || b2 || b3 || b4 || b5 || (_Bool) nullptr || (_Bool) nptr)
   __builtin_abort ();

  __auto_type a1 = nullptr;
  __auto_type a2 = nptr;

  /* We can convert nullptr_t to nullptr_t.  */
  __typeof__(nullptr) x = nullptr;
  f1 (x);
  f1 (nullptr);
  f1 (_Generic(0, int : nullptr));
  f2 (x);
  f2 (nullptr);
  f3 (nullptr);

  const nullptr_t np1 = nullptr;
  const nullptr_t np2 = np1;
  (void) nullptr;
  (void) np1;
  (void) np2;
  (void) cmp ();
  (void)(nullptr_t) nullptr;

  const nullptr_t n = 0;
  (void) (nullptr_t) 0;

  f1 (0);
  f1 ((void *) 0);
  f1 (0L);
  nullptr_t n2;
  n2 = (void *) 0;
  n2 = 123 - 123;
  (void) n2;
}

/* Test valid comparison.  */
void
test2 (int *p)
{
  /* If both operands have type nullptr_t or one operand has type nullptr_t
     and the other is a null pointer constant, they compare equal.  */
  const nullptr_t nptr = nullptr;
  int r = 0;

  /* Both operands have type nullptr_t.  */
  r |= nullptr != nullptr;
  r |= cmp () != nullptr;
  r |= nullptr != cmp ();
  r |= !(nullptr == nullptr);
  r |= !(cmp () == nullptr);
  r |= !(nullptr == cmp ());
  r |= nptr != nptr;
  r |= cmp () != nptr;
  r |= nptr != cmp ();
  r |= !(nptr == nptr);
  r |= !(cmp () == nptr);
  r |= !(nptr == cmp ());

 /* One operand has type nullptr_t and the other is a null pointer constant.  */
  r |= nullptr != (void *) 0;
  r |= _Generic(0, int : nullptr) != (void *) 0;
  r |= (nullptr) != (void *) 0;
  r |= !(nullptr == (void *) 0);
  r |= (void *) 0 != nullptr;
  r |= (void *) 0 != (nullptr);
  r |= !((void *) 0 == nullptr);
  r |= nullptr != 0;
  r |= _Generic(0, int : nullptr) != 0;
  r |= (nullptr) != 0;
  r |= 0 != nullptr;
  r |= 0 != (nullptr);
  r |= !(nullptr == 0);
  r |= !(0 == nullptr);
  r |= nullptr != 0u;
  r |= 0u != nullptr;
  r |= !(nullptr == 0u);
  r |= !(0u == nullptr);
  r |= nptr != (void *) 0;
  r |= !(nptr == (void *) 0);
  r |= (void *) 0 != nptr;
  r |= !((void *) 0 == nptr);
  r |= nptr != 0;
  r |= 0 != nptr;
  r |= !(nptr == 0);
  r |= !(0 == nptr);
  r |= nptr != 0u;
  r |= 0u != nptr;
  r |= !(nptr == 0u);
  r |= !(0u == nptr);
  r |= nptr != _Generic(0, int : nullptr);
  r |= _Generic(0, int : nullptr) != nptr;
  if (r)
    __builtin_abort ();

  /* One operand is a pointer and the other is a null pointer constant.  */
  (void) (p == nullptr);
  (void) (p != nullptr);
  (void) (nullptr == p);
  (void) (nullptr != p);
  (void) (p == (nullptr));
  (void) (p != (nullptr));
  (void) ((nullptr) == p);
  (void) ((nullptr) != p);
  (void) ((void *)nullptr == nullptr);
  (void) ((void *)nullptr != nullptr);
  (void) (nullptr == (void *)nullptr);
  (void) (nullptr != (void *)nullptr);
  (void) (p == _Generic(0, int : nullptr));
  (void) (p != _Generic(0, int : nullptr));
  (void) (_Generic(0, int : nullptr) == p);
  (void) (_Generic(0, int : nullptr) != p);

  /* "(nullptr_t)nullptr" has type nullptr_t but isn't an NPC; these
     comparisons are valid after C2X CD comments GB-071 and FR-073 were
     resolved by the wording in N3077.  */
  (void) ((nullptr_t)nullptr == p);
  (void) ((nullptr_t)nullptr != p);
  (void) (p == (nullptr_t)nullptr);
  (void) (p != (nullptr_t)nullptr);
  (void) (cmp () == p);
  (void) (cmp () != p);
  (void) (p == cmp ());
  (void) (p != cmp ());
  /* "(void *)nullptr" is not an NPC, either.  */
  (void) ((void *)nullptr == cmp ());
  (void) ((void *)nullptr != cmp ());
  (void) (cmp () == (void *)nullptr);
  (void) (cmp () != (void *)nullptr);
}

/* Test ?:.  */
void
test3 (int *p, _Bool b)
{
  int x = nullptr ? 1 : 2;
  (void) x;
  const nullptr_t nptr = nullptr;
  /* One of the following shall hold for the second and third operands:
     -- both operands have nullptr_t type.  */
  __auto_type r1 = b ? nullptr : nullptr;
  __auto_type r2 = b ? nptr : nptr;
  /* -- one operand is a pointer and the other is a null pointer constant
     or has type nullptr_t;  */
  __auto_type r3 = b ? p : nullptr;
  __auto_type r4 = b ? nullptr : p;
  __auto_type r5 = b ? nptr : p;
  __auto_type r6 = b ? p : nptr;
  __auto_type r7 = b ? 0 : p;
  __auto_type r8 = b ? p : 0;
  __auto_type r9 = b ? p : cmp ();
  __auto_type r10 = b ?  cmp () : p;
  __auto_type r11 = b ? p : _Generic(0, int : nullptr);
  __auto_type r12 = b ? _Generic(0, int : nullptr) : p;
}

void test_arg1 (const nullptr_t, _Atomic nullptr_t, volatile nullptr_t) { }
void test_arg2 (_Atomic int *, const int *, volatile int *) { }
void test_arg3 (_Atomic _Bool, const _Bool, volatile _Bool) { }
nullptr_t retn (void) { return nullptr; }
_Atomic int *ai (void) { return nullptr; }
const int *ci (void) { return nullptr; }
volatile int *vi (void) { return nullptr; }
_Bool retb (void) { return nullptr; }

/* Simple assignment.  */
void
test4 (void)
{
  /* -- the left operand has an atomic, qualified, or unqualified version of
     the nullptr_t type and the type of the right is nullptr_t;  */
  nullptr_t n1;
  const nullptr_t n2 = nullptr;
  _Atomic nullptr_t n3 = nullptr;
  volatile nullptr_t n4 = nullptr;
  _Atomic volatile nullptr_t n5 = nullptr;
  n1 = nullptr;
  n3 = nullptr;
  n4 = nullptr;
  n5 = nullptr;
  n5 = _Generic(0, int : nullptr);
  /* -- the left operand is an atomic, qualified, or unqualified pointer,
     and the type of the right is nullptr_t;  */
  int *p1 = cmp ();
  _Atomic int *p2 = cmp ();
  const int *volatile p3 = cmp ();
  const int *const *const p4 = cmp ();
  double (*const p5)(void) = n1;
  p2 = _Generic(0, int : nullptr);
  p3 = nullptr;
  /* -- the left operand is an atomic, qualified, or unqualified bool, and
     the type of the right is nullptr_t;  */
  _Bool b1;
  b1 = cmp ();
  const _Bool b2 = nullptr;
  _Atomic _Bool b3;
  b3 = n1;
  (void) b1;
  (void) b3;
  (void) n3;
  (void) n4;
  (void) n5;
  (void) p2;
  (void) p3;

  test_arg1 (nullptr, nullptr, nullptr);
  test_arg2 (nullptr, nullptr, nullptr);
  test_arg3 (nullptr, nullptr, nullptr);
}

/* var_arg etc.  */
static void
test5 (int i, ...)
{
  (void) i;
  va_list ap;
  va_start (ap, i);
  if (va_arg (ap, void *))
    __builtin_abort ();
}

/* Operand of alignas, sizeof or typeof operators.  */
void
test6 (void)
{
  _Static_assert (sizeof (nullptr) == sizeof (void *), "sizeof (nullptr)");
  _Static_assert (sizeof (nullptr_t) == sizeof (void *), "sizeof (nullptr_t)");
  _Static_assert (sizeof (nullptr) == sizeof (char *), "sizeof (nullptr)");
  _Static_assert (sizeof (nullptr_t) == sizeof (char *), "sizeof (nullptr_t)");
  _Static_assert (_Alignof (nullptr_t) == _Alignof (char *), "_Alignof (nullptr_t)");
  __typeof__(nullptr) t = nullptr;
  f1 (t);
  _Alignas (nullptr_t) char i1 = 'q';

  _Static_assert (_Generic (nullptr, nullptr_t: 1, default: 0) == 1, "_Generic");
  _Static_assert (_Generic (t, nullptr_t: 1, default: 0) == 1, "_Generic");
  _Static_assert (_Generic (cmp (), nullptr_t: 1, default: 0) == 1, "_Generic");
  _Static_assert (_Generic (0, nullptr_t: 1, int: 2, default: 0) == 2, "_Generic");
  _Static_assert (_Generic ((void *)0, nullptr_t: 1, void *: 2, default: 0) == 2, "_Generic");
  _Static_assert (_Generic (nullptr, nullptr_t: 1, void *: 2, default: 0) == 1, "_Generic");
}

/* Play with !, ||, &&. */
void
test7 (void)
{
  if (nullptr)
    __builtin_abort ();
  if (1 && nullptr)
    __builtin_abort ();
  if (0 || nullptr)
    __builtin_abort ();
  if (nullptr && 1)
    __builtin_abort ();
  if (nullptr || 0)
    __builtin_abort ();
  if (!nullptr)
    {
    }
  else
    __builtin_abort ();
  while (nullptr)
    __builtin_abort ();
  int i = 0;
  do
    ++i;
  while (nullptr);
  if (i != 1)
    __builtin_abort ();
  for (;nullptr;)
    __builtin_abort ();
}

int
main (void)
{
  int i = 42;
  test1 ();
  test2 (&i);
  test3 (&i, 0);
  test4 ();
  test5 (42, nullptr);
  test6 ();
  test7 ();
}