1 // RUN: %clang_cc1 -std=c++23 -verify %s
3 namespace usage_invalid
{
4 void void_return(int ¶m
[[clang::lifetimebound
]]); // expected-error {{'lifetimebound' attribute cannot be applied to a parameter of a function that returns void; did you mean 'lifetime_capture_by(X)'}}
6 int *not_class_member() [[clang::lifetimebound
]]; // expected-error {{non-member function has no implicit object parameter}}
8 A() [[clang::lifetimebound
]]; // expected-error {{cannot be applied to a constructor}}
9 ~A() [[clang::lifetimebound
]]; // expected-error {{cannot be applied to a destructor}}
10 static int *static_class_member() [[clang::lifetimebound
]]; // expected-error {{static member function has no implicit object parameter}}
11 int *explicit_object(this A
&) [[clang::lifetimebound
]]; // expected-error {{explicit object member function has no implicit object parameter}}
12 int not_function
[[clang::lifetimebound
]]; // expected-error {{only applies to parameters and implicit object parameters}}
13 int [[clang::lifetimebound
]] also_not_function
; // expected-error {{cannot be applied to types}}
14 void void_return_member() [[clang::lifetimebound
]]; // expected-error {{'lifetimebound' attribute cannot be applied to an implicit object parameter of a function that returns void; did you mean 'lifetime_capture_by(X)'}}
16 int *attr_with_param(int ¶m
[[clang::lifetimebound(42)]]); // expected-error {{takes no arguments}}
20 struct IntRef
{ int *target
; };
22 int &refparam(int ¶m
[[clang::lifetimebound
]]);
23 int &classparam(IntRef param
[[clang::lifetimebound
]]);
25 // Do not diagnose non-void return types; they can still be lifetime-bound.
26 long long ptrintcast(int ¶m
[[clang::lifetimebound
]]) {
27 return (long long)¶m
;
30 int &intptrcast(long long param
[[clang::lifetimebound
]]) {
34 template <class T
, class R
= void> R
dependent_void(const T
& t
[[clang::lifetimebound
]]);
35 void dependent_void_instantiation() {
36 dependent_void
<int>(1); // OK: Returns void.
37 int x
= dependent_void
<int, int>(1); // expected-warning {{temporary whose address is used as value of local variable 'x' will be destroyed at the end of the full-expression}}
38 dependent_void
<int, int>(1); // OK: Returns an unused value.
44 int *class_member() [[clang::lifetimebound
]];
45 operator int*() [[clang::lifetimebound
]];
48 int *p
= A().class_member(); // expected-warning {{temporary whose address is used as value of local variable 'p' will be destroyed at the end of the full-expression}}
49 int *q
= A(); // expected-warning {{temporary whose address is used as value of local variable 'q' will be destroyed at the end of the full-expression}}
50 int *r
= A(1); // expected-warning {{temporary whose address is used as value of local variable 'r' will be destroyed at the end of the full-expression}}
52 void test_assignment() {
53 p
= A().class_member(); // expected-warning {{object backing the pointer p will be destroyed at the end of the full-expression}}
54 p
= {A().class_member()}; // expected-warning {{object backing the pointer p will be destroyed at the end of the full-expression}}
55 q
= A(); // expected-warning {{object backing the pointer q will be destroyed at the end of the full-expression}}
56 r
= A(1); // expected-warning {{object backing the pointer r will be destroyed at the end of the full-expression}}
70 FieldCheck(const int& a
): p(a
){}
71 Pair
& getR() [[clang::lifetimebound
]] { return p
; }
72 Pair
* getP() [[clang::lifetimebound
]] { return &p
; }
73 Pair
* getNoLB() { return &p
; }
75 void test_field_access() {
77 const int& a
= FieldCheck
{x
}.getR().a
;
78 const int& b
= FieldCheck
{x
}.getP()->b
; // expected-warning {{temporary bound to local reference 'b' will be destroyed at the end of the full-expression}}
79 const int& c
= FieldCheck
{x
}.getP()->c
.a
; // expected-warning {{temporary bound to local reference 'c' will be destroyed at the end of the full-expression}}
80 const int& d
= FieldCheck
{x
}.getNoLB()->c
.a
;
81 const int* e
= FieldCheck
{x
}.getR().d
;
86 using size_t = __SIZE_TYPE__
;
90 basic_string(const T
*);
92 char &operator[](size_t) const [[clang::lifetimebound
]];
94 using string
= basic_string
<char>;
95 string
operator""s(const char *, size_t); // expected-warning {{user-defined literal suffixes not starting with '_' are reserved}}
98 struct basic_string_view
{
100 basic_string_view(const T
*p
);
101 basic_string_view(const string
&s
[[clang::lifetimebound
]]);
103 using string_view
= basic_string_view
<char>;
104 string_view
operator""sv(const char *, size_t); // expected-warning {{user-defined literal suffixes not starting with '_' are reserved}}
111 template<typename K
, typename V
> struct map
{};
114 using std::operator""s
;
115 using std::operator""sv
;
117 namespace default_args
{
118 using IntArray
= int[];
119 const int *defaultparam1(const int &def1
[[clang::lifetimebound
]] = 0); // #def1
120 const int &defaultparam_array([[clang::lifetimebound
]] const int *p
= IntArray
{1, 2, 3}); // #def2
122 A(const char *, const int &def3
[[clang::lifetimebound
]] = 0); // #def3
124 const int &defaultparam2(const int &def4
[[clang::lifetimebound
]] = 0); // #def4
125 const int &defaultparam3(const int &def5
[[clang::lifetimebound
]] = defaultparam2(), const int &def6
[[clang::lifetimebound
]] = 0); // #def5 #def6
126 std::string_view
defaultparam4(std::string_view s
[[clang::lifetimebound
]] = std::string()); // #def7
128 const int *test_default_args() {
129 const int *c
= defaultparam1(); // expected-warning {{temporary whose address is used as value of local variable 'c' will be destroyed at the end of the full-expression}} expected-note@#def1 {{initializing parameter 'def1' with default argument}}
130 A a
= A(""); // expected-warning {{temporary whose address is used as value of local variable 'a' will be destroyed at the end of the full-expression}} expected-note@#def3 {{initializing parameter 'def3' with default argument}}
131 const int &s
= defaultparam2(); // expected-warning {{temporary bound to local reference 's' will be destroyed at the end of the full-expression}} expected-note@#def4 {{initializing parameter 'def4' with default argument}}
132 const int &t
= defaultparam3(); // expected-warning {{temporary bound to local reference 't' will be destroyed at the end of the full-expression}} expected-note@#def4 {{initializing parameter 'def4' with default argument}} expected-note@#def5 {{initializing parameter 'def5' with default argument}} expected-warning {{temporary bound to local reference 't' will be destroyed at the end of the full-expression}} expected-note@#def6 {{initializing parameter 'def6' with default argument}}
133 const int &u
= defaultparam_array(); // expected-warning {{temporary bound to local reference 'u' will be destroyed at the end of the full-expression}} expected-note@#def2 {{initializing parameter 'p' with default argument}}
135 const int &v
= defaultparam2(local
); // no warning
136 const int &w
= defaultparam2(1); // expected-warning {{temporary bound to local reference 'w' will be destroyed at the end of the full-expression}}
138 return &defaultparam2(); // expected-warning {{returning address of local temporary object}}
141 return &defaultparam2(0); // expected-warning {{returning address of local temporary object}} expected-note@#def4 {{initializing parameter 'def4' with default argument}}
143 std::string_view sv
= defaultparam4(); // expected-warning {{temporary whose address is used as value of local variable 'sv' will be destroyed at the end of the full-expression}} expected-note@#def7 {{initializing parameter 's' with default argument}}
146 } // namespace default_args
148 namespace p0936r0_examples
{
149 std::string_view s
= "foo"s
; // expected-warning {{temporary}}
151 std::string
operator+(std::string_view s1
, std::string_view s2
);
153 std::string_view sv
= "hi";
154 std::string_view sv2
= sv
+ sv
; // expected-warning {{temporary}}
155 sv2
= sv
+ sv
; // expected-warning {{object backing the pointer}}
158 struct X
{ int a
, b
; };
159 const int &f(const X
&x
[[clang::lifetimebound
]]) { return x
.a
; }
160 const int &r
= f(X()); // expected-warning {{temporary}}
162 char &c
= std::string("hello my pretty long strong")[0]; // expected-warning {{temporary}}
164 struct reversed_range
{
170 template <typename R
> reversed_range
reversed(R
&&r
[[clang::lifetimebound
]]) {
171 return reversed_range
{r
.data(), r
.size()};
174 std::vector
make_vector();
175 void use_reversed_range() {
176 // FIXME: Don't expose the name of the internal range variable.
177 for (auto x
: reversed(make_vector())) {} // expected-warning {{temporary implicitly bound to local reference will be destroyed at the end of the full-expression}}
180 template <typename K
, typename V
>
181 const V
&findOrDefault(const std::map
<K
, V
> &m
[[clang::lifetimebound
]],
183 const V
&defvalue
[[clang::lifetimebound
]]);
185 // FIXME: Maybe weaken the wording here: "local reference 'v' could bind to temporary that will be destroyed at end of full-expression"?
186 std::map
<std::string
, std::string
> m
;
187 const std::string
&v
= findOrDefault(m
, "foo"s
, "bar"s
); // expected-warning {{temporary bound to local reference 'v'}}
190 // definitions for std::move, std::forward et al.
192 inline namespace foo
{
194 template <class T
> struct remove_reference
{
197 template <class T
> struct remove_reference
<T
&> {
200 template <class T
> struct remove_reference
<T
&&> {
204 template <class T
> constexpr typename remove_reference
<T
>::type
&&move(T
&&t
) {
205 return static_cast<typename remove_reference
<T
>::type
>(t
);
209 constexpr T
&&forward(typename remove_reference
<T
>::type
&t
) {
210 return static_cast<T
&&>(t
);
214 constexpr T
&&forward(typename remove_reference
<T
>::type
&&t
) {
215 return static_cast<T
&&>(t
);
218 template <class T
> constexpr const T
&as_const(T
&x
) { return x
; }
220 template <class T
, bool RValueRef
> struct PickRef
{
221 using type
= typename remove_reference
<T
>::type
&;
223 template <class T
> struct PickRef
<T
, true> {
224 using type
= typename remove_reference
<T
>::type
&&;
227 template <class T
> struct is_lvalue_reference
{
228 static constexpr bool value
= false;
231 template <class T
> struct is_lvalue_reference
<T
&> {
232 static constexpr bool value
= true;
235 template <class T
> struct is_const
{
236 static constexpr bool value
= false;
239 template <class T
> struct is_const
<const T
> {
240 static constexpr bool value
= true;
243 template <bool B
, class T
, class F
> struct conditional
{
247 template <class T
, class F
> struct conditional
<false, T
, F
> {
251 template <class U
, class T
>
252 using CopyConst
= typename conditional
<is_const
<remove_reference
<U
>>::value
,
255 template <class U
, class T
>
257 typename conditional
<is_lvalue_reference
<U
&&>::value
,
258 typename remove_reference
<T
>::type
&,
259 typename remove_reference
<T
>::type
&&>::type
;
261 template <class U
, class T
>
262 using ForwardLikeRetType
= OverrideRef
<U
&&, CopyConst
<U
, T
>>;
265 constexpr auto forward_like(auto &&t
) -> ForwardLikeRetType
<U
, decltype(t
)> {
266 return static_cast<ForwardLikeRetType
<U
, decltype(t
)>>(t
);
270 auto move_if_noexcept(T
&t
) ->
271 typename PickRef
<T
, noexcept(T(static_cast<T
&&>(t
)))>::type
{
273 typename PickRef
<T
, noexcept(T(static_cast<T
&&>(t
)))>::type
>(t
);
276 template <class T
> T
*addressof(T
&arg
) {
277 return reinterpret_cast<T
*>(
278 &const_cast<char &>(reinterpret_cast<const volatile char &>(arg
)));
281 template <class T
> struct span
{
282 template<size_t _ArrayExtent
>
283 span(const T (&__arr
)[_ArrayExtent
]) noexcept
;
289 namespace move_forward_et_al_examples
{
291 S
&self() [[clang::lifetimebound
]] { return *this; }
294 S
&&Move
= std::move(S
{}); // expected-warning {{temporary bound to local reference 'Move' will be destroyed at the end of the full-expression}}
295 S MoveOk
= std::move(S
{});
297 S
&&Forward
= std::forward
<S
&&>(S
{}); // expected-warning {{temporary bound to local reference 'Forward' will be destroyed at the end of the full-expression}}
298 S ForwardOk
= std::forward
<S
&&>(S
{});
300 S
&&ForwardLike
= std::forward_like
<int&&>(S
{}); // expected-warning {{temporary bound to local reference 'ForwardLike' will be destroyed at the end of the full-expression}}
301 S ForwardLikeOk
= std::forward_like
<int&&>(S
{});
303 const S
&Const
= std::as_const(S
{}.self()); // expected-warning {{temporary bound to local reference 'Const' will be destroyed at the end of the full-expression}}
304 const S ConstOk
= std::as_const(S
{}.self());
306 S
&&MoveIfNoExcept
= std::move_if_noexcept(S
{}.self()); // expected-warning {{temporary bound to local reference 'MoveIfNoExcept' will be destroyed at the end of the full-expression}}
307 S MoveIfNoExceptOk
= std::move_if_noexcept(S
{}.self());
309 S
*AddressOf
= std::addressof(S
{}.self()); // expected-warning {{temporary whose address is used as value of local variable 'AddressOf' will be destroyed at the end of the full-expression}}
311 S
*AddressOfOk
= std::addressof(X
);
312 } // namespace move_forward_et_al_examples
314 namespace ctor_cases
{
315 std::basic_string_view
<char> test1() {
317 return abc
; // expected-warning {{address of stack memory associated with local variable}}
320 std::span
<int> test2() {
322 return abc
; // expected-warning {{address of stack memory associated with local variable}}
324 } // namespace ctor_cases
327 class [[gsl::Owner
]] Foo
{};
328 class [[gsl::Pointer
]] FooView
{};
330 class NonAnnotatedFoo
{};
331 class NonAnnotatedFooView
{};
333 template <typename T
>
335 template <typename U
= T
>
336 StatusOr
& operator=(U
&& v
[[clang::lifetimebound
]]);
339 void test(StatusOr
<FooView
> foo1
, StatusOr
<NonAnnotatedFooView
> foo2
) {
340 foo1
= Foo(); // expected-warning {{object backing foo1 will be destroyed at the end}}
341 // This warning is triggered by the lifetimebound annotation, regardless of whether the class type is annotated with GSL.
342 foo2
= NonAnnotatedFoo(); // expected-warning {{object backing foo2 will be destroyed at the end}}
344 } // namespace GH106372