1 // PR c++/60760 - arithmetic on null pointers should not be allowed
2 //     in constant expressions
3 // PR c++/71091 - constexpr reference bound to a null pointer dereference
4 //     accepted
5 // { dg-do compile { target c++11 } }
6 // { dg-additional-options "-Wno-pointer-arith" }
7 
8 // Generate a null poiinter.
null()9 constexpr int* null () { return 0; }
10 
11 // Test case from comment #0 in c++/60760.
12 namespace PR_60760_comment_0 {
13 
14 constexpr int* ptr = nullptr;
15 constexpr int* ptr2 = ptr + 1;   // { dg-error "null pointer|not a constant" }
16 
17 }
18 
19 // Test case from comment #1 in c++/60760.
20 namespace PR_60760_comment_1 {
21 
22 constexpr int* ptr = nullptr;
23 
24 constexpr int zero = 0;
25 constexpr int* ptr2 = ptr + zero;   // Adding zero is valid.
26 constexpr int* ptr3 = ptr - zero;   // As is subtracting zero.
27 
28 }
29 
30 // Test case from c++/71091.
31 namespace PR_71091 {
32 
33 constexpr int *p = 0;
34 constexpr const int &r = *p;   // { dg-error "dereferencing a null pointer" }
35 
36 }
37 
38 // Other test cases.
39 namespace C {
40 
41 struct S { int a, b[1]; } s;
42 
43 constexpr S *p0 = &s;
44 constexpr S *p1 = nullptr;
45 constexpr int *r0 = p1->b;   // { dg-error "null pointer|constant expression" }
46 
47 // Adding and subtracting zero from and to a null pointer is valid.
48 constexpr S* r1 = p1 + 0;
49 constexpr S* r2 = r1 - 0;
50 
51 constexpr int zero = 0;
52 
53 constexpr S* r3 = r2 + zero;
54 constexpr S* r4 = r3 - zero;
55 
56 static_assert (r4 == nullptr, "r4 == nullptr");
57 
58 constexpr const S *pcs = p0;
59 constexpr int d1 = pcs - p0;
60 constexpr int d2 = p0 - pcs;
61 
62 constexpr bool b = !p1 && !pcs;
63 }
64 
65 namespace D {
66 
67 struct A { int i; const A *pa1; const A *pa0; };
68 
69 constexpr A a1 = { 0, 0, 0  };
70 constexpr A a2 = { 1, &a1, 0 };
71 
72 constexpr const A *pa2 = &a2;
73 constexpr int i0 = pa2->i;
74 constexpr int i1 = pa2->pa1->i;
75 constexpr int i2 = pa2->pa1->pa0->i;	    // { dg-error "null pointer|not a constant" }
76 
77 constexpr const A *pa3 = &*pa2->pa1->pa0;
78 constexpr const A *pa4 = pa2->pa1->pa0 + 1;     // { dg-error "null pointer|not a constant" }
79 
80 constexpr const int *pi0 = &pa2->pa1->pa0->i;   // { dg-error "null pointer|not a constant" }
81 
82 constexpr const A *pa5 = 0;
83 constexpr const int *pi1 = &pa5->i;	     // { dg-error "null pointer|not a constant" }
84 
85 }
86 
87 
88 namespace SimpleTests {
89 
90 constexpr int* p0 = nullptr;
91 constexpr int* q0 = p0;
92 constexpr int* r0 = null ();
93 
94 // Conversion to cv-qualified void* is valid.
95 constexpr void* pv0 = p0;
96 constexpr const void* pv1 = p0;
97 constexpr volatile void* pv2 = p0;
98 constexpr const volatile void* pv3 = p0;
99 constexpr void* pv4 = static_cast<void*>(p0);
100 constexpr const void* pv5 = static_cast<const void*>(p0);
101 
102 // The following was accepted due to bug c++/49171
103 constexpr void* pv6 = reinterpret_cast<void*>(p0);   // { dg-error "not a constant expression" }
104 
105 // Adding or subtracting zero from a null pointer is valid in C++.
106 constexpr int* p1 = p0 + 0;
107 constexpr int* p2 = p0 - 0;
108 constexpr int* p3 = 0 + p0;
109 
110 // While the text of the C++ standard still doesn't allow it, CWG
111 // issue 232 implies that dererencing a null pointer is intended
112 // to be permitted in contexts where the result isn't evaluated.
113 // For compatibility with C that should at a minimum include
114 // expressions like &*p that are valid there.
115 constexpr int* p4 = &*p0;
116 constexpr int* p5 = p0 + 1;       // { dg-error "null pointer|not a constant" }
117 constexpr int* p6 = 1 + p0;       // { dg-error "null pointer|not a constant" }
118 constexpr int* p7 = p0 - 1;       // { dg-error "null pointer|not a constant" }
119 constexpr int* p8 = &p0 [0];
120 constexpr int* p9 = &0 [p0];
121 
122 constexpr int* p10 = null () + 2; // { dg-error "null pointer|not a constant" }
123 constexpr int* p11 = 3 + null (); // { dg-error "null pointer|not a constant" }
124 constexpr int* p12 = null () - 4; // { dg-error "null pointer|not a constant" }
125 constexpr int* p13 = &null ()[4]; // { dg-error "null pointer|not a constant" }
126 constexpr int* p14 = &3[null ()]; // { dg-error "null pointer|not a constant" }
127 
128 constexpr int* q1 = q0 + 0;
129 constexpr int* q2 = q0 - 0;
130 constexpr int* q3 = q0 + 1;       // { dg-error "null pointer|not a constant" }
131 constexpr int* q4 = q0 + 2;       // { dg-error "null pointer|not a constant" }
132 constexpr int* q5 = &q0 [0];
133 
134 // Subtracting null pointers from one another is valid.
135 constexpr int i0 = p0 - (int*)0;
136 constexpr int i1 = p0 - static_cast<int*>(0);
137 constexpr int i2 = p0 - (int*)nullptr;
138 constexpr int i3 = p0 - static_cast<int*>(nullptr);
139 constexpr int i4 = p0 - p0;
140 constexpr int i5 = p0 - q0;
141 constexpr int i6 = p0 - r0;
142 constexpr int i7 = (int*)0 - p0;
143 constexpr int i8 = static_cast<int*>(0) - p0;
144 constexpr int i9 = (int*)nullptr - p0;
145 constexpr int i10 = static_cast<int*>(nullptr) - p0;
146 constexpr int i11 = q0 - p0;
147 constexpr int i12 = r0 - p0;
148 
149 }
150 
151 namespace IncompleteTypeTests {
152 
153 // The type must be complete.
154 struct X;
155 constexpr X *px0 = nullptr;
156 constexpr X *px1 = px0 + 0;     // { dg-error "invalid use of incomplete type"  }
157 constexpr X *px2 = px0 - 0;     // { dg-error "invalid use of incomplete type"  }
158 constexpr X *px3 = px0 - px0;   // { dg-error "invalid use of incomplete type"  }
159 
160 constexpr void *pv0 = px0;
161 constexpr void *pv1 = pv0;
162 constexpr const void *pv2 = pv0;
163 constexpr void *pv3 = pv2;      // { dg-error "invalid conversion|not a constant expression" }
164 constexpr const void *pv4 = pv2;
165 
166 constexpr X *px4 = pv0;	 // { dg-error "cast from|invalid conversion|not a constant expression" }
167 
168 }
169 
170 namespace IndirectTests {
171 
172 struct S { int i, j; struct SA { struct SB { int *pi; } sb; } sa; };
173 
174 constexpr S* ps = (S*)0;
175 
176 // Comparing null pointers is valid.
177 constexpr bool b0 = ps == ps;
178 constexpr bool b1 = ps != ps;
179 constexpr bool b2 = ps <  ps;
180 constexpr bool b3 = ps <= ps;
181 constexpr bool b4 = ps >  ps;
182 constexpr bool b5 = ps >= ps;
183 
184 constexpr bool b6 = ps == (S*)0;
185 constexpr bool b7 = ps != (S*)0;
186 constexpr bool b8 = ps <  (S*)0;
187 constexpr bool b9 = ps <= (S*)0;
188 constexpr bool b10 = ps >  (S*)0;
189 constexpr bool b11 = ps >= (S*)0;
190 
191 constexpr S* ps1 = ps;
192 constexpr S* ps2 = ps1;
193 
194 constexpr int* pi0 = &((S*)0)->i;	// { dg-error "null pointer|not a constant" }
195 constexpr int* pi1 = &((S*)nullptr)->i;	// { dg-error "null pointer|not a constant" }
196 
197 constexpr int* pj0 = &((S*)0)->j;	// { dg-error "null pointer|not a constant" }
198 constexpr int* pj1 = &((S*)nullptr)->j;	// { dg-error "null pointer|not a constant" }
199 
200 constexpr int* psi = &ps->i;	    // { dg-error "null pointer|not a constant" }
201 constexpr int* psj = &ps->j;	    // { dg-error "null pointer|not a constant" }
202 
203 constexpr int* ps1i = &ps1->i;	  // { dg-error "null pointer|not a constant" }
204 constexpr int* ps2i = &ps1->i;	  // { dg-error "null pointer|not a constant" }
205 
206 constexpr int* ps1j = &ps1->j;	  // { dg-error "null pointer|not a constant" }
207 constexpr int* ps2j = &ps1->j;	  // { dg-error "null pointer|not a constant" }
208 
209 }
210 
211 namespace BaseAndDerivedTests {
212 
213 struct A { };
214 struct B: A { };
215 struct C: B { };
216 struct D: B, C { };		     // { dg-warning "inaccessible" }
217 
218 constexpr D *pd0 = 0;
219 constexpr C *pc0 = 0;
220 constexpr B *pb0 = 0;
221 
222 constexpr A *pa0 = pb0;
223 constexpr A *pa1 = static_cast<A*>(pb0);
224 constexpr A *pa2 = pc0;
225 constexpr A *pa3 = pd0;		   // { dg-error "ambiguous base" }
226 constexpr A *pa4 = static_cast<A*>(pd0);  // { dg-error "ambiguous base" }
227 
228 constexpr B *pb1 = pa0;		   // { dg-error "invalid conversion|not a constant expression" }
229 constexpr B *pb2 = static_cast<B*>(pa0);
230 
231 constexpr C *pc1 = pa0;		   // { dg-error "invalid conversion|not a constant expression" }
232 constexpr D *pd1 = pa0;		   // { dg-error "ambiguous base|invalid conversion" }
233 
234 struct E: private A { };
235 
236 constexpr E *pe0 = 0;
237 constexpr A *pa5 = pe0;		 // { dg-error "inaccessible base of" }
238 
239 struct VA { virtual ~VA (); };
240 struct VB: virtual VA { };
241 struct VC: virtual VA { };
242 struct VD: VB, VC { };
243 
244 constexpr VD *pvd0 = 0;
245 constexpr VC *pvc0 = 0;
246 constexpr VB *pvb0 = 0;
247 
248 constexpr VA *pva0 = pvb0;
249 constexpr VA *pva1 = pvc0;
250 constexpr VA *pva2 = pvd0;
251 
252 constexpr VB *pvb1 = pva0;	      // { dg-error "invalid conversion|cannot convert from pointer to base class" }
253 
254 }
255 
256 namespace FunctionTests {
257 
258 typedef void Func ();
259 
260 // Arithmetic on member function pointers is diagnosed with -Wpointer-arith.
261 // With constexpr, only zero may be added or subtracted.
262 constexpr Func *pf0 = 0;
263 constexpr Func *pf1 = pf0 + 0;  // triggers -Wpointer-arith
264 constexpr Func *pf2 = pf0 - 0;  // triggers -Wpointer-arith
265 constexpr Func *pf3 = 0 + pf0;  // triggers -Wpointer-arith
266 constexpr Func *pf4 = pf0 + 1;  // { dg-error "null pointer|not a constant" }
267 constexpr Func *pf5 = 2 + pf0;  // { dg-error "null pointer|not a constant" }
268 constexpr Func *pf6 = pf0 - 3;  // { dg-error "null pointer|not a constant" }
269 
270 struct S;
271 typedef void (S::*MemFuncPtr)();
272 
273 // Arithmetic on member function pointers is rejected with a hard error.
274 constexpr MemFuncPtr pmf0 = nullptr;
275 constexpr MemFuncPtr pmf1 = pmf0 + 0;   // { dg-error "invalid operands" }
276 constexpr MemFuncPtr pmf2 = 0 + pmf0;   // { dg-error "invalid operands" }
277 constexpr MemFuncPtr pmf3 = pmf0 + 1;   // { dg-error "invalid operands" }
278 constexpr MemFuncPtr pmf4 = 1 + pmf0;   // { dg-error "invalid operands" }
279 constexpr MemFuncPtr pmf5 = pmf0 - 1;   // { dg-error "invalid operands" }
280 
281 }
282 
283 namespace ConversionTest {
284 
285 struct A {
286   int *p;
287 };
288 
f(const int * p)289 constexpr const int* f (const int *p) { return p; }
290 
f()291 void f ()
292 {
293   static_assert (!f (0), "f (a.p)");
294   static_assert (!f (nullptr), "f (a.p)");
295 
296   constexpr A a = A ();
297 
298   static_assert (!f (a.p), "f (a.p)");
299 }
300 
301 }
302