================ @@ -0,0 +1,233 @@ +// RUN: %clang_cc1 --std=c++20 -fsyntax-only -Wdangling -Wdangling-field -Wreturn-stack-address -verify %s + +#include "Inputs/lifetime-analysis.h" + +struct X { + const int *x; + void captureInt(const int& x [[clang::lifetime_capture_by(this)]]) { this->x = &x; } + void captureSV(std::string_view sv [[clang::lifetime_capture_by(this)]]); +}; +/////////////////////////// +// Detect dangling cases. +/////////////////////////// +void captureInt(const int &i [[clang::lifetime_capture_by(x)]], X &x); +void captureRValInt(int &&i [[clang::lifetime_capture_by(x)]], X &x); +void noCaptureInt(int i [[clang::lifetime_capture_by(x)]], X &x); + +std::string_view substr(const std::string& s [[clang::lifetimebound]]); +std::string_view strcopy(const std::string& s); + +void captureStringView(std::string_view s [[clang::lifetime_capture_by(x)]], X &x); +void captureRValStringView(std::string_view &&sv [[clang::lifetime_capture_by(x)]], X &x); +void noCaptureStringView(std::string_view sv, X &x); +void captureString(const std::string &s [[clang::lifetime_capture_by(x)]], X &x); +void captureRValString(std::string &&s [[clang::lifetime_capture_by(x)]], X &x); + +// Return reference to the argument through lifetimebound. +const std::string& getLB(const std::string &s [[clang::lifetimebound]]); +const std::string& getLB(std::string_view sv [[clang::lifetimebound]]); +const std::string* getPointerLB(const std::string &s [[clang::lifetimebound]]); +const std::string* getPointerNoLB(const std::string &s); + +void capturePointer(const std::string* sp [[clang::lifetime_capture_by(x)]], X &x); + +struct ThisIsCaptured { + void capture(X &x) [[clang::lifetime_capture_by(x)]]; +}; + +void captureByGlobal(std::string_view s [[clang::lifetime_capture_by(global)]]); +void captureByUnknown(std::string_view s [[clang::lifetime_capture_by(unknown)]]); + +void use() { + std::string_view local_string_view; + std::string local_string; + X x; + // Capture an 'int'. + int local; + captureInt(1, // expected-warning {{object whose reference is captured by 'x' will be destroyed at the end of the full-expression}} + x); + captureRValInt(1, x); // expected-warning {{object whose reference is captured by 'x'}} + captureInt(local, x); + noCaptureInt(1, x); + noCaptureInt(local, x); + + // Capture using std::string_view. + captureStringView(local_string_view, x); + captureStringView(std::string(), // expected-warning {{object whose reference is captured by 'x'}} + x); + captureStringView(substr( + std::string() // expected-warning {{object whose reference is captured by 'x'}} + ), x); + captureStringView(substr(local_string), x); + captureStringView(strcopy(std::string()), x); + captureRValStringView(std::move(local_string_view), x); + captureRValStringView(std::string(), x); // expected-warning {{object whose reference is captured by 'x'}} + captureRValStringView(std::string_view{"abcd"}, x); + captureRValStringView(substr(local_string), x); + captureRValStringView(substr(std::string()), x); // expected-warning {{object whose reference is captured by 'x'}} + captureRValStringView(strcopy(std::string()), x); + noCaptureStringView(local_string_view, x); + noCaptureStringView(std::string(), x); + noCaptureStringView(substr(std::string()), x); + + // Capture using std::string. + captureString(std::string(), x); // expected-warning {{object whose reference is captured by 'x'}} + captureString(local_string, x); + captureRValString(std::move(local_string), x); + captureRValString(std::string(), x); // expected-warning {{object whose reference is captured by 'x'}} + + // Capture with lifetimebound. + captureStringView(getLB(std::string()), x); // expected-warning {{object whose reference is captured by 'x'}} + captureStringView(getLB(substr(std::string())), x); // expected-warning {{object whose reference is captured by 'x'}} + captureStringView(getLB(getLB( + std::string() // expected-warning {{object whose reference is captured by 'x'}} + )), x); + capturePointer(getPointerLB(std::string()), x); // expected-warning {{object whose reference is captured by 'x'}} + capturePointer(getPointerLB(*getPointerLB( + std::string() // expected-warning {{object whose reference is captured by 'x'}} + )), x); + capturePointer(getPointerNoLB(std::string()), x); + + // Member functions. + x.captureInt(1); // expected-warning {{object whose reference is captured by 'x'}} + x.captureSV(std::string()); // expected-warning {{object whose reference is captured by 'x'}} + x.captureSV(substr(std::string())); // expected-warning {{object whose reference is captured by 'x'}} + x.captureSV(strcopy(std::string())); + + // 'this' is captured. + ThisIsCaptured{}.capture(x); // expected-warning {{object whose reference is captured by 'x'}} + ThisIsCaptured TIS; + TIS.capture(x); + + // capture by global. + captureByGlobal(std::string()); // expected-warning {{object whose reference is captured will be destroyed at the end of the full-expression}} + captureByGlobal(substr(std::string())); // expected-warning {{captured}} + captureByGlobal(local_string); + captureByGlobal(local_string_view); + + // // capture by unknown. + captureByGlobal(std::string()); // expected-warning {{object whose reference is captured will be destroyed at the end of the full-expression}} + captureByGlobal(substr(std::string())); // expected-warning {{captured}} + captureByGlobal(local_string); + captureByGlobal(local_string_view); +} + +void captureDefaultArg(X &x, std::string_view s [[clang::lifetime_capture_by(x)]] = std::string()); +void useCaptureDefaultArg() { + X x; + captureDefaultArg(x); // FIXME: Diagnose temporary default arg. + captureDefaultArg(x, std::string("temp")); // expected-warning {{captured}} + std::string local; + captureDefaultArg(x, local); +} + +template<typename T> struct IsPointerLikeTypeImpl : std::false_type {}; +template<> struct IsPointerLikeTypeImpl<std::string_view> : std::true_type {}; +template<typename T> concept IsPointerLikeType = std::is_pointer<T>::value || IsPointerLikeTypeImpl<T>::value; + +// Templated containers having no distinction between pointer-like and other element type. +template<class T> +struct MySet { + void insert(T&& t [[clang::lifetime_capture_by(this)]]); + void insert(const T& t [[clang::lifetime_capture_by(this)]]); +}; +void user_defined_containers() { + MySet<int> set_of_int; + set_of_int.insert(1); // expected-warning {{object whose reference is captured by 'set_of_int' will be destroyed}} + MySet<std::string_view> set_of_sv; + set_of_sv.insert(std::string()); // expected-warning {{object whose reference is captured by 'set_of_sv' will be destroyed}} ---------------- hokein wrote:
Can you add a testcase `set_of_sv.insert(std::string_view())`? I think we will diagnose this case as well. https://github.com/llvm/llvm-project/pull/115921 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits