Bug 1452754 - Add tests to TestMustReturnFromCaller.cpp that verify that RAII destruction after a must-return-after expression is permitted. r=mystor
authorJeff Walden <jwalden@mit.edu>
Mon, 09 Apr 2018 12:56:37 -0700
changeset 1480200 51399503eb15cd14ecc5510d15927c6b0f840175
parent 1480199 9ae76a38a5148b400853151a08ef22d8a7ab463a
child 1480201 ca65fd361e412c270276850cbcc6511c5022f48e
push id264020
push usereisaacson@mozilla.com
push dateWed, 11 Apr 2018 03:00:44 +0000
treeherdertry@c76c72352514 [default view] [failures only]
reviewersmystor
bugs1452754
milestone61.0a1
Bug 1452754 - Add tests to TestMustReturnFromCaller.cpp that verify that RAII destruction after a must-return-after expression is permitted. r=mystor
build/clang-plugin/tests/TestMustReturnFromCaller.cpp
--- a/build/clang-plugin/tests/TestMustReturnFromCaller.cpp
+++ b/build/clang-plugin/tests/TestMustReturnFromCaller.cpp
@@ -1,35 +1,69 @@
 #include <cstddef>
+#include <utility>
 
 #define MOZ_MUST_RETURN_FROM_CALLER __attribute__((annotate("moz_must_return_from_caller")))
 #define MOZ_MAY_CALL_AFTER_MUST_RETURN __attribute__((annotate("moz_may_call_after_must_return")))
 
 void MOZ_MUST_RETURN_FROM_CALLER Throw() {}
 void DoAnythingElse();
 int MakeAnInt();
 int MOZ_MAY_CALL_AFTER_MUST_RETURN SafeMakeInt();
 bool Condition();
 
+// It might be nicer to #include "mozilla/ScopeExit.h" and use that here -- but
+// doing so also will #define the two attribute-macros defined above, running a
+// risk of redefinition errors.  Just stick to the normal clang-plugin test
+// style and use as little external code as possible.
+
+template<typename Func>
+class ScopeExit {
+  Func exitFunction;
+  bool callOnDestruction;
+public:
+  explicit ScopeExit(Func&& func)
+    : exitFunction(std::move(func))
+    , callOnDestruction(true)
+  {}
+
+  ~ScopeExit() {
+    if (callOnDestruction) {
+      exitFunction();
+    }
+  }
+
+  void release() { callOnDestruction = false; }
+};
+
+template<typename ExitFunction>
+ScopeExit<ExitFunction>
+MakeScopeExit(ExitFunction&& func)
+{
+  return ScopeExit<ExitFunction>(std::move(func));
+}
+
 class Foo {
 public:
   __attribute__((annotate("moz_implicit"))) Foo(std::nullptr_t);
   Foo();
 };
 
 void a1() {
   Throw();
 }
 
 int a2() {
   Throw(); // expected-error {{You must immediately return after calling this function}}
   return MakeAnInt();
 }
 
 int a3() {
+  // RAII operations happening after a must-immediately-return are fine.
+  auto atExit = MakeScopeExit([] { DoAnythingElse(); });
   Throw();
   return 5;
 }
 
 int a4() {
   Throw(); // expected-error {{You must immediately return after calling this function}}
   return Condition() ? MakeAnInt() : MakeAnInt();
 }
@@ -58,16 +92,29 @@ int a8() {
 
 int a9() {
   if (Condition()) {
     Throw();
   }
   return SafeMakeInt();
 }
 
+int a10() {
+  auto atExit = MakeScopeExit([] { DoAnythingElse(); });
+
+  if (Condition()) {
+    Throw();
+    return SafeMakeInt();
+  }
+
+  atExit.release();
+  DoAnythingElse();
+  return 5;
+}
+
 void b1() {
   if (Condition()) {
     Throw();
   }
 }
 
 int b2() {
   if (Condition()) {