================
@@ -0,0 +1,151 @@
+// RUN: %clang_cc1 -fsyntax-only -Wlifetime-safety -Wno-dangling -verify %s
+
+#include "Inputs/lifetime-analysis.h"
+
+template<int N> struct Dummy {};
+static std::string kGlobal = "GLOBAL";
+void takeString(std::string&& s);
+
+std::string_view construct_view(const std::string& str
[[clang::lifetimebound]]);
+
+struct CtorInit {
+ std::string_view view; // expected-note {{this field dangles}}
+ CtorInit(std::string s) : view(s) {} // expected-warning {{address of stack
memory escapes to a field}}
+};
+
+struct CtorSet {
+ std::string_view view; // expected-note {{this field dangles}}
+ CtorSet(std::string s) { view = s; } // expected-warning {{address of stack
memory escapes to a field}}
+};
+
+struct CtorInitLifetimeBound {
+ std::string_view view; // expected-note {{this field dangles}}
+ CtorInitLifetimeBound(std::string s) : view(construct_view(s)) {} //
expected-warning {{address of stack memory escapes to a field}}
+};
+
+struct CtorInitButMoved {
+ std::string_view view;
+ CtorInitButMoved(std::string s) : view(s) { takeString(std::move(s)); }
+};
+
+struct CtorInitButMovedOwned {
+ std::string owned;
+ std::string_view view;
+ CtorInitButMovedOwned(std::string s) : view(s), owned(std::move(s)) {}
+ CtorInitButMovedOwned(Dummy<1>, std::string s) : owned(std::move(s)),
view(owned) {}
+};
+
+struct CtorInitMultipleViews {
+ std::string_view view1; // expected-note {{this field dangles}}
+ std::string_view view2; // expected-note {{this field dangles}}
+ CtorInitMultipleViews(std::string s) : view1(s), // expected-warning
{{address of stack memory escapes to a field}}
+ view2(s) {} // expected-warning
{{address of stack memory escapes to a field}}
+};
+
+struct CtorInitMultipleParams {
+ std::string_view view1; // expected-note {{this field dangles}}
+ std::string_view view2; // expected-note {{this field dangles}}
+ CtorInitMultipleParams(std::string s1, std::string s2) : view1(s1), //
expected-warning {{address of stack memory escapes to a field}}
+ view2(s2) {} //
expected-warning {{address of stack memory escapes to a field}}
+};
+
+struct CtorRefField {
+ const std::string& str; // expected-note {{this field dangles}}
+ const std::string_view& view; // expected-note {{this field dangles}}
+ CtorRefField(std::string s, std::string_view v) : str(s), //
expected-warning {{address of stack memory escapes to a field}}
+ view(v) {} //
expected-warning {{address of stack memory escapes to a field}}
+ CtorRefField(Dummy<1> ok, const std::string& s, const std::string_view& v):
str(s), view(v) {}
+};
+
+struct CtorPointerField {
+ const char* ptr; // expected-note {{this field dangles}}
+ CtorPointerField(std::string s) : ptr(s.data()) {} // expected-warning
{{address of stack memory escapes to a field}}
+ CtorPointerField(Dummy<1> ok, const std::string& s) : ptr(s.data()) {}
+ CtorPointerField(Dummy<2> ok, std::string_view view) : ptr(view.data()) {}
+};
+
+struct MemberSetters {
+ std::string_view view; // expected-note 5 {{this field dangles}}
+ const char* p; // expected-note 5 {{this field dangles}}
+
+ void setWithParam(std::string s) {
+ view = s; // expected-warning {{address of stack memory escapes to a
field}}
+ p = s.data(); // expected-warning {{address of stack memory escapes to a
field}}
+ }
+
+ void setWithParamAndReturn(std::string s) {
+ view = s; // expected-warning {{address of stack memory escapes to a
field}}
+ p = s.data(); // expected-warning {{address of stack memory escapes to a
field}}
+ return;
+ }
+
+ void setWithParamOk(const std::string& s) {
+ view = s;
+ p = s.data();
+ }
+
+ void setWithParamOkAndReturn(const std::string& s) {
+ view = s;
+ p = s.data();
+ return;
+ }
+
+ void setWithLocal() {
+ std::string s;
+ view = s; // expected-warning {{address of stack memory escapes to a
field}}
+ p = s.data(); // expected-warning {{address of stack memory escapes to a
field}}
+ }
+
+ void setWithLocalButMoved() {
+ std::string s;
+ view = s;
+ p = s.data();
+ takeString(std::move(s));
+ }
+
+ void setWithGlobal() {
+ view = kGlobal;
+ p = kGlobal.data();
+ }
+
+ void setWithLocalThenWithGlobal() {
+ std::string local;
+ view = local;
+ p = local.data();
+
+ view = kGlobal;
+ p = kGlobal.data();
+ }
+
+ void setWithGlobalThenWithLocal() {
+ view = kGlobal;
+ p = kGlobal.data();
+
+ std::string local;
+ view = local; // expected-warning {{address of stack memory escapes to
a field}}
+ p = local.data(); // expected-warning {{address of stack memory escapes to
a field}}
+ }
+
+ void use_after_scope() {
+ {
+ std::string local;
+ view = local; // expected-warning {{address of stack memory escapes
to a field}}
+ p = local.data(); // expected-warning {{address of stack memory escapes
to a field}}
+ }
+ (void)view;
+ (void)p;
+ }
+
+ void use_after_scope_saved_after_reassignment() {
+ {
+ std::string local;
+ view = local;
+ p = local.data();
+ }
+ (void)view;
+ (void)p;
+
+ view = kGlobal;
+ p = kGlobal.data();
+ }
+};
----------------
Xazax-hun wrote:
Could we add a test cases where the fields are not direct?
```
struct A {
struct {
char *p;
} b;
// escape to b.p
};
struct B {
struct {
char *p;
};
// escape to p
};
```
https://github.com/llvm/llvm-project/pull/177363
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits