blob: 4bb57e6b9df95e019f017167304c7647a7a679b1 [file] [edit]
// RUN: %clang_cc1 -fsyntax-only -flifetime-safety-inference -Wlifetime-safety-noescape -verify %s
#include "Inputs/lifetime-analysis.h"
struct [[gsl::Owner]] MyObj {
int id;
~MyObj() {} // Non-trivial destructor
};
struct [[gsl::Pointer()]] View {
View(const MyObj&); // Borrows from MyObj
View();
void use() const;
};
View return_noescape_directly(const MyObj& in [[clang::noescape]]) { // expected-warning {{parameter is marked [[clang::noescape]] but escapes}}
return in; // expected-note {{returned here}}
}
View return_one_of_two(
const MyObj& a [[clang::noescape]], // expected-warning {{parameter is marked [[clang::noescape]] but escapes}}
const MyObj& b [[clang::noescape]],
bool cond) {
if (cond)
return a; // expected-note {{returned here}}
return View();
}
View return_both(
const MyObj& a [[clang::noescape]], // expected-warning {{parameter is marked [[clang::noescape]] but escapes}}
const MyObj& b [[clang::noescape]], // expected-warning {{parameter is marked [[clang::noescape]] but escapes}}
bool cond) {
if (cond)
return a; // expected-note {{returned here}}
return b; // expected-note {{returned here}}
}
View mixed_noescape_lifetimebound(
const MyObj& a [[clang::noescape]], // expected-warning {{parameter is marked [[clang::noescape]] but escapes}}
const MyObj& b [[clang::lifetimebound]],
bool cond) {
if (cond)
return a; // expected-note {{returned here}}
return b;
}
View mixed_only_noescape_escapes(
const MyObj& a [[clang::noescape]],
const MyObj& b [[clang::lifetimebound]]) {
(void)a;
return b;
}
View multiple_reassign(
const MyObj& a [[clang::noescape]],
const MyObj& b [[clang::noescape]], // expected-warning {{parameter is marked [[clang::noescape]] but escapes}}
const MyObj& c [[clang::noescape]], // expected-warning {{parameter is marked [[clang::noescape]] but escapes}}
bool cond) {
View v = a;
if (cond)
v = b;
else
v = c;
return v; // expected-note 2 {{returned here}}
}
int* return_noescape_pointer(int* p [[clang::noescape]]) { // expected-warning {{parameter is marked [[clang::noescape]] but escapes}}
return p; // expected-note {{returned here}}
}
MyObj& return_noescape_reference(MyObj& r [[clang::noescape]]) { // expected-warning {{parameter is marked [[clang::noescape]] but escapes}}
return r; // expected-note {{returned here}}
}
View return_via_local(const MyObj& in [[clang::noescape]]) { // expected-warning {{parameter is marked [[clang::noescape]] but escapes}}
View v = in;
return v; // expected-note {{returned here}}
}
void use_locally(const MyObj& in [[clang::noescape]]) {
View v = in;
v.use();
}
View return_without_noescape(const MyObj& in) {
return in;
}
View return_with_lifetimebound(const MyObj& in [[clang::lifetimebound]]) {
return in;
}
void pointer_used_locally(MyObj* p [[clang::noescape]]) {
p->id = 42;
}
// FIXME: diagnose differently when parameter has both '[[clang::noescape]]' and '[[clang::lifetimebound]]'.
View both_noescape_and_lifetimebound(
const MyObj& in [[clang::noescape]] [[clang::lifetimebound]]) { // expected-warning {{parameter is marked [[clang::noescape]] but escapes}}
return in; // expected-note {{returned here}}
}
View identity_lifetimebound(View v [[clang::lifetimebound]]) { return v; }
View escape_through_lifetimebound_call(
const MyObj& in [[clang::noescape]]) { // expected-warning {{parameter is marked [[clang::noescape]] but escapes}}
return identity_lifetimebound(in); // expected-note {{returned here}}
}
View no_annotation_identity(View v) { return v; }
View escape_through_unannotated_call(const MyObj& in [[clang::noescape]]) { // expected-warning {{parameter is marked [[clang::noescape]] but escapes}}
return no_annotation_identity(in); // expected-note {{returned here}}
}
View global_view; // expected-note {{escapes to this global storage}}
void escape_through_global_var(const MyObj& in [[clang::noescape]]) { // expected-warning {{parameter is marked [[clang::noescape]] but escapes}}
global_view = in;
}
struct ObjWithStaticField {
static int *static_field; // expected-note {{escapes to this static storage}}
};
void escape_to_static_data_member(int *data [[clang::noescape]]) { // expected-warning {{parameter is marked [[clang::noescape]] but escapes}}
ObjWithStaticField::static_field = data;
}
void escape_through_static_local(int *data [[clang::noescape]]) { // expected-warning {{parameter is marked [[clang::noescape]] but escapes}}
static int *static_local; // expected-note {{escapes to this static storage}}
static_local = data;
}
thread_local int *thread_local_storage; // expected-note {{escapes to this global storage}}
void escape_through_thread_local(int *data [[clang::noescape]]) { // expected-warning {{parameter is marked [[clang::noescape]] but escapes}}
// FIXME: We might want to report whenever anything derived from a
// noescape parameter is assigned to a global, as this is likely
// undesired behavior in most cases.
thread_local_storage = data;
}
struct ObjConsumer {
void escape_through_member(const MyObj& in [[clang::noescape]]) { // expected-warning {{parameter is marked [[clang::noescape]] but escapes}}
member_view = in;
}
View member_view; // expected-note {{escapes to this field}}
};
// FIXME: Escaping through another param is not detected.
void escape_through_param(const MyObj& in, std::vector<View> &v) {
v.push_back(in);
}
View reassign_to_second(
const MyObj& a [[clang::noescape]],
const MyObj& b [[clang::noescape]]) { // expected-warning {{parameter is marked [[clang::noescape]] but escapes}}
View v = a;
v = b;
return v; // expected-note {{returned here}}
}
struct Container {
MyObj data;
const MyObj& getRef() const [[clang::lifetimebound]] { return data; }
};
View access_noescape_field(
const Container& c [[clang::noescape]]) { // expected-warning {{parameter is marked [[clang::noescape]] but escapes}}
return c.data; // expected-note {{returned here}}
}
View access_noescape_through_getter(
Container& c [[clang::noescape]]) { // expected-warning {{parameter is marked [[clang::noescape]] but escapes}}
return c.getRef(); // expected-note {{returned here}}
}
MyObj* return_ptr_from_noescape_ref(
MyObj& r [[clang::noescape]]) { // expected-warning {{parameter is marked [[clang::noescape]] but escapes}}
return &r; // expected-note {{returned here}}
}
MyObj& return_ref_from_noescape_ptr(
MyObj* p [[clang::noescape]]) { // expected-warning {{parameter is marked [[clang::noescape]] but escapes}}
return *p; // expected-note {{returned here}}
}
int* return_spaced_brackets(int* p [ [clang::noescape] /*some comment*/ ]) { // expected-warning {{parameter is marked [[clang::noescape]] but escapes}}
return p; // expected-note {{returned here}}
}
namespace callable_wrappers {
std::function<void()> escape_noescape_via_function(int &x [[clang::noescape]]) { // expected-warning {{parameter is marked [[clang::noescape]] but escapes}}
return [&]() { (void)x; }; // expected-note {{returned here}}
}
} // namespace callable_wrappers