[clang] Implement lifetime analysis for lifetime_capture_by(X) (#115921)
[llvm-project.git] / clang / test / SemaCXX / builtin-is-within-lifetime.cpp
blob62ff2681952ce5792ce6758515df611ecb39697b
1 // RUN: %clang_cc1 -std=c++20 -Wno-unused %s -verify=expected,cxx20 -Wno-vla-cxx-extension
2 // RUN: %clang_cc1 -std=c++23 -Wno-unused %s -verify=expected,sincecxx23 -Wno-vla-cxx-extension
3 // RUN: %clang_cc1 -std=c++26 -Wno-unused %s -verify=expected,sincecxx23 -Wno-vla-cxx-extension
4 // RUN: %clang_cc1 -std=c++26 -DINLINE_NAMESPACE -Wno-unused %s -verify=expected,sincecxx23 -Wno-vla-cxx-extension
6 inline constexpr void* operator new(__SIZE_TYPE__, void* p) noexcept { return p; }
7 namespace std {
8 template<typename T, typename... Args>
9 constexpr T* construct_at(T* p, Args&&... args) { return ::new((void*)p) T(static_cast<Args&&>(args)...); }
10 template<typename T>
11 constexpr void destroy_at(T* p) { p->~T(); }
12 template<typename T>
13 struct allocator {
14 constexpr T* allocate(__SIZE_TYPE__ n) { return static_cast<T*>(::operator new(n * sizeof(T))); }
15 constexpr void deallocate(T* p, __SIZE_TYPE__) { ::operator delete(p); }
17 using nullptr_t = decltype(nullptr);
18 template<typename T, T v>
19 struct integral_constant { static constexpr T value = v; };
20 template<bool v>
21 using bool_constant = integral_constant<bool, v>;
22 using true_type = bool_constant<true>;
23 using false_type = bool_constant<false>;
24 template<typename T>
25 inline constexpr bool is_function_v = __is_function(T);
26 #ifdef INLINE_NAMESPACE
27 inline namespace __1 {
28 #endif
29 template<typename T> requires (!is_function_v<T>) // #std-constraint
30 consteval bool is_within_lifetime(const T* p) noexcept { // #std-definition
31 return __builtin_is_within_lifetime(p);
33 #ifdef INLINE_NAMESPACE
35 #endif
38 consteval bool test_union(int& i, char& c) {
39 if (__builtin_is_within_lifetime(&i) || __builtin_is_within_lifetime(&c))
40 return false;
41 std::construct_at(&c, 1);
42 if (__builtin_is_within_lifetime(&i) || !__builtin_is_within_lifetime(&c))
43 return false;
44 std::construct_at(&i, 3);
45 if (!__builtin_is_within_lifetime(&i) || __builtin_is_within_lifetime(&c))
46 return false;
47 return true;
50 static_assert([]{
51 union { int i; char c; } u;
52 return test_union(u.i, u.c);
53 }());
54 static_assert([]{
55 union { int i; char c; };
56 return test_union(i, c);
57 }());
58 static_assert([]{
59 struct { union { int i; char c; }; } u;
60 return test_union(u.i, u.c);
61 }());
62 static_assert([]{
63 struct { union { int i; char c; } u; } r;
64 return test_union(r.u.i, r.u.c);
65 }());
67 consteval bool test_nested() {
68 union {
69 union { int i; char c; } u;
70 long l;
72 if (__builtin_is_within_lifetime(&l) || __builtin_is_within_lifetime(&u) || __builtin_is_within_lifetime(&u.i) || __builtin_is_within_lifetime(&u.c))
73 return false;
74 std::construct_at(&l);
75 if (!__builtin_is_within_lifetime(&l) || __builtin_is_within_lifetime(&u) || __builtin_is_within_lifetime(&u.i) || __builtin_is_within_lifetime(&u.c))
76 return false;
77 std::construct_at(&u);
78 std::construct_at(&u.i);
79 if (__builtin_is_within_lifetime(&l) || !__builtin_is_within_lifetime(&u) || !__builtin_is_within_lifetime(&u.i) || __builtin_is_within_lifetime(&u.c))
80 return false;
81 std::construct_at(&u.c);
82 if (__builtin_is_within_lifetime(&l) || !__builtin_is_within_lifetime(&u) || __builtin_is_within_lifetime(&u.i) || !__builtin_is_within_lifetime(&u.c))
83 return false;
84 return true;
86 static_assert(test_nested());
88 consteval bool test_dynamic(bool read_after_deallocate) {
89 std::allocator<int> a;
90 int* p = a.allocate(1);
91 // a.allocate starts the lifetime of an array,
92 // the complete object of *p has started its lifetime
93 if (__builtin_is_within_lifetime(p))
94 return false;
95 std::construct_at(p);
96 if (!__builtin_is_within_lifetime(p))
97 return false;
98 std::destroy_at(p);
99 if (__builtin_is_within_lifetime(p))
100 return false;
101 a.deallocate(p, 1);
102 if (read_after_deallocate)
103 __builtin_is_within_lifetime(p); // expected-note {{read of heap allocated object that has been deleted}}
104 return true;
106 static_assert(test_dynamic(false));
107 static_assert(test_dynamic(true));
108 // expected-error@-1 {{static assertion expression is not an integral constant expression}}
109 // expected-note@-2 {{in call to 'test_dynamic(true)'}}
111 consteval bool test_automatic(int read_dangling) {
112 int* p;
114 int x = 0;
115 p = &x;
116 if (!__builtin_is_within_lifetime(p))
117 return false;
120 int x = 0;
121 if (read_dangling == 1)
122 __builtin_is_within_lifetime(p); // expected-note {{read of object outside its lifetime is not allowed in a constant expression}}
124 if (read_dangling == 2)
125 __builtin_is_within_lifetime(p); // expected-note {{read of object outside its lifetime is not allowed in a constant expression}}
127 int x[4];
128 p = &x[2];
129 if (!__builtin_is_within_lifetime(p))
130 return false;
132 if (read_dangling == 3)
133 __builtin_is_within_lifetime(p); // expected-note {{read of object outside its lifetime is not allowed in a constant expression}}
134 std::nullptr_t* q;
136 std::nullptr_t np = nullptr;
137 q = &np;
138 if (!__builtin_is_within_lifetime(q))
139 return false;
141 if (read_dangling == 4)
142 __builtin_is_within_lifetime(q); // expected-note {{read of object outside its lifetime is not allowed in a constant expression}}
143 return true;
145 static_assert(test_automatic(0));
146 static_assert(test_automatic(1));
147 // expected-error@-1 {{static assertion expression is not an integral constant expression}}
148 // expected-note@-2 {{in call to 'test_automatic(1)'}}
149 static_assert(test_automatic(2));
150 // expected-error@-1 {{static assertion expression is not an integral constant expression}}
151 // expected-note@-2 {{in call to 'test_automatic(2)'}}
152 static_assert(test_automatic(3));
153 // expected-error@-1 {{static assertion expression is not an integral constant expression}}
154 // expected-note@-2 {{in call to 'test_automatic(3)'}}
155 static_assert(test_automatic(4));
156 // expected-error@-1 {{static assertion expression is not an integral constant expression}}
157 // expected-note@-2 {{in call to 'test_automatic(4)'}}
160 consteval bool test_indeterminate() {
161 int x;
162 if (!__builtin_is_within_lifetime(&x))
163 return false;
164 bool b = true;
165 unsigned char c = __builtin_bit_cast(unsigned char, b);
166 if (!__builtin_is_within_lifetime(&c))
167 return false;
168 struct {} padding;
169 unsigned char y = __builtin_bit_cast(unsigned char, padding);
170 if (!__builtin_is_within_lifetime(&y))
171 return false;
172 return true;
174 static_assert(test_indeterminate());
176 consteval bool test_volatile() {
177 int x;
178 if (!__builtin_is_within_lifetime(static_cast<volatile int*>(&x)) || !__builtin_is_within_lifetime(static_cast<volatile void*>(&x)))
179 return false;
180 volatile int y;
181 if (!__builtin_is_within_lifetime(const_cast<int*>(&y)) || !__builtin_is_within_lifetime(const_cast<void*>(static_cast<volatile void*>(&y))))
182 return false;
183 return true;
185 static_assert(test_volatile());
187 constexpr bool self = __builtin_is_within_lifetime(&self);
188 // expected-error@-1 {{constexpr variable 'self' must be initialized by a constant expression}}
189 // expected-note@-2 {{'__builtin_is_within_lifetime' cannot be called with a pointer to an object whose lifetime has not yet begun}}
190 // expected-error@-3 {{call to consteval function '__builtin_is_within_lifetime' is not a constant expression}}
191 // expected-note@-4 {{initializer of 'self' is not a constant expression}}
192 // expected-note@-5 {{declared here}}
193 constexpr int external{};
194 static_assert(__builtin_is_within_lifetime(&external));
195 void not_constexpr() {
196 __builtin_is_within_lifetime(&external);
198 void invalid_args() {
199 __builtin_is_within_lifetime(static_cast<int*>(nullptr));
200 // expected-error@-1 {{call to consteval function '__builtin_is_within_lifetime' is not a constant expression}}
201 // expected-note@-2 {{'__builtin_is_within_lifetime' cannot be called with a null pointer}}
203 // FIXME: avoid function to pointer conversion on all consteval builtins
204 __builtin_is_within_lifetime(0);
205 // expected-error@-1 {{non-pointer argument to '__builtin_is_within_lifetime' is not allowed}}
206 // expected-error@-2 {{cannot take address of consteval function '__builtin_is_within_lifetime' outside of an immediate invocation}}
207 __builtin_is_within_lifetime();
208 // expected-error@-1 {{too few arguments to function call, expected 1, have 0}}
209 // expected-error@-2 {{cannot take address of consteval function '__builtin_is_within_lifetime' outside of an immediate invocation}}
210 __builtin_is_within_lifetime(1, 2);
211 // expected-error@-1 {{too many arguments to function call, expected 1, have 2}}
212 // expected-error@-2 {{cannot take address of consteval function '__builtin_is_within_lifetime' outside of an immediate invocation}}
213 __builtin_is_within_lifetime(&external, &external);
214 // expected-error@-1 {{too many arguments to function call, expected 1, have 2}}
215 // expected-error@-2 {{cannot take address of consteval function '__builtin_is_within_lifetime' outside of an immediate invocation}}
218 constexpr struct {
219 union {
220 int i;
221 char c;
223 mutable int mi; // #x-mi
224 } x1{ .c = 2 };
225 static_assert(!__builtin_is_within_lifetime(&x1.i));
226 static_assert(__builtin_is_within_lifetime(&x1.c));
227 static_assert(__builtin_is_within_lifetime(&x1.mi));
228 // expected-error@-1 {{static assertion expression is not an integral constant expression}}
229 // expected-note@-2 {{read of mutable member 'mi' is not allowed in a constant expression}}
230 // expected-note@#x-mi {{declared here}}
232 constexpr struct NSDMI { // #NSDMI
233 bool a = true;
234 bool b = __builtin_is_within_lifetime(&a); // #NSDMI-read
235 } x2;
236 // expected-error@-1 {{constexpr variable 'x2' must be initialized by a constant expression}}
237 // expected-note@#NSDMI-read {{'__builtin_is_within_lifetime' cannot be called with a pointer to an object whose lifetime has not yet begun}}
238 // expected-note@-3 {{in call to 'NSDMI()'}}
239 // expected-error@-4 {{call to immediate function 'NSDMI::NSDMI' is not a constant expression}}
240 // expected-note@#NSDMI {{'NSDMI' is an immediate constructor because the default initializer of 'b' contains a call to a consteval function '__builtin_is_within_lifetime' and that call is not a constant expression}}
241 // expected-note@#NSDMI-read {{'__builtin_is_within_lifetime' cannot be called with a pointer to an object whose lifetime has not yet begun}}
242 // expected-note@-7 {{in call to 'NSDMI()'}}
244 struct X3 {
245 consteval X3() {
246 __builtin_is_within_lifetime(this); // #X3-read
248 } x3;
249 // expected-error@-1 {{call to consteval function 'X3::X3' is not a constant expression}}
250 // expected-note@#X3-read {{'__builtin_is_within_lifetime' cannot be called with a pointer to an object whose lifetime has not yet begun}}
251 // expected-note@-3 {{in call to 'X3()'}}
253 constexpr int i = 2;
254 static_assert(__builtin_is_within_lifetime(const_cast<int*>(&i)));
255 static_assert(__builtin_is_within_lifetime(const_cast<volatile int*>(&i)));
256 static_assert(__builtin_is_within_lifetime(static_cast<const void*>(&i)));
258 constexpr int arr[2]{};
259 static_assert(__builtin_is_within_lifetime(arr));
260 static_assert(__builtin_is_within_lifetime(arr + 0));
261 static_assert(__builtin_is_within_lifetime(arr + 1));
262 void f() {
263 __builtin_is_within_lifetime(&i + 1);
264 // expected-error@-1 {{call to consteval function '__builtin_is_within_lifetime' is not a constant expression}}
265 // expected-note@-2 {{'__builtin_is_within_lifetime' cannot be called with a one-past-the-end pointer}}
266 __builtin_is_within_lifetime(arr + 2);
267 // expected-error@-1 {{call to consteval function '__builtin_is_within_lifetime' is not a constant expression}}
268 // expected-note@-2 {{'__builtin_is_within_lifetime' cannot be called with a one-past-the-end pointer}}
271 template<typename T>
272 consteval void disallow_function_types(bool b, const T* p) {
273 if (b) {
274 __builtin_is_within_lifetime(p); // expected-error {{function pointer argument to '__builtin_is_within_lifetime' is not allowed}}
277 void g() {
278 disallow_function_types<void ()>(false, &f);
279 // expected-note@-1 {{in instantiation of function template specialization 'disallow_function_types<void ()>' requested here}}
282 struct OptBool {
283 union { bool b; char c; };
285 // note: this assumes common implementation properties for bool and char:
286 // * sizeof(bool) == sizeof(char), and
287 // * the value representations for true and false are distinct
288 // from the value representation for 2
289 constexpr OptBool() : c(2) { }
290 constexpr OptBool(bool b) : b(b) { }
292 constexpr auto has_value() const -> bool {
293 if consteval { // cxx20-warning {{consteval if}}
294 return __builtin_is_within_lifetime(&b); // during constant evaluation, cannot read from c
295 } else {
296 return c != 2; // during runtime, must read from c
300 constexpr auto operator*() const -> const bool& {
301 return b;
305 constexpr OptBool disengaged;
306 constexpr OptBool engaged(true);
307 static_assert(!disengaged.has_value());
308 static_assert(engaged.has_value());
309 static_assert(*engaged);
311 namespace vlas {
313 consteval bool f(int n) {
314 int vla[n]; // cxx20-error {{variable of non-literal type}}
315 return __builtin_is_within_lifetime(static_cast<void*>(&vla));
317 static_assert(f(1));
319 consteval bool fail(int n) {
320 int vla[n]; // cxx20-error {{variable of non-literal type}}
321 return __builtin_is_within_lifetime(&vla); // expected-error {{variable length arrays are not supported in '__builtin_is_within_lifetime'}}
323 static_assert(fail(1)); // sincecxx23-error {{static assertion expression is not an integral constant expression}}
325 consteval bool variably_modified(int n) {
326 int(* p)[n];
327 return __builtin_is_within_lifetime(&p);
329 static_assert(variably_modified(1));
331 } // namespace vlas
333 consteval bool partial_arrays() {
334 int arr[2];
335 if (!__builtin_is_within_lifetime(&arr) || !__builtin_is_within_lifetime(&arr[0]) || !__builtin_is_within_lifetime(&arr[1]))
336 return false;
337 std::destroy_at(&arr[0]);
338 if (!__builtin_is_within_lifetime(&arr) || __builtin_is_within_lifetime(&arr[0]) || !__builtin_is_within_lifetime(&arr[1]))
339 return false;
340 std::construct_at(&arr[0]);
341 if (!__builtin_is_within_lifetime(&arr) || !__builtin_is_within_lifetime(&arr[0]) || !__builtin_is_within_lifetime(&arr[1]))
342 return false;
343 return true;
345 static_assert(partial_arrays());
347 consteval bool partial_members() {
348 struct S {
349 int x;
350 int y;
351 } s;
352 if (!__builtin_is_within_lifetime(&s) || !__builtin_is_within_lifetime(&s.x) || !__builtin_is_within_lifetime(&s.y))
353 return false;
354 std::destroy_at(&s.x);
355 if (!__builtin_is_within_lifetime(&s) || __builtin_is_within_lifetime(&s.x) || !__builtin_is_within_lifetime(&s.y))
356 return false;
357 std::construct_at(&s.x);
358 if (!__builtin_is_within_lifetime(&s) || !__builtin_is_within_lifetime(&s.x) || !__builtin_is_within_lifetime(&s.y))
359 return false;
360 return true;
363 struct NonTrivial {
364 constexpr NonTrivial() {}
365 constexpr NonTrivial(const NonTrivial&) {}
366 constexpr ~NonTrivial() {}
369 template<typename T>
370 constexpr T& unmove(T&& temp) { return static_cast<T&>(temp); }
372 consteval bool test_temporaries() {
373 static_assert(__builtin_is_within_lifetime(&unmove(0)));
374 static_assert(__builtin_is_within_lifetime(&unmove(NonTrivial{})));
375 if (!__builtin_is_within_lifetime(&unmove(0)))
376 return false;
377 if (!__builtin_is_within_lifetime(&unmove(NonTrivial{})))
378 return false;
379 return true;
381 static_assert(test_temporaries());
383 constexpr const int& temp = 0;
384 static_assert(__builtin_is_within_lifetime(&temp));
386 template<typename T>
387 constexpr T* test_dangling() {
388 T i; // expected-note 2 {{declared here}}
389 return &i; // expected-warning 2 {{address of stack memory associated with local variable 'i' returned}}
391 static_assert(__builtin_is_within_lifetime(test_dangling<int>())); // expected-note {{in instantiation of function template specialization}}
392 // expected-error@-1 {{static assertion expression is not an integral constant expression}}
393 // expected-note@-2 {{read of variable whose lifetime has ended}}
394 static_assert(__builtin_is_within_lifetime(test_dangling<int[1]>())); // expected-note {{in instantiation of function template specialization}}
395 // expected-error@-1 {{static assertion expression is not an integral constant expression}}
396 // expected-note@-2 {{read of variable whose lifetime has ended}}
398 template<auto F>
399 concept CanCallAndPassToIsWithinLifetime = std::bool_constant<__builtin_is_within_lifetime(F())>::value;
400 static_assert(CanCallAndPassToIsWithinLifetime<[]{ return &i; }>);
401 static_assert(!CanCallAndPassToIsWithinLifetime<[]{ return static_cast<int*>(nullptr); }>);
402 static_assert(!CanCallAndPassToIsWithinLifetime<[]{ return static_cast<void(*)()>(&f); }>);
403 template<auto F> constexpr std::true_type sfinae() requires CanCallAndPassToIsWithinLifetime<F> { return {}; }
404 template<auto F> std::false_type sfinae() { return {}; }
405 static_assert(decltype(sfinae<[]{ return &i; }>())::value);
406 static_assert(!decltype(sfinae<[]{ return static_cast<int*>(nullptr); }>())::value);
407 std::true_type(* not_immediate)() = &sfinae<[]{ return &i; }>;
409 void test_std_error_message() {
410 std::is_within_lifetime(static_cast<int*>(nullptr));
411 // expected-error@-1 {{call to consteval function 'std::is_within_lifetime<int>' is not a constant expression}}
412 // expected-note@-2 {{'std::is_within_lifetime' cannot be called with a null pointer}}
413 // expected-note@-3 {{in call to 'is_within_lifetime<int>(nullptr)'}}
414 std::is_within_lifetime<void()>(&test_std_error_message);
415 // expected-error@-1 {{no matching function for call to 'is_within_lifetime'}}
416 // expected-note@#std-definition {{candidate template ignored: constraints not satisfied [with T = void ()]}}
417 // expected-note@#std-constraint {{because '!is_function_v<void ()>' evaluated to false}}
418 std::is_within_lifetime(arr + 2);
419 // expected-error@-1 {{call to consteval function 'std::is_within_lifetime<int>' is not a constant expression}}
420 // expected-note@-2 {{'std::is_within_lifetime' cannot be called with a one-past-the-end pointer}}
421 // expected-note@-3 {{in call to 'is_within_lifetime<int>(&arr[2])'}}
423 struct XStd {
424 consteval XStd() {
425 std::is_within_lifetime(this); // #XStd-read
427 } xstd;
428 // expected-error@-1 {{call to consteval function 'XStd::XStd' is not a constant expression}}
429 // expected-note@#XStd-read {{'std::is_within_lifetime' cannot be called with a pointer to an object whose lifetime has not yet begun}}
430 // expected-note@#XStd-read {{in call to 'is_within_lifetime<XStd>(&)'}}
431 // expected-note@-4 {{in call to 'XStd()'}}