1 // RUN: %clang_cc1 --std=c++20 -fsyntax-only -verify -Wdangling-capture %s 2 3 #include "Inputs/lifetime-analysis.h" 4 5 // **************************************************************************** 6 // Capture an integer 7 // **************************************************************************** 8 namespace capture_int { 9 struct X {} x; 10 void captureInt(const int &i [[clang::lifetime_capture_by(x)]], X &x); 11 void captureRValInt(int &&i [[clang::lifetime_capture_by(x)]], X &x); 12 void noCaptureInt(int i [[clang::lifetime_capture_by(x)]], X &x); 13 14 void use() { 15 int local; 16 captureInt(1, // expected-warning {{object whose reference is captured by 'x' will be destroyed at the end of the full-expression}} 17 x); 18 captureRValInt(1, x); // expected-warning {{object whose reference is captured by 'x' will be destroyed at the end of the full-expression}} 19 captureInt(local, x); 20 noCaptureInt(1, x); 21 noCaptureInt(local, x); 22 } 23 } // namespace capture_int 24 25 // **************************************************************************** 26 // Capture std::string (gsl owner types) 27 // **************************************************************************** 28 namespace capture_string { 29 struct X {} x; 30 void captureString(const std::string &s [[clang::lifetime_capture_by(x)]], X &x); 31 void captureRValString(std::string &&s [[clang::lifetime_capture_by(x)]], X &x); 32 33 void use() { 34 std::string local_string; 35 captureString(std::string(), x); // expected-warning {{object whose reference is captured by 'x' will be destroyed at the end of the full-expression}} 36 captureString(local_string, x); 37 captureRValString(std::move(local_string), x); 38 captureRValString(std::string(), x); // expected-warning {{object whose reference is captured by 'x' will be destroyed at the end of the full-expression}} 39 } 40 } // namespace capture_string 41 42 // **************************************************************************** 43 // Capture std::string_view (gsl pointer types) 44 // **************************************************************************** 45 namespace capture_string_view { 46 struct X {} x; 47 void captureStringView(std::string_view s [[clang::lifetime_capture_by(x)]], X &x); 48 void captureRValStringView(std::string_view &&sv [[clang::lifetime_capture_by(x)]], X &x); 49 void noCaptureStringView(std::string_view sv, X &x); 50 51 std::string_view getLifetimeBoundView(const std::string& s [[clang::lifetimebound]]); 52 std::string_view getNotLifetimeBoundView(const std::string& s); 53 const std::string& getLifetimeBoundString(const std::string &s [[clang::lifetimebound]]); 54 const std::string& getLifetimeBoundString(std::string_view sv [[clang::lifetimebound]]); 55 56 void use() { 57 std::string_view local_string_view; 58 std::string local_string; 59 captureStringView(local_string_view, x); 60 captureStringView(std::string(), // expected-warning {{object whose reference is captured by 'x' will be destroyed at the end of the full-expression}} 61 x); 62 63 captureStringView(getLifetimeBoundView(local_string), x); 64 captureStringView(getNotLifetimeBoundView(std::string()), x); 65 captureRValStringView(std::move(local_string_view), x); 66 captureRValStringView(std::string(), x); // expected-warning {{object whose reference is captured by 'x' will be destroyed at the end of the full-expression}} 67 captureRValStringView(std::string_view{"abcd"}, x); 68 69 noCaptureStringView(local_string_view, x); 70 noCaptureStringView(std::string(), x); 71 72 // With lifetimebound functions. 73 captureStringView(getLifetimeBoundView( 74 std::string() // expected-warning {{object whose reference is captured by 'x' will be destroyed at the end of the full-expression}} 75 ), x); 76 captureRValStringView(getLifetimeBoundView(local_string), x); 77 captureRValStringView(getLifetimeBoundView(std::string()), x); // expected-warning {{object whose reference is captured by 'x' will be destroyed at the end of the full-expression}} 78 captureRValStringView(getNotLifetimeBoundView(std::string()), x); 79 noCaptureStringView(getLifetimeBoundView(std::string()), x); 80 captureStringView(getLifetimeBoundString(std::string()), x); // expected-warning {{object whose reference is captured by 'x' will be destroyed at the end of the full-expression}} 81 captureStringView(getLifetimeBoundString(getLifetimeBoundView(std::string())), x); // expected-warning {{object whose reference is captured by 'x' will be destroyed at the end of the full-expression}} 82 captureStringView(getLifetimeBoundString(getLifetimeBoundString( 83 std::string() // expected-warning {{object whose reference is captured by 'x' will be destroyed at the end of the full-expression}} 84 )), x); 85 } 86 } // namespace capture_string_view 87 88 // **************************************************************************** 89 // Capture pointer (eg: std::string*) 90 // **************************************************************************** 91 const std::string* getLifetimeBoundPointer(const std::string &s [[clang::lifetimebound]]); 92 const std::string* getNotLifetimeBoundPointer(const std::string &s); 93 94 namespace capture_pointer { 95 struct X {} x; 96 void capturePointer(const std::string* sp [[clang::lifetime_capture_by(x)]], X &x); 97 void use() { 98 capturePointer(getLifetimeBoundPointer(std::string()), x); // expected-warning {{object whose reference is captured by 'x' will be destroyed at the end of the full-expression}} 99 capturePointer(getLifetimeBoundPointer(*getLifetimeBoundPointer( 100 std::string() // expected-warning {{object whose reference is captured by 'x' will be destroyed at the end of the full-expression}} 101 )), x); 102 capturePointer(getNotLifetimeBoundPointer(std::string()), x); 103 104 } 105 } // namespace capture_pointer 106 107 // **************************************************************************** 108 // Arrays and initializer lists. 109 // **************************************************************************** 110 namespace init_lists { 111 struct X {} x; 112 void captureVector(const std::vector<int> &a [[clang::lifetime_capture_by(x)]], X &x); 113 void captureArray(int array [[clang::lifetime_capture_by(x)]] [2], X &x); 114 void captureInitList(std::initializer_list<int> abc [[clang::lifetime_capture_by(x)]], X &x); 115 116 117 std::initializer_list<int> getLifetimeBoundInitList(std::initializer_list<int> abc [[clang::lifetimebound]]); 118 119 void use() { 120 captureVector({1, 2, 3}, x); // expected-warning {{object whose reference is captured by 'x' will be destroyed at the end of the full-expression}} 121 captureVector(std::vector<int>{}, x); // expected-warning {{object whose reference is captured by 'x' will be destroyed at the end of the full-expression}} 122 std::vector<int> local_vector; 123 captureVector(local_vector, x); 124 int local_array[2]; 125 captureArray(local_array, x); 126 captureInitList({1, 2}, x); // expected-warning {{object whose reference is captured by 'x' will be destroyed at the end of the full-expression}} 127 captureInitList(getLifetimeBoundInitList({1, 2}), x); // expected-warning {{object whose reference is captured by 'x' will be destroyed at the end of the full-expression}} 128 } 129 } // namespace init_lists 130 131 // **************************************************************************** 132 // Implicit object param 'this' is captured 133 // **************************************************************************** 134 namespace this_is_captured { 135 struct X {} x; 136 struct S { 137 void capture(X &x) [[clang::lifetime_capture_by(x)]]; 138 }; 139 void use() { 140 S{}.capture(x); // expected-warning {{object whose reference is captured by 'x' will be destroyed at the end of the full-expression}} 141 S s; 142 s.capture(x); 143 } 144 } // namespace this_is_captured 145 146 namespace temporary_capturing_object { 147 struct S { 148 void add(const int& x [[clang::lifetime_capture_by(this)]]); 149 }; 150 151 void test() { 152 // We still give an warning even the capturing object is a temoprary. 153 // It is possible that the capturing object uses the captured object in its 154 // destructor. 155 S().add(1); // expected-warning {{object whose reference is captured}} 156 S{}.add(1); // expected-warning {{object whose reference is captured}} 157 } 158 } // namespace ignore_temporary_class_object 159 160 // **************************************************************************** 161 // Capture by Global and Unknown. 162 // **************************************************************************** 163 namespace capture_by_global_unknown { 164 void captureByGlobal(std::string_view s [[clang::lifetime_capture_by(global)]]); 165 void captureByUnknown(std::string_view s [[clang::lifetime_capture_by(unknown)]]); 166 167 std::string_view getLifetimeBoundView(const std::string& s [[clang::lifetimebound]]); 168 169 void use() { 170 std::string_view local_string_view; 171 std::string local_string; 172 // capture by global. 173 captureByGlobal(std::string()); // expected-warning {{object whose reference is captured will be destroyed at the end of the full-expression}} 174 captureByGlobal(getLifetimeBoundView(std::string())); // expected-warning {{object whose reference is captured will be destroyed at the end of the full-expression}} 175 captureByGlobal(local_string); 176 captureByGlobal(local_string_view); 177 178 // capture by unknown. 179 captureByUnknown(std::string()); // expected-warning {{object whose reference is captured will be destroyed at the end of the full-expression}} 180 captureByUnknown(getLifetimeBoundView(std::string())); // expected-warning {{object whose reference is captured will be destroyed at the end of the full-expression}} 181 captureByUnknown(local_string); 182 captureByUnknown(local_string_view); 183 } 184 } // namespace capture_by_global_unknown 185 186 // **************************************************************************** 187 // Member functions: Capture by 'this' 188 // **************************************************************************** 189 namespace capture_by_this { 190 struct S { 191 void captureInt(const int& x [[clang::lifetime_capture_by(this)]]); 192 void captureView(std::string_view sv [[clang::lifetime_capture_by(this)]]); 193 }; 194 std::string_view getLifetimeBoundView(const std::string& s [[clang::lifetimebound]]); 195 std::string_view getNotLifetimeBoundView(const std::string& s); 196 const std::string& getLifetimeBoundString(const std::string &s [[clang::lifetimebound]]); 197 198 void use() { 199 S s; 200 s.captureInt(1); // expected-warning {{object whose reference is captured by 's' will be destroyed at the end of the full-expression}} 201 s.captureView(std::string()); // expected-warning {{object whose reference is captured by 's' will be destroyed at the end of the full-expression}} 202 s.captureView(getLifetimeBoundView(std::string())); // expected-warning {{object whose reference is captured by 's' will be destroyed at the end of the full-expression}} 203 s.captureView(getLifetimeBoundString(std::string())); // expected-warning {{object whose reference is captured by 's' will be destroyed at the end of the full-expression}} 204 s.captureView(getNotLifetimeBoundView(std::string())); 205 } 206 } // namespace capture_by_this 207 208 // **************************************************************************** 209 // Struct with field as a reference 210 // **************************************************************************** 211 namespace reference_field { 212 struct X {} x; 213 struct Foo { 214 const int& b; 215 }; 216 void captureField(Foo param [[clang::lifetime_capture_by(x)]], X &x); 217 void use() { 218 captureField(Foo{ 219 1 // expected-warning {{object whose reference is captured by 'x' will be destroyed at the end of the full-expression}} 220 }, x); 221 int local; 222 captureField(Foo{local}, x); 223 } 224 } // namespace reference_field 225 226 // **************************************************************************** 227 // Capture default argument. 228 // **************************************************************************** 229 namespace default_arg { 230 struct X {} x; 231 void captureDefaultArg(X &x, std::string_view s [[clang::lifetime_capture_by(x)]] = std::string()); 232 233 std::string_view getLifetimeBoundView(const std::string& s [[clang::lifetimebound]]); 234 235 void useCaptureDefaultArg() { 236 X x; 237 captureDefaultArg(x); // FIXME: Diagnose temporary default arg. 238 captureDefaultArg(x, std::string("temp")); // expected-warning {{object whose reference is captured by 'x' will be destroyed at the end of the full-expression}} 239 captureDefaultArg(x, getLifetimeBoundView(std::string())); // expected-warning {{object whose reference is captured by 'x' will be destroyed at the end of the full-expression}} 240 std::string local; 241 captureDefaultArg(x, local); 242 } 243 } // namespace default_arg 244 245 // **************************************************************************** 246 // Container: *No* distinction between pointer-like and other element type 247 // **************************************************************************** 248 namespace containers_no_distinction { 249 template<class T> 250 struct MySet { 251 void insert(T&& t [[clang::lifetime_capture_by(this)]]); 252 void insert(const T& t [[clang::lifetime_capture_by(this)]]); 253 }; 254 void user_defined_containers() { 255 MySet<int> set_of_int; 256 set_of_int.insert(1); // expected-warning {{object whose reference is captured by 'set_of_int' will be destroyed at the end of the full-expression}} 257 MySet<std::string_view> set_of_sv; 258 set_of_sv.insert(std::string()); // expected-warning {{object whose reference is captured by 'set_of_sv' will be destroyed at the end of the full-expression}} 259 set_of_sv.insert(std::string_view()); 260 } 261 } // namespace containers_no_distinction 262 263 // **************************************************************************** 264 // Container: Different for pointer-like and other element type. 265 // **************************************************************************** 266 namespace conatiners_with_different { 267 template<typename T> struct IsPointerLikeTypeImpl : std::false_type {}; 268 template<> struct IsPointerLikeTypeImpl<std::string_view> : std::true_type {}; 269 template<typename T> concept IsPointerLikeType = std::is_pointer<T>::value || IsPointerLikeTypeImpl<T>::value; 270 271 template<class T> struct MyVector { 272 void push_back(T&& t [[clang::lifetime_capture_by(this)]]) requires IsPointerLikeType<T>; 273 void push_back(const T& t [[clang::lifetime_capture_by(this)]]) requires IsPointerLikeType<T>; 274 275 void push_back(T&& t) requires (!IsPointerLikeType<T>); 276 void push_back(const T& t) requires (!IsPointerLikeType<T>); 277 }; 278 279 std::string_view getLifetimeBoundView(const std::string& s [[clang::lifetimebound]]); 280 281 void use_container() { 282 std::string local; 283 284 MyVector<std::string> vector_of_string; 285 vector_of_string.push_back(std::string()); // Ok. 286 287 MyVector<std::string_view> vector_of_view; 288 vector_of_view.push_back(std::string()); // expected-warning {{object whose reference is captured by 'vector_of_view' will be destroyed at the end of the full-expression}} 289 vector_of_view.push_back(getLifetimeBoundView(std::string())); // expected-warning {{object whose reference is captured by 'vector_of_view' will be destroyed at the end of the full-expression}} 290 291 MyVector<const std::string*> vector_of_pointer; 292 vector_of_pointer.push_back(getLifetimeBoundPointer(std::string())); // expected-warning {{object whose reference is captured by 'vector_of_pointer' will be destroyed at the end of the full-expression}} 293 vector_of_pointer.push_back(getLifetimeBoundPointer(*getLifetimeBoundPointer(std::string()))); // expected-warning {{object whose reference is captured by 'vector_of_pointer' will be destroyed at the end of the full-expression}} 294 vector_of_pointer.push_back(getLifetimeBoundPointer(local)); 295 vector_of_pointer.push_back(getNotLifetimeBoundPointer(std::string())); 296 } 297 298 // **************************************************************************** 299 // Container: For user defined view types 300 // **************************************************************************** 301 struct [[gsl::Pointer()]] MyStringView : public std::string_view { 302 MyStringView(); 303 MyStringView(std::string_view&&); 304 MyStringView(const MyStringView&); 305 MyStringView(const std::string&); 306 }; 307 template<> struct IsPointerLikeTypeImpl<MyStringView> : std::true_type {}; 308 309 std::optional<std::string_view> getOptionalSV(); 310 std::optional<std::string> getOptionalS(); 311 std::optional<MyStringView> getOptionalMySV(); 312 MyStringView getMySV(); 313 314 class MyStringViewNotPointer : public std::string_view {}; 315 std::optional<MyStringViewNotPointer> getOptionalMySVNotP(); 316 MyStringViewNotPointer getMySVNotP(); 317 318 std::string_view getLifetimeBoundView(const std::string& s [[clang::lifetimebound]]); 319 std::string_view getNotLifetimeBoundView(const std::string& s); 320 const std::string& getLifetimeBoundString(const std::string &s [[clang::lifetimebound]]); 321 const std::string& getLifetimeBoundString(std::string_view sv [[clang::lifetimebound]]); 322 323 void use_my_view() { 324 std::string local; 325 MyVector<MyStringView> vector_of_my_view; 326 vector_of_my_view.push_back(getMySV()); 327 vector_of_my_view.push_back(MyStringView{}); 328 vector_of_my_view.push_back(std::string_view{}); 329 vector_of_my_view.push_back(std::string{}); // expected-warning {{object whose reference is captured by 'vector_of_my_view' will be destroyed at the end of the full-expression}} 330 vector_of_my_view.push_back(getLifetimeBoundView(std::string{})); // expected-warning {{object whose reference is captured by 'vector_of_my_view' will be destroyed at the end of the full-expression}} 331 vector_of_my_view.push_back(getLifetimeBoundString(getLifetimeBoundView(std::string{}))); // expected-warning {{object whose reference is captured by 'vector_of_my_view' will be destroyed at the end of the full-expression}} 332 vector_of_my_view.push_back(getNotLifetimeBoundView(getLifetimeBoundString(getLifetimeBoundView(std::string{})))); 333 334 // Use with container of other view types. 335 MyVector<std::string_view> vector_of_view; 336 vector_of_view.push_back(getMySV()); 337 vector_of_view.push_back(getMySVNotP()); 338 } 339 340 // **************************************************************************** 341 // Container: Use with std::optional<view> (owner<pointer> types) 342 // **************************************************************************** 343 void use_with_optional_view() { 344 MyVector<std::string_view> vector_of_view; 345 346 std::optional<std::string_view> optional_of_view; 347 vector_of_view.push_back(optional_of_view.value()); 348 vector_of_view.push_back(getOptionalS().value()); // expected-warning {{object whose reference is captured by 'vector_of_view' will be destroyed at the end of the full-expression}} 349 350 vector_of_view.push_back(getOptionalSV().value()); 351 vector_of_view.push_back(getOptionalMySV().value()); 352 vector_of_view.push_back(getOptionalMySVNotP().value()); 353 } 354 } // namespace conatiners_with_different 355 356 // **************************************************************************** 357 // Capture 'temporary' views 358 // **************************************************************************** 359 namespace temporary_views { 360 void capture1(std::string_view s [[clang::lifetime_capture_by(x)]], std::vector<std::string_view>& x); 361 362 // Intended to capture the "string_view" itself 363 void capture2(const std::string_view& s [[clang::lifetime_capture_by(x)]], std::vector<std::string_view*>& x); 364 // Intended to capture the pointee of the "string_view" 365 void capture3(const std::string_view& s [[clang::lifetime_capture_by(x)]], std::vector<std::string_view>& x); 366 367 void use() { 368 std::vector<std::string_view> x1; 369 capture1(std::string(), x1); // expected-warning {{object whose reference is captured by 'x1' will be destroyed at the end of the full-expression}} 370 capture1(std::string_view(), x1); 371 372 std::vector<std::string_view*> x2; 373 // Clang considers 'const std::string_view&' to refer to the owner 374 // 'std::string' and not 'std::string_view'. Therefore no diagnostic here. 375 capture2(std::string_view(), x2); 376 capture2(std::string(), x2); // expected-warning {{object whose reference is captured by 'x2' will be destroyed at the end of the full-expression}} 377 378 std::vector<std::string_view> x3; 379 capture3(std::string_view(), x3); 380 capture3(std::string(), x3); // expected-warning {{object whose reference is captured by 'x3' will be destroyed at the end of the full-expression}} 381 } 382 } // namespace temporary_views 383 384 // **************************************************************************** 385 // Inferring annotation for STL containers 386 // **************************************************************************** 387 namespace inferred_capture_by { 388 const std::string* getLifetimeBoundPointer(const std::string &s [[clang::lifetimebound]]); 389 const std::string* getNotLifetimeBoundPointer(const std::string &s); 390 391 std::string_view getLifetimeBoundView(const std::string& s [[clang::lifetimebound]]); 392 std::string_view getNotLifetimeBoundView(const std::string& s); 393 void use() { 394 std::string local; 395 std::vector<std::string_view> views; 396 views.push_back(std::string()); // expected-warning {{object whose reference is captured by 'views' will be destroyed at the end of the full-expression}} 397 views.insert(views.begin(), 398 std::string()); // expected-warning {{object whose reference is captured by 'views' will be destroyed at the end of the full-expression}} 399 views.push_back(getLifetimeBoundView(std::string())); // expected-warning {{object whose reference is captured by 'views' will be destroyed at the end of the full-expression}} 400 views.push_back(getNotLifetimeBoundView(std::string())); 401 views.push_back(local); 402 views.insert(views.end(), local); 403 404 std::vector<std::string> strings; 405 strings.push_back(std::string()); 406 strings.insert(strings.begin(), std::string()); 407 408 std::vector<const std::string*> pointers; 409 pointers.push_back(getLifetimeBoundPointer(std::string())); 410 pointers.push_back(&local); 411 } 412 413 namespace with_span { 414 // Templated view types. 415 template<typename T> 416 struct [[gsl::Pointer]] Span { 417 Span(const std::vector<T> &V); 418 }; 419 420 void use() { 421 std::vector<Span<int>> spans; 422 spans.push_back(std::vector<int>{1, 2, 3}); // expected-warning {{object whose reference is captured by 'spans' will be destroyed at the end of the full-expression}} 423 std::vector<int> local; 424 spans.push_back(local); 425 } 426 } // namespace with_span 427 } // namespace inferred_capture_by 428 429 namespace on_constructor { 430 struct T { 431 T(const int& t [[clang::lifetime_capture_by(this)]]); 432 }; 433 struct T2 { 434 T2(const int& t [[clang::lifetime_capture_by(x)]], int& x); 435 }; 436 struct T3 { 437 T3(const T& t [[clang::lifetime_capture_by(this)]]); 438 }; 439 440 int foo(const T& t); 441 int bar(const T& t[[clang::lifetimebound]]); 442 443 void test() { 444 auto x = foo(T(1)); // OK. no diagnosic 445 T(1); // OK. no diagnostic 446 T t(1); // expected-warning {{temporary whose address is used}} 447 auto y = bar(T(1)); // expected-warning {{temporary whose address is used}} 448 T3 t3(T(1)); // expected-warning {{temporary whose address is used}} 449 450 int a; 451 T2(1, a); // expected-warning {{object whose reference is captured by}} 452 } 453 } // namespace on_constructor 454 455 namespace GH121391 { 456 457 struct Foo {}; 458 459 template <typename T> 460 struct Container { 461 const T& tt() [[clang::lifetimebound]]; 462 }; 463 template<typename T> 464 struct StatusOr { 465 T* get() [[clang::lifetimebound]]; 466 }; 467 StatusOr<Container<const Foo*>> getContainer(); 468 469 void test() { 470 std::vector<const Foo*> vv; 471 vv.push_back(getContainer().get()->tt()); // OK 472 } 473 474 } // namespace GH121391 475