summaryrefslogtreecommitdiffstats
path: root/build/clang-plugin/tests/TestNoRefcountedInsideLambdas.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'build/clang-plugin/tests/TestNoRefcountedInsideLambdas.cpp')
-rw-r--r--build/clang-plugin/tests/TestNoRefcountedInsideLambdas.cpp682
1 files changed, 682 insertions, 0 deletions
diff --git a/build/clang-plugin/tests/TestNoRefcountedInsideLambdas.cpp b/build/clang-plugin/tests/TestNoRefcountedInsideLambdas.cpp
new file mode 100644
index 0000000000..aedc5af096
--- /dev/null
+++ b/build/clang-plugin/tests/TestNoRefcountedInsideLambdas.cpp
@@ -0,0 +1,682 @@
+#include <mozilla/StaticAnalysisFunctions.h>
+
+#include <functional>
+#define MOZ_STRONG_REF
+#define MOZ_IMPLICIT __attribute__((annotate("moz_implicit")))
+
+// Ensure that warnings about returning stack addresses of local variables are
+// errors, so our `expected-error` annotations below work correctly.
+#pragma GCC diagnostic error "-Wreturn-stack-address"
+
+struct RefCountedBase {
+ void AddRef();
+ void Release();
+};
+
+template <class T>
+struct SmartPtr {
+ SmartPtr();
+ MOZ_IMPLICIT SmartPtr(T*);
+ T* MOZ_STRONG_REF t;
+ T* operator->() const;
+};
+
+struct R : RefCountedBase {
+ void method();
+private:
+ void privateMethod();
+};
+
+void take(...);
+void foo() {
+ R* ptr;
+ SmartPtr<R> sp;
+ take([&](R* argptr) {
+ R* localptr;
+ ptr->method();
+ argptr->method();
+ localptr->method();
+ });
+ take([&](SmartPtr<R> argsp) {
+ SmartPtr<R> localsp;
+ sp->method();
+ argsp->method();
+ localsp->method();
+ });
+ take([&](R* argptr) {
+ R* localptr;
+ take(ptr);
+ take(argptr);
+ take(localptr);
+ });
+ take([&](SmartPtr<R> argsp) {
+ SmartPtr<R> localsp;
+ take(sp);
+ take(argsp);
+ take(localsp);
+ });
+ take([=](R* argptr) {
+ R* localptr;
+ ptr->method();
+ argptr->method();
+ localptr->method();
+ });
+ take([=](SmartPtr<R> argsp) {
+ SmartPtr<R> localsp;
+ sp->method();
+ argsp->method();
+ localsp->method();
+ });
+ take([=](R* argptr) {
+ R* localptr;
+ take(ptr);
+ take(argptr);
+ take(localptr);
+ });
+ take([=](SmartPtr<R> argsp) {
+ SmartPtr<R> localsp;
+ take(sp);
+ take(argsp);
+ take(localsp);
+ });
+ take([ptr](R* argptr) {
+ R* localptr;
+ ptr->method();
+ argptr->method();
+ localptr->method();
+ });
+ take([sp](SmartPtr<R> argsp) {
+ SmartPtr<R> localsp;
+ sp->method();
+ argsp->method();
+ localsp->method();
+ });
+ take([ptr](R* argptr) {
+ R* localptr;
+ take(ptr);
+ take(argptr);
+ take(localptr);
+ });
+ take([sp](SmartPtr<R> argsp) {
+ SmartPtr<R> localsp;
+ take(sp);
+ take(argsp);
+ take(localsp);
+ });
+ take([&ptr](R* argptr) {
+ R* localptr;
+ ptr->method();
+ argptr->method();
+ localptr->method();
+ });
+ take([&sp](SmartPtr<R> argsp) {
+ SmartPtr<R> localsp;
+ sp->method();
+ argsp->method();
+ localsp->method();
+ });
+ take([&ptr](R* argptr) {
+ R* localptr;
+ take(ptr);
+ take(argptr);
+ take(localptr);
+ });
+ take([&sp](SmartPtr<R> argsp) {
+ SmartPtr<R> localsp;
+ take(sp);
+ take(argsp);
+ take(localsp);
+ });
+}
+
+void b() {
+ R* ptr;
+ SmartPtr<R> sp;
+ std::function<void(R*)>([&](R* argptr) {
+ R* localptr;
+ ptr->method();
+ argptr->method();
+ localptr->method();
+ });
+ std::function<void(SmartPtr<R>)>([&](SmartPtr<R> argsp) {
+ SmartPtr<R> localsp;
+ sp->method();
+ argsp->method();
+ localsp->method();
+ });
+ std::function<void(R*)>([&](R* argptr) {
+ R* localptr;
+ take(ptr);
+ take(argptr);
+ take(localptr);
+ });
+ std::function<void(SmartPtr<R>)>([&](SmartPtr<R> argsp) {
+ SmartPtr<R> localsp;
+ take(sp);
+ take(argsp);
+ take(localsp);
+ });
+ std::function<void(R*)>([=](R* argptr) {
+ R* localptr;
+ ptr->method(); // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}}
+ argptr->method();
+ localptr->method();
+ });
+ std::function<void(SmartPtr<R>)>([=](SmartPtr<R> argsp) {
+ SmartPtr<R> localsp;
+ sp->method();
+ argsp->method();
+ localsp->method();
+ });
+ std::function<void(R*)>([=](R* argptr) {
+ R* localptr;
+ take(ptr); // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}}
+ take(argptr);
+ take(localptr);
+ });
+ std::function<void(SmartPtr<R>)>([=](SmartPtr<R> argsp) {
+ SmartPtr<R> localsp;
+ take(sp);
+ take(argsp);
+ take(localsp);
+ });
+ std::function<void(R*)>([ptr](R* argptr) { // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}}
+ R* localptr;
+ ptr->method();
+ argptr->method();
+ localptr->method();
+ });
+ std::function<void(SmartPtr<R>)>([sp](SmartPtr<R> argsp) {
+ SmartPtr<R> localsp;
+ sp->method();
+ argsp->method();
+ localsp->method();
+ });
+ std::function<void(R*)>([ptr](R* argptr) { // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}}
+ R* localptr;
+ take(ptr);
+ take(argptr);
+ take(localptr);
+ });
+ std::function<void(SmartPtr<R>)>([sp](SmartPtr<R> argsp) {
+ SmartPtr<R> localsp;
+ take(sp);
+ take(argsp);
+ take(localsp);
+ });
+ std::function<void(R*)>([&ptr](R* argptr) {
+ R* localptr;
+ ptr->method();
+ argptr->method();
+ localptr->method();
+ });
+ std::function<void(SmartPtr<R>)>([&sp](SmartPtr<R> argsp) {
+ SmartPtr<R> localsp;
+ sp->method();
+ argsp->method();
+ localsp->method();
+ });
+ std::function<void(R*)>([&ptr](R* argptr) {
+ R* localptr;
+ take(ptr);
+ take(argptr);
+ take(localptr);
+ });
+ std::function<void(SmartPtr<R>)>([&sp](SmartPtr<R> argsp) {
+ SmartPtr<R> localsp;
+ take(sp);
+ take(argsp);
+ take(localsp);
+ });
+}
+
+// These tests would check c++14 deduced return types, if they were supported in
+// our codebase. They are being kept here for convenience in the future if we do
+// add support for c++14 deduced return types
+#if 0
+auto d1() {
+ R* ptr;
+ SmartPtr<R> sp;
+ return ([&](R* argptr) {
+ R* localptr;
+ ptr->method();
+ argptr->method();
+ localptr->method();
+ });
+}
+auto d2() {
+ R* ptr;
+ SmartPtr<R> sp;
+ return ([&](SmartPtr<R> argsp) {
+ SmartPtr<R> localsp;
+ sp->method();
+ argsp->method();
+ localsp->method();
+ });
+}
+auto d3() {
+ R* ptr;
+ SmartPtr<R> sp;
+ return ([&](R* argptr) {
+ R* localptr;
+ take(ptr);
+ take(argptr);
+ take(localptr);
+ });
+}
+auto d4() {
+ R* ptr;
+ SmartPtr<R> sp;
+ return ([&](SmartPtr<R> argsp) {
+ SmartPtr<R> localsp;
+ take(sp);
+ take(argsp);
+ take(localsp);
+ });
+}
+auto d5() {
+ R* ptr;
+ SmartPtr<R> sp;
+ return ([=](R* argptr) {
+ R* localptr;
+ ptr->method(); // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}}
+ argptr->method();
+ localptr->method();
+ });
+}
+auto d6() {
+ R* ptr;
+ SmartPtr<R> sp;
+ return ([=](SmartPtr<R> argsp) {
+ SmartPtr<R> localsp;
+ sp->method();
+ argsp->method();
+ localsp->method();
+ });
+}
+auto d8() {
+ R* ptr;
+ SmartPtr<R> sp;
+ return ([=](R* argptr) {
+ R* localptr;
+ take(ptr); // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}}
+ take(argptr);
+ take(localptr);
+ });
+}
+auto d9() {
+ R* ptr;
+ SmartPtr<R> sp;
+ return ([=](SmartPtr<R> argsp) {
+ SmartPtr<R> localsp;
+ take(sp);
+ take(argsp);
+ take(localsp);
+ });
+}
+auto d10() {
+ R* ptr;
+ SmartPtr<R> sp;
+ return ([ptr](R* argptr) { // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}}
+ R* localptr;
+ ptr->method();
+ argptr->method();
+ localptr->method();
+ });
+}
+auto d11() {
+ R* ptr;
+ SmartPtr<R> sp;
+ return ([sp](SmartPtr<R> argsp) {
+ SmartPtr<R> localsp;
+ sp->method();
+ argsp->method();
+ localsp->method();
+ });
+}
+auto d12() {
+ R* ptr;
+ SmartPtr<R> sp;
+ return ([ptr](R* argptr) { // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}}
+ R* localptr;
+ take(ptr);
+ take(argptr);
+ take(localptr);
+ });
+}
+auto d13() {
+ R* ptr;
+ SmartPtr<R> sp;
+ return ([sp](SmartPtr<R> argsp) {
+ SmartPtr<R> localsp;
+ take(sp);
+ take(argsp);
+ take(localsp);
+ });
+}
+auto d14() {
+ R* ptr;
+ SmartPtr<R> sp;
+ return ([&ptr](R* argptr) {
+ R* localptr;
+ ptr->method();
+ argptr->method();
+ localptr->method();
+ });
+}
+auto d15() {
+ R* ptr;
+ SmartPtr<R> sp;
+ return ([&sp](SmartPtr<R> argsp) {
+ SmartPtr<R> localsp;
+ sp->method();
+ argsp->method();
+ localsp->method();
+ });
+}
+auto d16() {
+ R* ptr;
+ SmartPtr<R> sp;
+ return ([&ptr](R* argptr) {
+ R* localptr;
+ take(ptr);
+ take(argptr);
+ take(localptr);
+ });
+}
+auto d17() {
+ R* ptr;
+ SmartPtr<R> sp;
+ return ([&sp](SmartPtr<R> argsp) {
+ SmartPtr<R> localsp;
+ take(sp);
+ take(argsp);
+ take(localsp);
+ });
+}
+#endif
+
+void e() {
+ auto e1 = []() {
+ R* ptr;
+ SmartPtr<R> sp;
+ return ([&](R* argptr) { // expected-error{{address of stack memory associated with local variable 'ptr' returned}}
+ R* localptr;
+#if __clang_major__ >= 12
+ ptr->method(); // expected-note{{implicitly captured by reference due to use here}}
+#else
+ ptr->method();
+#endif
+ argptr->method();
+ localptr->method();
+ });
+ };
+ auto e2 = []() {
+ R* ptr;
+ SmartPtr<R> sp;
+ return ([&](SmartPtr<R> argsp) { // expected-error{{address of stack memory associated with local variable 'sp' returned}}
+ SmartPtr<R> localsp;
+#if __clang_major__ >= 12
+ sp->method(); // expected-note{{implicitly captured by reference due to use here}}
+#else
+ sp->method();
+#endif
+ argsp->method();
+ localsp->method();
+ });
+ };
+ auto e3 = []() {
+ R* ptr;
+ SmartPtr<R> sp;
+ return ([&](R* argptr) { // expected-error{{address of stack memory associated with local variable 'ptr' returned}}
+ R* localptr;
+#if __clang_major__ >= 12
+ take(ptr); // expected-note{{implicitly captured by reference due to use here}}
+#else
+ take(ptr);
+#endif
+ take(argptr);
+ take(localptr);
+ });
+ };
+ auto e4 = []() {
+ R* ptr;
+ SmartPtr<R> sp;
+ return ([&](SmartPtr<R> argsp) { // expected-error{{address of stack memory associated with local variable 'sp' returned}}
+ SmartPtr<R> localsp;
+#if __clang_major__ >= 12
+ take(sp); // expected-note{{implicitly captured by reference due to use here}}
+#else
+ take(sp);
+#endif
+ take(argsp);
+ take(localsp);
+ });
+ };
+ auto e5 = []() {
+ R* ptr;
+ SmartPtr<R> sp;
+ return ([=](R* argptr) {
+ R* localptr;
+ ptr->method(); // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}}
+ argptr->method();
+ localptr->method();
+ });
+ };
+ auto e6 = []() {
+ R* ptr;
+ SmartPtr<R> sp;
+ return ([=](SmartPtr<R> argsp) {
+ SmartPtr<R> localsp;
+ sp->method();
+ argsp->method();
+ localsp->method();
+ });
+ };
+ auto e8 = []() {
+ R* ptr;
+ SmartPtr<R> sp;
+ return ([=](R* argptr) {
+ R* localptr;
+ take(ptr); // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}}
+ take(argptr);
+ take(localptr);
+ });
+ };
+ auto e9 = []() {
+ R* ptr;
+ SmartPtr<R> sp;
+ return ([=](SmartPtr<R> argsp) {
+ SmartPtr<R> localsp;
+ take(sp);
+ take(argsp);
+ take(localsp);
+ });
+ };
+ auto e10 = []() {
+ R* ptr;
+ SmartPtr<R> sp;
+ return ([ptr](R* argptr) { // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}}
+ R* localptr;
+ ptr->method();
+ argptr->method();
+ localptr->method();
+ });
+ };
+ auto e11 = []() {
+ R* ptr;
+ SmartPtr<R> sp;
+ return ([sp](SmartPtr<R> argsp) {
+ SmartPtr<R> localsp;
+ sp->method();
+ argsp->method();
+ localsp->method();
+ });
+ };
+ auto e12 = []() {
+ R* ptr;
+ SmartPtr<R> sp;
+ return ([ptr](R* argptr) { // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}}
+ R* localptr;
+ take(ptr);
+ take(argptr);
+ take(localptr);
+ });
+ };
+ auto e13 = []() {
+ R* ptr;
+ SmartPtr<R> sp;
+ return ([sp](SmartPtr<R> argsp) {
+ SmartPtr<R> localsp;
+ take(sp);
+ take(argsp);
+ take(localsp);
+ });
+ };
+ auto e14 = []() {
+ R* ptr;
+ SmartPtr<R> sp;
+#if __clang_major__ >= 12
+ return ([&ptr](R* argptr) { // expected-error{{address of stack memory associated with local variable 'ptr' returned}} expected-note{{captured by reference here}}
+ R* localptr;
+ ptr->method();
+ argptr->method();
+ localptr->method();
+ });
+#else
+ return ([&ptr](R* argptr) { // expected-error{{address of stack memory associated with local variable 'ptr' returned}}
+ R* localptr;
+ ptr->method();
+ argptr->method();
+ localptr->method();
+ });
+#endif
+ };
+ auto e15 = []() {
+ R* ptr;
+ SmartPtr<R> sp;
+#if __clang_major__ >= 12
+ return ([&sp](SmartPtr<R> argsp) { // expected-error{{address of stack memory associated with local variable 'sp' returned}} expected-note{{captured by reference here}}
+ SmartPtr<R> localsp;
+ sp->method();
+ argsp->method();
+ localsp->method();
+ });
+#else
+ return ([&sp](SmartPtr<R> argsp) { // expected-error{{address of stack memory associated with local variable 'sp' returned}}
+ SmartPtr<R> localsp;
+ sp->method();
+ argsp->method();
+ localsp->method();
+ });
+#endif
+ };
+ auto e16 = []() {
+ R* ptr;
+ SmartPtr<R> sp;
+#if __clang_major__ >= 12
+ return ([&ptr](R* argptr) { // expected-error{{address of stack memory associated with local variable 'ptr' returned}} expected-note{{captured by reference here}}
+ R* localptr;
+ take(ptr);
+ take(argptr);
+ take(localptr);
+ });
+#else
+ return ([&ptr](R* argptr) { // expected-error{{address of stack memory associated with local variable 'ptr' returned}}
+ R* localptr;
+ take(ptr);
+ take(argptr);
+ take(localptr);
+ });
+#endif
+ };
+ auto e17 = []() {
+ R* ptr;
+ SmartPtr<R> sp;
+#if __clang_major__ >= 12
+ return ([&sp](SmartPtr<R> argsp) { // expected-error{{address of stack memory associated with local variable 'sp' returned}} expected-note{{captured by reference here}}
+ SmartPtr<R> localsp;
+ take(sp);
+ take(argsp);
+ take(localsp);
+ });
+#else
+ return ([&sp](SmartPtr<R> argsp) { // expected-error{{address of stack memory associated with local variable 'sp' returned}}
+ SmartPtr<R> localsp;
+ take(sp);
+ take(argsp);
+ take(localsp);
+ });
+#endif
+ };
+}
+
+void
+R::privateMethod() {
+ SmartPtr<R> self = this;
+ std::function<void()>([&]() {
+ self->method();
+ });
+ std::function<void()>([&]() {
+ self->privateMethod();
+ });
+ std::function<void()>([&]() {
+ this->method();
+ });
+ std::function<void()>([&]() {
+ this->privateMethod();
+ });
+ std::function<void()>([=]() {
+ self->method();
+ });
+ std::function<void()>([=]() {
+ self->privateMethod();
+ });
+ std::function<void()>([=]() {
+ this->method(); // expected-error{{Refcounted variable 'this' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}}
+ });
+ std::function<void()>([=]() {
+ this->privateMethod(); // expected-error{{Refcounted variable 'this' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}}
+ });
+ std::function<void()>([self]() {
+ self->method();
+ });
+ std::function<void()>([self]() {
+ self->privateMethod();
+ });
+ std::function<void()>([this]() {
+ this->method(); // expected-error{{Refcounted variable 'this' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}}
+ });
+ std::function<void()>([this]() {
+ this->privateMethod(); // expected-error{{Refcounted variable 'this' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}}
+ });
+ std::function<void()>([this]() {
+ method(); // expected-error{{Refcounted variable 'this' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}}
+ });
+ std::function<void()>([this]() {
+ privateMethod(); // expected-error{{Refcounted variable 'this' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}}
+ });
+ std::function<void()>([=]() {
+ method(); // expected-error{{Refcounted variable 'this' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}}
+ });
+ std::function<void()>([=]() {
+ privateMethod(); // expected-error{{Refcounted variable 'this' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}}
+ });
+ std::function<void()>([&]() {
+ method();
+ });
+ std::function<void()>([&]() {
+ privateMethod();
+ });
+
+ std::function<void()>(
+ [instance = MOZ_KnownLive(this)]() { instance->privateMethod(); });
+
+ // It should be OK to go through `this` if we have captured a reference to it.
+ std::function<void()>([this, self]() {
+ this->method();
+ this->privateMethod();
+ method();
+ privateMethod();
+ });
+}