xref: /llvm-project/clang/test/C/C23/n3042.c (revision 50c81128de8616117118564eff22cf508cba7848)
1*50c81128SAaron Ballman // RUN: %clang_cc1 -verify -ffreestanding -Wno-unused -std=c2x %s
2*50c81128SAaron Ballman 
3*50c81128SAaron Ballman /* WG14 N3042: full
4*50c81128SAaron Ballman  * Introduce the nullptr constant
5*50c81128SAaron Ballman  */
6*50c81128SAaron Ballman 
7*50c81128SAaron Ballman #include <stddef.h>
8*50c81128SAaron Ballman 
9*50c81128SAaron Ballman // FIXME: The paper calls for a feature testing macro to be added to stddef.h
10*50c81128SAaron Ballman // which we do not implement. This should be addressed after WG14 has processed
11*50c81128SAaron Ballman // national body comments for C2x as we've asked for the feature test macros to
12*50c81128SAaron Ballman // be removed.
13*50c81128SAaron Ballman #ifndef __STDC_VERSION_STDDEF_H__
14*50c81128SAaron Ballman #error "no version macro for stddef.h"
15*50c81128SAaron Ballman #endif
16*50c81128SAaron Ballman // expected-error@-2 {{"no version macro for stddef.h"}}
17*50c81128SAaron Ballman 
questionable_behaviors()18*50c81128SAaron Ballman void questionable_behaviors() {
19*50c81128SAaron Ballman   nullptr_t val;
20*50c81128SAaron Ballman 
21*50c81128SAaron Ballman   // This code is intended to be rejected by C and is accepted by C++. We filed
22*50c81128SAaron Ballman   // an NB comment asking for this to be changed, but WG14 declined.
23*50c81128SAaron Ballman   (void)(1 ? val : 0);     // expected-error {{non-pointer operand type 'int' incompatible with nullptr}}
24*50c81128SAaron Ballman   (void)(1 ? nullptr : 0); // expected-error {{non-pointer operand type 'int' incompatible with nullptr}}
25*50c81128SAaron Ballman 
26*50c81128SAaron Ballman   // This code is intended to be accepted by C and is rejected by C++. We filed
27*50c81128SAaron Ballman   // an NB comment asking for this to be changed, but WG14 declined.
28*50c81128SAaron Ballman   _Bool another = val;    // expected-warning {{implicit conversion of nullptr constant to 'bool'}}
29*50c81128SAaron Ballman   another = val;          // expected-warning {{implicit conversion of nullptr constant to 'bool'}}
30*50c81128SAaron Ballman   _Bool again = nullptr;  // expected-warning {{implicit conversion of nullptr constant to 'bool'}}
31*50c81128SAaron Ballman   again = nullptr;        // expected-warning {{implicit conversion of nullptr constant to 'bool'}}
32*50c81128SAaron Ballman }
33*50c81128SAaron Ballman 
test()34*50c81128SAaron Ballman void test() {
35*50c81128SAaron Ballman   // Can we declare the type?
36*50c81128SAaron Ballman   nullptr_t null_val;
37*50c81128SAaron Ballman 
38*50c81128SAaron Ballman   // Can we use the keyword?
39*50c81128SAaron Ballman   int *typed_ptr = nullptr;
40*50c81128SAaron Ballman   typed_ptr = nullptr;
41*50c81128SAaron Ballman 
42*50c81128SAaron Ballman   // Can we use the keyword with the type?
43*50c81128SAaron Ballman   null_val = nullptr;
44*50c81128SAaron Ballman   // Even initialize with it?
45*50c81128SAaron Ballman   nullptr_t ignore = nullptr;
46*50c81128SAaron Ballman 
47*50c81128SAaron Ballman   // Can we assign an object of the type to another object of the same type?
48*50c81128SAaron Ballman   null_val = null_val;
49*50c81128SAaron Ballman 
50*50c81128SAaron Ballman   // Can we assign nullptr_t objects to pointer objects?
51*50c81128SAaron Ballman   typed_ptr = null_val;
52*50c81128SAaron Ballman 
53*50c81128SAaron Ballman   // Can we take the address of an object of type nullptr_t?
54*50c81128SAaron Ballman   &null_val;
55*50c81128SAaron Ballman 
56*50c81128SAaron Ballman   // How about the null pointer named constant?
57*50c81128SAaron Ballman   &nullptr; // expected-error {{cannot take the address of an rvalue of type 'nullptr_t'}}
58*50c81128SAaron Ballman 
59*50c81128SAaron Ballman   // Assignment from a null pointer constant to a nullptr_t is valid.
60*50c81128SAaron Ballman   null_val = 0;
61*50c81128SAaron Ballman   null_val = (void *)0;
62*50c81128SAaron Ballman 
63*50c81128SAaron Ballman   // Assignment from a nullptr_t to a pointer is also valid.
64*50c81128SAaron Ballman   typed_ptr = null_val;
65*50c81128SAaron Ballman   void *other_ptr = null_val;
66*50c81128SAaron Ballman 
67*50c81128SAaron Ballman   // Can it be used in all the places a scalar can be used?
68*50c81128SAaron Ballman   if (null_val) {}     // expected-warning {{implicit conversion of nullptr constant to 'bool'}}
69*50c81128SAaron Ballman   if (!null_val) {}    // expected-warning {{implicit conversion of nullptr constant to 'bool'}}
70*50c81128SAaron Ballman   for (;null_val;) {}  // expected-warning {{implicit conversion of nullptr constant to 'bool'}}
71*50c81128SAaron Ballman   while (nullptr) {}   // expected-warning {{implicit conversion of nullptr constant to 'bool'}}
72*50c81128SAaron Ballman   null_val && nullptr; // expected-warning {{implicit conversion of nullptr constant to 'bool'}} \
73*50c81128SAaron Ballman                           expected-warning {{implicit conversion of nullptr constant to 'bool'}}
74*50c81128SAaron Ballman   nullptr || null_val; // expected-warning {{implicit conversion of nullptr constant to 'bool'}} \
75*50c81128SAaron Ballman                           expected-warning {{implicit conversion of nullptr constant to 'bool'}}
76*50c81128SAaron Ballman   null_val ? 0 : 1;    // expected-warning {{implicit conversion of nullptr constant to 'bool'}}
77*50c81128SAaron Ballman   sizeof(null_val);
78*50c81128SAaron Ballman   alignas(nullptr_t) int aligned;
79*50c81128SAaron Ballman 
80*50c81128SAaron Ballman   // Cast expressions have special handling for nullptr_t despite allowing
81*50c81128SAaron Ballman   // casts of scalar types.
82*50c81128SAaron Ballman   (nullptr_t)12;        // expected-error {{cannot cast an object of type 'int' to 'nullptr_t'}}
83*50c81128SAaron Ballman   (float)null_val;      // expected-error {{cannot cast an object of type 'nullptr_t' to 'float'}}
84*50c81128SAaron Ballman   (float)nullptr;       // expected-error {{cannot cast an object of type 'nullptr_t' to 'float'}}
85*50c81128SAaron Ballman   (nullptr_t)0;         // expected-error {{cannot cast an object of type 'int' to 'nullptr_t'}}
86*50c81128SAaron Ballman   (nullptr_t)(void *)0; // expected-error {{cannot cast an object of type 'void *' to 'nullptr_t'}}
87*50c81128SAaron Ballman   (nullptr_t)(int *)12; // expected-error {{cannot cast an object of type 'int *' to 'nullptr_t'}}
88*50c81128SAaron Ballman 
89*50c81128SAaron Ballman   (void)null_val;     // ok
90*50c81128SAaron Ballman   (void)nullptr;      // ok
91*50c81128SAaron Ballman   (bool)null_val;     // ok
92*50c81128SAaron Ballman   (bool)nullptr;      // ok
93*50c81128SAaron Ballman   (int *)null_val;    // ok
94*50c81128SAaron Ballman   (int *)nullptr;     // ok
95*50c81128SAaron Ballman   (nullptr_t)nullptr; // ok
96*50c81128SAaron Ballman 
97*50c81128SAaron Ballman   // Can it be converted to bool with the result false (this relies on Clang
98*50c81128SAaron Ballman   // accepting additional kinds of constant expressions where an ICE is
99*50c81128SAaron Ballman   // required)?
100*50c81128SAaron Ballman   static_assert(!nullptr);  // expected-warning {{implicit conversion of nullptr constant to 'bool'}}
101*50c81128SAaron Ballman   static_assert(!null_val); // expected-warning {{implicit conversion of nullptr constant to 'bool'}}
102*50c81128SAaron Ballman   static_assert(nullptr);   // expected-error {{static assertion failed due to requirement 'nullptr'}} \
103*50c81128SAaron Ballman                                expected-warning {{implicit conversion of nullptr constant to 'bool'}}
104*50c81128SAaron Ballman   static_assert(null_val);  // expected-error {{static assertion failed due to requirement 'null_val'}} \
105*50c81128SAaron Ballman                                expected-warning {{implicit conversion of nullptr constant to 'bool'}}
106*50c81128SAaron Ballman 
107*50c81128SAaron Ballman   // Do equality operators work as expected with it?
108*50c81128SAaron Ballman   static_assert(nullptr == nullptr);
109*50c81128SAaron Ballman   static_assert(null_val == null_val);
110*50c81128SAaron Ballman   static_assert(nullptr != (int*)1);
111*50c81128SAaron Ballman   static_assert(null_val != (int*)1);
112*50c81128SAaron Ballman   static_assert(nullptr == null_val);
113*50c81128SAaron Ballman   static_assert(nullptr == 0);
114*50c81128SAaron Ballman   static_assert(null_val == (void *)0);
115*50c81128SAaron Ballman 
116*50c81128SAaron Ballman   // None of the relational operators should succeed.
117*50c81128SAaron Ballman   (void)(null_val <= 0);            // expected-error {{invalid operands to binary expression ('nullptr_t' and 'int')}}
118*50c81128SAaron Ballman   (void)(null_val >= (void *)0);    // expected-error {{invalid operands to binary expression ('nullptr_t' and 'void *')}}
119*50c81128SAaron Ballman   (void)(!(null_val < (void *)0));  // expected-error {{invalid operands to binary expression ('nullptr_t' and 'void *')}}
120*50c81128SAaron Ballman   (void)(!(null_val > 0));          // expected-error {{invalid operands to binary expression ('nullptr_t' and 'int')}}
121*50c81128SAaron Ballman   (void)(nullptr <= 0);             // expected-error {{invalid operands to binary expression ('nullptr_t' and 'int')}}
122*50c81128SAaron Ballman   (void)(nullptr >= (void *)0);     // expected-error {{invalid operands to binary expression ('nullptr_t' and 'void *')}}
123*50c81128SAaron Ballman   (void)(!(nullptr < (void *)0));   // expected-error {{invalid operands to binary expression ('nullptr_t' and 'void *')}}
124*50c81128SAaron Ballman   (void)(!(nullptr > 0));           // expected-error {{invalid operands to binary expression ('nullptr_t' and 'int')}}
125*50c81128SAaron Ballman   (void)(null_val <= null_val);     // expected-error {{invalid operands to binary expression ('nullptr_t' and 'nullptr_t')}}
126*50c81128SAaron Ballman   (void)(null_val >= null_val);     // expected-error {{invalid operands to binary expression ('nullptr_t' and 'nullptr_t')}}
127*50c81128SAaron Ballman   (void)(!(null_val < null_val));   // expected-error {{invalid operands to binary expression ('nullptr_t' and 'nullptr_t')}}
128*50c81128SAaron Ballman   (void)(!(null_val > null_val));   // expected-error {{invalid operands to binary expression ('nullptr_t' and 'nullptr_t')}}
129*50c81128SAaron Ballman   (void)(null_val <= nullptr);      // expected-error {{invalid operands to binary expression ('nullptr_t' and 'nullptr_t')}}
130*50c81128SAaron Ballman   (void)(null_val >= nullptr);      // expected-error {{invalid operands to binary expression ('nullptr_t' and 'nullptr_t')}}
131*50c81128SAaron Ballman   (void)(!(null_val < nullptr));    // expected-error {{invalid operands to binary expression ('nullptr_t' and 'nullptr_t')}}
132*50c81128SAaron Ballman   (void)(!(null_val > nullptr));    // expected-error {{invalid operands to binary expression ('nullptr_t' and 'nullptr_t')}}
133*50c81128SAaron Ballman   (void)(nullptr <= nullptr);       // expected-error {{invalid operands to binary expression ('nullptr_t' and 'nullptr_t')}}
134*50c81128SAaron Ballman   (void)(nullptr >= nullptr);       // expected-error {{invalid operands to binary expression ('nullptr_t' and 'nullptr_t')}}
135*50c81128SAaron Ballman   (void)(!(nullptr < nullptr));     // expected-error {{invalid operands to binary expression ('nullptr_t' and 'nullptr_t')}}
136*50c81128SAaron Ballman   (void)(!(nullptr > nullptr));     // expected-error {{invalid operands to binary expression ('nullptr_t' and 'nullptr_t')}}
137*50c81128SAaron Ballman 
138*50c81128SAaron Ballman   // Do we pick the correct common type for conditional operators?
139*50c81128SAaron Ballman   _Generic(1 ? nullptr : nullptr, nullptr_t : 0);
140*50c81128SAaron Ballman   _Generic(1 ? null_val : null_val, nullptr_t : 0);
141*50c81128SAaron Ballman   _Generic(1 ? typed_ptr : null_val, typeof(typed_ptr) : 0);
142*50c81128SAaron Ballman   _Generic(1 ? null_val : typed_ptr, typeof(typed_ptr) : 0);
143*50c81128SAaron Ballman   _Generic(1 ? nullptr : typed_ptr, typeof(typed_ptr) : 0);
144*50c81128SAaron Ballman   _Generic(1 ? typed_ptr : nullptr, typeof(typed_ptr) : 0);
145*50c81128SAaron Ballman 
146*50c81128SAaron Ballman   // Same for GNU conditional operators?
147*50c81128SAaron Ballman   _Generic(nullptr ?: nullptr, nullptr_t : 0);            // expected-warning {{implicit conversion of nullptr constant to 'bool'}}
148*50c81128SAaron Ballman   _Generic(null_val ?: null_val, nullptr_t : 0);          // expected-warning {{implicit conversion of nullptr constant to 'bool'}}
149*50c81128SAaron Ballman   _Generic(typed_ptr ?: null_val, typeof(typed_ptr) : 0);
150*50c81128SAaron Ballman   _Generic(null_val ?: typed_ptr, typeof(typed_ptr) : 0); // expected-warning {{implicit conversion of nullptr constant to 'bool'}}
151*50c81128SAaron Ballman   _Generic(nullptr ?: typed_ptr, typeof(typed_ptr) : 0);  // expected-warning {{implicit conversion of nullptr constant to 'bool'}}
152*50c81128SAaron Ballman   _Generic(typed_ptr ?: nullptr, typeof(typed_ptr) : 0);
153*50c81128SAaron Ballman 
154*50c81128SAaron Ballman   // Do we correctly issue type incompatibility diagnostics?
155*50c81128SAaron Ballman   int i = nullptr;   // expected-error {{initializing 'int' with an expression of incompatible type 'nullptr_t'}}
156*50c81128SAaron Ballman   float f = nullptr; // expected-error {{initializing 'float' with an expression of incompatible type 'nullptr_t'}}
157*50c81128SAaron Ballman   i = null_val;      // expected-error {{assigning to 'int' from incompatible type 'nullptr_t'}}
158*50c81128SAaron Ballman   f = null_val;      // expected-error {{assigning to 'float' from incompatible type 'nullptr_t'}}
159*50c81128SAaron Ballman   null_val = i;      // expected-error {{assigning to 'nullptr_t' from incompatible type 'int'}}
160*50c81128SAaron Ballman   null_val = f;      // expected-error {{assigning to 'nullptr_t' from incompatible type 'float'}}
161*50c81128SAaron Ballman }
162*50c81128SAaron Ballman 
163*50c81128SAaron Ballman // Can we use it as a function parameter?
164*50c81128SAaron Ballman void null_param(nullptr_t);
165*50c81128SAaron Ballman 
other_test()166*50c81128SAaron Ballman void other_test() {
167*50c81128SAaron Ballman   // Can we call the function properly?
168*50c81128SAaron Ballman   null_param(nullptr);
169*50c81128SAaron Ballman 
170*50c81128SAaron Ballman   // We can pass any kind of null pointer constant.
171*50c81128SAaron Ballman   null_param((void *)0);
172*50c81128SAaron Ballman   null_param(0);
173*50c81128SAaron Ballman }
174*50c81128SAaron Ballman 
175*50c81128SAaron Ballman 
176*50c81128SAaron Ballman void printf(const char*, ...) __attribute__((format(printf, 1, 2)));
format_specifiers()177*50c81128SAaron Ballman void format_specifiers() {
178*50c81128SAaron Ballman   // Don't warn when using nullptr with %p.
179*50c81128SAaron Ballman   printf("%p", nullptr);
180*50c81128SAaron Ballman }
181*50c81128SAaron Ballman 
182*50c81128SAaron Ballman // Ensure that conversion from a null pointer constant to nullptr_t is
183*50c81128SAaron Ballman // valid in a constant expression.
184*50c81128SAaron Ballman static_assert((nullptr_t){} == 0);
185