brintos

brintos / llvm-project-archived public Read only

0
0
Text · 22.6 KiB · 2877d8d Raw
475 lines · cpp
1// RUN: %clang_cc1 --std=c++20 -fsyntax-only -verify -Wdangling-capture %s2 3#include "Inputs/lifetime-analysis.h"4 5// ****************************************************************************6// Capture an integer7// ****************************************************************************8namespace capture_int {9struct X {} x;10void captureInt(const int &i [[clang::lifetime_capture_by(x)]], X &x);11void captureRValInt(int &&i [[clang::lifetime_capture_by(x)]], X &x);12void noCaptureInt(int i [[clang::lifetime_capture_by(x)]], X &x);13 14void 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_int24 25// ****************************************************************************26// Capture std::string (gsl owner types)27// ****************************************************************************28namespace capture_string {29struct X {} x;30void captureString(const std::string &s [[clang::lifetime_capture_by(x)]], X &x);31void captureRValString(std::string &&s [[clang::lifetime_capture_by(x)]], X &x);32 33void 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_string41 42// ****************************************************************************43// Capture std::string_view (gsl pointer types)44// ****************************************************************************45namespace capture_string_view {46struct X {} x;47void captureStringView(std::string_view s [[clang::lifetime_capture_by(x)]], X &x);48void captureRValStringView(std::string_view &&sv [[clang::lifetime_capture_by(x)]], X &x);49void noCaptureStringView(std::string_view sv, X &x);50 51std::string_view getLifetimeBoundView(const std::string& s [[clang::lifetimebound]]);52std::string_view getNotLifetimeBoundView(const std::string& s);53const std::string& getLifetimeBoundString(const std::string &s [[clang::lifetimebound]]);54const std::string& getLifetimeBoundString(std::string_view sv [[clang::lifetimebound]]);55 56void 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_view87 88// ****************************************************************************89// Capture pointer (eg: std::string*)90// ****************************************************************************91const std::string* getLifetimeBoundPointer(const std::string &s [[clang::lifetimebound]]);92const std::string* getNotLifetimeBoundPointer(const std::string &s);93 94namespace capture_pointer {95struct X {} x;96void capturePointer(const std::string* sp [[clang::lifetime_capture_by(x)]], X &x);97void 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_pointer106 107// ****************************************************************************108// Arrays and initializer lists.109// ****************************************************************************110namespace init_lists {111struct X {} x;112void captureVector(const std::vector<int> &a [[clang::lifetime_capture_by(x)]], X &x);113void captureArray(int array [[clang::lifetime_capture_by(x)]] [2], X &x);114void captureInitList(std::initializer_list<int> abc [[clang::lifetime_capture_by(x)]], X &x);115 116 117std::initializer_list<int> getLifetimeBoundInitList(std::initializer_list<int> abc [[clang::lifetimebound]]);118 119void 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_lists130 131// ****************************************************************************132// Implicit object param 'this' is captured133// ****************************************************************************134namespace this_is_captured {135struct X {} x;136struct S {137  void capture(X &x) [[clang::lifetime_capture_by(x)]];138};139void 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_captured145 146namespace temporary_capturing_object {147struct S {148  void add(const int& x [[clang::lifetime_capture_by(this)]]);149};150 151void 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 its154  // 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_object159 160// ****************************************************************************161// Capture by Global and Unknown.162// ****************************************************************************163namespace capture_by_global_unknown {164void captureByGlobal(std::string_view s [[clang::lifetime_capture_by(global)]]);165void captureByUnknown(std::string_view s [[clang::lifetime_capture_by(unknown)]]);166 167std::string_view getLifetimeBoundView(const std::string& s [[clang::lifetimebound]]);168 169void 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_unknown185 186// ****************************************************************************187// Member functions: Capture by 'this'188// ****************************************************************************189namespace capture_by_this {190struct 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};194std::string_view getLifetimeBoundView(const std::string& s [[clang::lifetimebound]]);195std::string_view getNotLifetimeBoundView(const std::string& s);196const std::string& getLifetimeBoundString(const std::string &s [[clang::lifetimebound]]);197 198void 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_this207 208// ****************************************************************************209// Struct with field as a reference210// ****************************************************************************211namespace reference_field {212struct X {} x;213struct Foo {214  const int& b;215};216void captureField(Foo param [[clang::lifetime_capture_by(x)]], X &x);217void 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_field225 226// ****************************************************************************227// Capture default argument.228// ****************************************************************************229namespace default_arg {230struct X {} x;231void captureDefaultArg(X &x, std::string_view s [[clang::lifetime_capture_by(x)]] = std::string());232 233std::string_view getLifetimeBoundView(const std::string& s [[clang::lifetimebound]]);234 235void 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 type247// ****************************************************************************248namespace containers_no_distinction {249template<class T>250struct MySet {251  void insert(T&& t [[clang::lifetime_capture_by(this)]]);252  void insert(const T& t [[clang::lifetime_capture_by(this)]]);253};254void 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_distinction262 263// ****************************************************************************264// Container: Different for pointer-like and other element type.265// ****************************************************************************266namespace conatiners_with_different {267template<typename T> struct IsPointerLikeTypeImpl : std::false_type {};268template<> struct IsPointerLikeTypeImpl<std::string_view> : std::true_type {};269template<typename T> concept IsPointerLikeType = std::is_pointer<T>::value || IsPointerLikeTypeImpl<T>::value;270 271template<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 279std::string_view getLifetimeBoundView(const std::string& s [[clang::lifetimebound]]);280 281void 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 types300// ****************************************************************************301struct [[gsl::Pointer()]] MyStringView : public std::string_view {302  MyStringView();303  MyStringView(std::string_view&&);304  MyStringView(const MyStringView&);305  MyStringView(const std::string&);306};307template<> struct IsPointerLikeTypeImpl<MyStringView> : std::true_type {};308 309std::optional<std::string_view> getOptionalSV();310std::optional<std::string> getOptionalS();311std::optional<MyStringView> getOptionalMySV();312MyStringView getMySV();313 314class MyStringViewNotPointer : public std::string_view {};315std::optional<MyStringViewNotPointer> getOptionalMySVNotP();316MyStringViewNotPointer getMySVNotP();317 318std::string_view getLifetimeBoundView(const std::string& s [[clang::lifetimebound]]);319std::string_view getNotLifetimeBoundView(const std::string& s);320const std::string& getLifetimeBoundString(const std::string &s [[clang::lifetimebound]]);321const std::string& getLifetimeBoundString(std::string_view sv [[clang::lifetimebound]]);322 323void 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// ****************************************************************************343void 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_different355 356// ****************************************************************************357// Capture 'temporary' views358// ****************************************************************************359namespace temporary_views {360void capture1(std::string_view s [[clang::lifetime_capture_by(x)]], std::vector<std::string_view>& x);361 362// Intended to capture the "string_view" itself363void 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"365void capture3(const std::string_view& s [[clang::lifetime_capture_by(x)]], std::vector<std::string_view>& x);366 367void 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 owner374  // '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_views383 384// ****************************************************************************385// Inferring annotation for STL containers386// ****************************************************************************387namespace inferred_capture_by {388const std::string* getLifetimeBoundPointer(const std::string &s [[clang::lifetimebound]]);389const std::string* getNotLifetimeBoundPointer(const std::string &s);390 391std::string_view getLifetimeBoundView(const std::string& s [[clang::lifetimebound]]);392std::string_view getNotLifetimeBoundView(const std::string& s);393void 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 413namespace with_span {414// Templated view types.415template<typename T>416struct [[gsl::Pointer]] Span {417  Span(const std::vector<T> &V);418};419 420void 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_span427} // namespace inferred_capture_by428 429namespace on_constructor {430struct T {431  T(const int& t [[clang::lifetime_capture_by(this)]]);432};433struct T2 {434  T2(const int& t [[clang::lifetime_capture_by(x)]], int& x);435};436struct T3 {437  T3(const T& t [[clang::lifetime_capture_by(this)]]);438};439 440int foo(const T& t);441int bar(const T& t[[clang::lifetimebound]]);442 443void test() {444  auto x = foo(T(1)); // OK. no diagnosic445  T(1); // OK. no diagnostic446  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_constructor454 455namespace GH121391 {456 457struct Foo {};458 459template <typename T>460struct Container {461  const T& tt() [[clang::lifetimebound]];462};463template<typename T>464struct StatusOr {465   T* get() [[clang::lifetimebound]];466};467StatusOr<Container<const Foo*>> getContainer();468 469void test() {470  std::vector<const Foo*> vv;471  vv.push_back(getContainer().get()->tt()); // OK472}473 474} // namespace GH121391475