Bug 1331434 - Part 1: Add an analysis to require a return after calls to annotated functions, r=ehsan
authorMichael Layzell <michael@thelayzells.com>
Mon, 16 Jan 2017 19:11:41 -0500
changeset 346485 f539afe7ee0d3191d83b34034d1a7aa91e2c0a1e
parent 346484 733e8e23f8a1f71ba87876d9594e2047aaf350d6
child 346486 8640e2712eef577a339d4d12b0c27af808a633ca
push id31470
push usercbook@mozilla.com
push dateWed, 08 Mar 2017 16:00:07 +0000
treeherdermozilla-central@800ba54a4bd5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersehsan
bugs1331434
milestone55.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1331434 - Part 1: Add an analysis to require a return after calls to annotated functions, r=ehsan MozReview-Commit-ID: 7NqXap8FdSn
build/clang-plugin/Checks.inc
build/clang-plugin/ChecksIncludes.inc
build/clang-plugin/CustomMatchers.h
build/clang-plugin/MustReturnFromCallerChecker.cpp
build/clang-plugin/MustReturnFromCallerChecker.h
build/clang-plugin/RecurseGuard.h
build/clang-plugin/StmtToBlockMap.h
build/clang-plugin/moz.build
build/clang-plugin/plugin.h
build/clang-plugin/tests/TestMustReturnFromCaller.cpp
build/clang-plugin/tests/moz.build
mfbt/Attributes.h
--- a/build/clang-plugin/Checks.inc
+++ b/build/clang-plugin/Checks.inc
@@ -5,16 +5,17 @@
 // The list of checker classes that are compatible with clang-tidy.
 
 CHECK(ArithmeticArgChecker, "arithmetic-argument")
 CHECK(AssertAssignmentChecker, "assignment-in-assert")
 CHECK(ExplicitImplicitChecker, "implicit-constructor")
 CHECK(ExplicitOperatorBoolChecker, "explicit-operator-bool")
 CHECK(KungFuDeathGripChecker, "kungfu-death-grip")
 CHECK(MustOverrideChecker, "must-override")
+CHECK(MustReturnFromCallerChecker, "must-return-from-caller")
 CHECK(MustUseChecker, "must-use")
 CHECK(NaNExprChecker, "nan-expr")
 CHECK(NeedsNoVTableTypeChecker, "needs-no-vtable-type")
 CHECK(NoAddRefReleaseOnReturnChecker, "no-addref-release-on-return")
 CHECK(NoAutoTypeChecker, "no-auto-type")
 CHECK(NoDuplicateRefCntMemberChecker, "no-duplicate-refcnt-member")
 CHECK(NoExplicitMoveConstructorChecker, "no-explicit-move-constructor")
 CHECK(NonMemMovableMemberChecker, "non-memmovable-member")
--- a/build/clang-plugin/ChecksIncludes.inc
+++ b/build/clang-plugin/ChecksIncludes.inc
@@ -6,16 +6,17 @@
 // are compatible with clang-tidy.
 
 #include "ArithmeticArgChecker.h"
 #include "AssertAssignmentChecker.h"
 #include "ExplicitImplicitChecker.h"
 #include "ExplicitOperatorBoolChecker.h"
 #include "KungFuDeathGripChecker.h"
 #include "MustOverrideChecker.h"
+#include "MustReturnFromCallerChecker.h"
 #include "MustUseChecker.h"
 #include "NaNExprChecker.h"
 #include "NeedsNoVTableTypeChecker.h"
 #include "NoAddRefReleaseOnReturnChecker.h"
 #include "NoAutoTypeChecker.h"
 #include "NoDuplicateRefCntMemberChecker.h"
 #include "NoExplicitMoveConstructorChecker.h"
 #include "NonMemMovableMemberChecker.h"
--- a/build/clang-plugin/CustomMatchers.h
+++ b/build/clang-plugin/CustomMatchers.h
@@ -226,12 +226,17 @@ AST_MATCHER(CXXMethodDecl, isRequiredBas
   return Decl
       && hasCustomAnnotation(Decl, "moz_required_base_method");
 }
 
 AST_MATCHER(CXXMethodDecl, isNonVirtual) {
   const CXXMethodDecl *Decl = Node.getCanonicalDecl();
   return Decl && !Decl->isVirtual();
 }
+
+AST_MATCHER(FunctionDecl, isMozMustReturnFromCaller) {
+  const FunctionDecl *Decl = Node.getCanonicalDecl();
+  return Decl && hasCustomAnnotation(Decl, "moz_must_return_from_caller");
+}
 }
 }
 
 #endif
new file mode 100644
--- /dev/null
+++ b/build/clang-plugin/MustReturnFromCallerChecker.cpp
@@ -0,0 +1,105 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "MustReturnFromCallerChecker.h"
+#include "CustomMatchers.h"
+
+void MustReturnFromCallerChecker::registerMatchers(MatchFinder* AstMatcher) {
+  // Look for a call to a MOZ_MUST_RETURN_FROM_CALLER function
+  AstMatcher->addMatcher(callExpr(callee(functionDecl(isMozMustReturnFromCaller())),
+                                  anyOf(hasAncestor(lambdaExpr().bind("containing-lambda")),
+                                        hasAncestor(functionDecl().bind("containing-func")))).bind("call"),
+                         this);
+}
+
+void MustReturnFromCallerChecker::check(
+    const MatchFinder::MatchResult& Result) {
+  const auto *ContainingLambda =
+    Result.Nodes.getNodeAs<LambdaExpr>("containing-lambda");
+  const auto *ContainingFunc =
+    Result.Nodes.getNodeAs<FunctionDecl>("containing-func");
+  const auto *Call = Result.Nodes.getNodeAs<CallExpr>("call");
+
+  Stmt *Body = nullptr;
+  if (ContainingLambda) {
+    Body = ContainingLambda->getBody();
+  } else if (ContainingFunc) {
+    Body = ContainingFunc->getBody();
+  } else {
+    return;
+  }
+  assert(Body && "Should have a body by this point");
+
+  // Generate the CFG for the enclosing function or decl.
+  CFG::BuildOptions Options;
+  std::unique_ptr<CFG> TheCFG =
+    CFG::buildCFG(nullptr, Body, Result.Context, Options);
+  if (!TheCFG) {
+    return;
+  }
+
+  // Determine which block in the CFG we want to look at the successors of.
+  StmtToBlockMap BlockMap(TheCFG.get(), Result.Context);
+  size_t CallIndex;
+  const auto *Block = BlockMap.blockContainingStmt(Call, &CallIndex);
+  assert(Block && "This statement should be within the CFG!");
+
+  if (!immediatelyReturns(Block, Result.Context, CallIndex + 1)) {
+    diag(Call->getLocStart(),
+         "You must immediately return after calling this function",
+         DiagnosticIDs::Error);
+  }
+}
+
+bool
+MustReturnFromCallerChecker::immediatelyReturns(RecurseGuard<const CFGBlock *> Block,
+                                                ASTContext *TheContext,
+                                                size_t FromIdx) {
+  if (Block.isRepeat()) {
+    return false;
+  }
+
+  for (size_t I = FromIdx; I < Block->size(); ++I) {
+    Optional<CFGStmt> S = (*Block)[I].getAs<CFGStmt>();
+    if (!S) {
+      continue;
+    }
+
+    auto AfterTrivials = IgnoreTrivials(S->getStmt());
+
+    // If we are looking at a ConstructExpr, a DeclRefExpr or a MemberExpr it's
+    // OK to use them after a call to a MOZ_MUST_RETURN_FROM_CALLER function.
+    // It is also, of course, OK to look at a ReturnStmt.
+    if (isa<ReturnStmt>(AfterTrivials) ||
+        isa<CXXConstructExpr>(AfterTrivials) ||
+        isa<DeclRefExpr>(AfterTrivials) ||
+        isa<MemberExpr>(AfterTrivials)) {
+      continue;
+    }
+
+    // It's also OK to call any function or method which is annotated with
+    // MOZ_MAY_CALL_AFTER_MUST_RETURN. We consider all CXXConversionDecls
+    // to be MOZ_MAY_CALL_AFTER_MUST_RETURN (like operator T*()).
+    if (auto CE = dyn_cast<CallExpr>(AfterTrivials)) {
+      auto Callee = CE->getDirectCallee();
+      if (Callee && hasCustomAnnotation(Callee, "moz_may_call_after_must_return")) {
+        continue;
+      }
+
+      if (Callee && isa<CXXConversionDecl>(Callee)) {
+        continue;
+      }
+    }
+
+    // Otherwise, this expression is problematic.
+    return false;
+  }
+
+  for (auto Succ = Block->succ_begin(); Succ != Block->succ_end(); ++Succ) {
+    if (!immediatelyReturns(Block.recurse(*Succ), TheContext, 0)) {
+      return false;
+    }
+  }
+  return true;
+}
new file mode 100644
--- /dev/null
+++ b/build/clang-plugin/MustReturnFromCallerChecker.h
@@ -0,0 +1,26 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef MustReturnFromCallerChecker_h__
+#define MustReturnFromCallerChecker_h__
+
+#include "plugin.h"
+#include "Utils.h"
+#include "RecurseGuard.h"
+#include "StmtToBlockMap.h"
+
+class MustReturnFromCallerChecker : public BaseCheck {
+public:
+  MustReturnFromCallerChecker(StringRef CheckName,
+                              ContextType *Context = nullptr)
+    : BaseCheck(CheckName, Context) {}
+  void registerMatchers(MatchFinder* AstMatcher) override;
+  void check(const MatchFinder::MatchResult &Result) override;
+private:
+  bool immediatelyReturns(RecurseGuard<const CFGBlock *> Block,
+                          ASTContext *TheContext,
+                          size_t FromIdx);
+};
+
+#endif
new file mode 100644
--- /dev/null
+++ b/build/clang-plugin/RecurseGuard.h
@@ -0,0 +1,63 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef RecurseGuard_h__
+#define RecurseGuard_h__
+
+#include "Utils.h"
+
+// This class acts as a tracker for avoiding infinite recursion when traversing
+// chains in CFGs etc.
+//
+// Constructing a RecurseGuard sets up a shared backing store which tracks the
+// currently observed objects. Whenever recursing, use RecurseGuard.recurse(T)
+// to construct another RecurseGuard with the same backing store.
+//
+// The RecurseGuard object will unregister its object when it is destroyed, and
+// has a method `isRepeat()` which will return `true` if the item was already
+// seen.
+template<typename T>
+class RecurseGuard {
+public:
+  RecurseGuard(T Thing) : Thing(Thing), Set(new DenseSet<T>()), Repeat(false) {
+    Set->insert(Thing);
+  }
+  RecurseGuard(T Thing, std::shared_ptr<DenseSet<T>>& Set)
+    : Thing(Thing), Set(Set), Repeat(false) {
+    Repeat = !Set->insert(Thing).second;
+  }
+  RecurseGuard(const RecurseGuard &) = delete;
+  RecurseGuard(RecurseGuard && Other)
+    : Thing(Other.Thing), Set(Other.Set), Repeat(Other.Repeat) {
+    Other.Repeat = true;
+  }
+  ~RecurseGuard() {
+    if (!Repeat) {
+      Set->erase(Thing);
+    }
+  }
+
+  bool isRepeat() { return Repeat; }
+
+  T get() { return Thing; }
+
+  operator T() {
+    return Thing;
+  }
+
+  T operator ->() {
+    return Thing;
+  }
+
+  RecurseGuard recurse(T NewThing) {
+    return RecurseGuard(NewThing, Set);
+  }
+
+private:
+  T Thing;
+  std::shared_ptr<DenseSet<T>> Set;
+  bool Repeat;
+};
+
+#endif // RecurseGuard_h__
new file mode 100644
--- /dev/null
+++ b/build/clang-plugin/StmtToBlockMap.h
@@ -0,0 +1,86 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef StmtToBlockMap_h__
+#define StmtToBlockMap_h__
+
+#include "Utils.h"
+
+// This method is copied from clang-tidy's ExprSequence.cpp.
+//
+// Returns the Stmt nodes that are parents of 'S', skipping any potential
+// intermediate non-Stmt nodes.
+//
+// In almost all cases, this function returns a single parent or no parents at
+// all.
+inline SmallVector<const Stmt *, 1> getParentStmts(const Stmt *S,
+                                                   ASTContext *Context) {
+  SmallVector<const Stmt *, 1> Result;
+
+  ASTContext::DynTypedNodeList Parents = Context->getParents(*S);
+
+  SmallVector<ast_type_traits::DynTypedNode, 1> NodesToProcess(Parents.begin(),
+                                                               Parents.end());
+
+  while (!NodesToProcess.empty()) {
+    ast_type_traits::DynTypedNode Node = NodesToProcess.back();
+    NodesToProcess.pop_back();
+
+    if (const auto *S = Node.get<Stmt>()) {
+      Result.push_back(S);
+    } else {
+      Parents = Context->getParents(Node);
+      NodesToProcess.append(Parents.begin(), Parents.end());
+    }
+  }
+
+  return Result;
+}
+
+// This class is a modified version of the class from clang-tidy's ExprSequence.cpp
+//
+// Maps `Stmt`s to the `CFGBlock` that contains them. Some `Stmt`s may be
+// contained in more than one `CFGBlock`; in this case, they are mapped to the
+// innermost block (i.e. the one that is furthest from the root of the tree).
+// An optional outparameter provides the index into the block where the `Stmt`
+// was found.
+class StmtToBlockMap {
+public:
+  // Initializes the map for the given `CFG`.
+  StmtToBlockMap(const CFG *TheCFG, ASTContext *TheContext) : Context(TheContext) {
+    for (const auto *B : *TheCFG) {
+      for (size_t I = 0; I < B->size(); ++I) {
+        if (Optional<CFGStmt> S = (*B)[I].getAs<CFGStmt>()) {
+          Map[S->getStmt()] = std::make_pair(B, I);
+        }
+      }
+    }
+  }
+
+  // Returns the block that S is contained in. Some `Stmt`s may be contained
+  // in more than one `CFGBlock`; in this case, this function returns the
+  // innermost block (i.e. the one that is furthest from the root of the tree).
+  //
+  // The optional outparameter `Index` is set to the index into the block where
+  // the `Stmt` was found.
+  const CFGBlock *blockContainingStmt(const Stmt *S, size_t *Index = nullptr) const {
+    while (!Map.count(S)) {
+      SmallVector<const Stmt *, 1> Parents = getParentStmts(S, Context);
+      if (Parents.empty())
+        return nullptr;
+      S = Parents[0];
+    }
+
+    const auto &E = Map.lookup(S);
+    if (Index) *Index = E.second;
+    return E.first;
+  }
+
+private:
+  ASTContext *Context;
+
+  llvm::DenseMap<const Stmt *, std::pair<const CFGBlock *, size_t>> Map;
+};
+
+#endif // StmtToBlockMap_h__
--- a/build/clang-plugin/moz.build
+++ b/build/clang-plugin/moz.build
@@ -11,16 +11,17 @@ UNIFIED_SOURCES += [
     'AssertAssignmentChecker.cpp',
     'CustomTypeAnnotation.cpp',
     'DiagnosticsMatcher.cpp',
     'ExplicitImplicitChecker.cpp',
     'ExplicitOperatorBoolChecker.cpp',
     'KungFuDeathGripChecker.cpp',
     'MozCheckAction.cpp',
     'MustOverrideChecker.cpp',
+    'MustReturnFromCallerChecker.cpp',
     'MustUseChecker.cpp',
     'NaNExprChecker.cpp',
     'NeedsNoVTableTypeChecker.cpp',
     'NoAddRefReleaseOnReturnChecker.cpp',
     'NoAutoTypeChecker.cpp',
     'NoDuplicateRefCntMemberChecker.cpp',
     'NoExplicitMoveConstructorChecker.cpp',
     'NonMemMovableMemberChecker.cpp',
--- a/build/clang-plugin/plugin.h
+++ b/build/clang-plugin/plugin.h
@@ -1,15 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef plugin_h__
 #define plugin_h__
 
+#include "clang/Analysis/CFG.h"
 #include "clang/AST/ASTConsumer.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/RecursiveASTVisitor.h"
 #include "clang/ASTMatchers/ASTMatchFinder.h"
 #include "clang/ASTMatchers/ASTMatchers.h"
 #include "clang/Basic/Version.h"
 #include "clang/Frontend/CompilerInstance.h"
 #include "clang/Frontend/MultiplexConsumer.h"
new file mode 100644
--- /dev/null
+++ b/build/clang-plugin/tests/TestMustReturnFromCaller.cpp
@@ -0,0 +1,183 @@
+#include <cstddef>
+
+#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();
+
+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() {
+  Throw();
+  return 5;
+}
+
+int a4() {
+  Throw(); // expected-error {{You must immediately return after calling this function}}
+  return Condition() ? MakeAnInt() : MakeAnInt();
+}
+
+void a5() {
+  Throw(); // expected-error {{You must immediately return after calling this function}}
+  DoAnythingElse();
+}
+
+int a6() {
+  Throw(); // expected-error {{You must immediately return after calling this function}}
+  DoAnythingElse();
+  return MakeAnInt();
+}
+
+int a7() {
+  Throw(); // expected-error {{You must immediately return after calling this function}}
+  DoAnythingElse();
+  return Condition() ? MakeAnInt() : MakeAnInt();
+}
+
+int a8() {
+  Throw();
+  return SafeMakeInt();
+}
+
+int a9() {
+  if (Condition()) {
+    Throw();
+  }
+  return SafeMakeInt();
+}
+
+void b1() {
+  if (Condition()) {
+    Throw();
+  }
+}
+
+int b2() {
+  if (Condition()) {
+    Throw(); // expected-error {{You must immediately return after calling this function}}
+  }
+  return MakeAnInt();
+}
+
+int b3() {
+  if (Condition()) {
+    Throw();
+  }
+  return 5;
+}
+
+int b4() {
+  if (Condition()) {
+    Throw(); // expected-error {{You must immediately return after calling this function}}
+  }
+  return Condition() ? MakeAnInt() : MakeAnInt();
+}
+
+void b5() {
+  if (Condition()) {
+    Throw(); // expected-error {{You must immediately return after calling this function}}
+  }
+  DoAnythingElse();
+}
+
+void b6() {
+  if (Condition()) {
+    Throw(); // expected-error {{You must immediately return after calling this function}}
+    DoAnythingElse();
+  }
+}
+
+void b7() {
+  if (Condition()) {
+    Throw();
+    return;
+  }
+  DoAnythingElse();
+}
+
+void b8() {
+  if (Condition()) {
+    Throw(); // expected-error {{You must immediately return after calling this function}}
+    DoAnythingElse();
+    return;
+  }
+  DoAnythingElse();
+}
+
+void b9() {
+  while (Condition()) {
+    Throw(); // expected-error {{You must immediately return after calling this function}}
+  }
+}
+
+void b10() {
+  while (Condition()) {
+    Throw();
+    return;
+  }
+}
+
+void b11() {
+  Throw(); // expected-error {{You must immediately return after calling this function}}
+  if (Condition()) {
+    return;
+  } else {
+    return;
+  }
+}
+
+void b12() {
+  switch (MakeAnInt()) {
+  case 1:
+    break;
+  default:
+    Throw();
+    return;
+  }
+}
+
+void b13() {
+  if (Condition()) {
+    Throw();
+  }
+  return;
+}
+
+Foo b14() {
+  if (Condition()) {
+    Throw();
+    return nullptr;
+  }
+  return nullptr;
+}
+
+Foo b15() {
+  if (Condition()) {
+    Throw();
+  }
+  return nullptr;
+}
+
+Foo b16() {
+  if (Condition()) {
+    Throw();
+  }
+  return Foo();
+}
--- a/build/clang-plugin/tests/moz.build
+++ b/build/clang-plugin/tests/moz.build
@@ -13,16 +13,17 @@ SOURCES += [
     'TestCustomHeap.cpp',
     'TestExplicitOperatorBool.cpp',
     'TestGlobalClass.cpp',
     'TestHeapClass.cpp',
     'TestInheritTypeAnnotationsFromTemplateArgs.cpp',
     'TestKungFuDeathGrip.cpp',
     'TestMultipleAnnotations.cpp',
     'TestMustOverride.cpp',
+    'TestMustReturnFromCaller.cpp',
     'TestMustUse.cpp',
     'TestNANTestingExpr.cpp',
     'TestNANTestingExprC.c',
     'TestNeedsNoVTableType.cpp',
     'TestNoAddRefReleaseOnReturn.cpp',
     'TestNoArithmeticExprInArgument.cpp',
     'TestNoAutoType.cpp',
     'TestNoDuplicateRefCntMember.cpp',
--- a/mfbt/Attributes.h
+++ b/mfbt/Attributes.h
@@ -505,19 +505,28 @@
  *   member variables still remain uninitialized.
  * MOZ_NON_PARAM: Applies to types. Makes it compile time error to use the type
  *   in parameter without pointer or reference.
  * MOZ_NON_AUTOABLE: Applies to class declarations. Makes it a compile time error to
  *   use `auto` in place of this type in variable declarations.  This is intended to
  *   be used with types which are intended to be implicitly constructed into other
  *   other types before being assigned to variables.
  * MOZ_REQUIRED_BASE_METHOD: Applies to virtual class method declarations.
- *  Sometimes derived classes override methods that need to be called by their
- *  overridden counterparts. This marker indicates that the marked method must
- *  be called by the method that it overrides.
+ *   Sometimes derived classes override methods that need to be called by their
+ *   overridden counterparts. This marker indicates that the marked method must
+ *   be called by the method that it overrides.
+ * MOZ_MUST_RETURN_FROM_CALLER: Applies to function or method declarations.
+ *   Callers of the annotated function/method must return from that function
+ *   within the calling block using an explicit `return` statement.
+ *   Only calls to Constructors, references to local and member variables,
+ *   and calls to functions or methods marked as MOZ_MAY_CALL_AFTER_MUST_RETURN
+ *   may be made after the MUST_RETURN_FROM_CALLER call.
+ * MOZ_MAY_CALL_AFTER_MUST_RETURN: Applies to function or method declarations.
+ *   Calls to these methods may be made in functions after calls a
+ *   MOZ_MUST_RETURN_FROM_CALLER function or method.
  */
 #ifdef MOZ_CLANG_PLUGIN
 #  define MOZ_MUST_OVERRIDE __attribute__((annotate("moz_must_override")))
 #  define MOZ_STACK_CLASS __attribute__((annotate("moz_stack_class")))
 #  define MOZ_NONHEAP_CLASS __attribute__((annotate("moz_nonheap_class")))
 #  define MOZ_HEAP_CLASS __attribute__((annotate("moz_heap_class")))
 #  define MOZ_NON_TEMPORARY_CLASS __attribute__((annotate("moz_non_temporary_class")))
 #  define MOZ_TRIVIAL_CTOR_DTOR __attribute__((annotate("moz_trivial_ctor_dtor")))
@@ -545,16 +554,20 @@
 #  define MOZ_INIT_OUTSIDE_CTOR \
     __attribute__((annotate("moz_ignore_ctor_initialization")))
 #  define MOZ_IS_CLASS_INIT \
     __attribute__((annotate("moz_is_class_init")))
 #  define MOZ_NON_PARAM \
     __attribute__((annotate("moz_non_param")))
 #  define MOZ_REQUIRED_BASE_METHOD \
     __attribute__((annotate("moz_required_base_method")))
+#  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")))
 /*
  * It turns out that clang doesn't like void func() __attribute__ {} without a
  * warning, so use pragmas to disable the warning. This code won't work on GCC
  * anyways, so the warning is safe to ignore.
  */
 #  define MOZ_HEAP_ALLOCATOR \
     _Pragma("clang diagnostic push") \
     _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \
@@ -581,16 +594,18 @@
 #  define MOZ_NEEDS_MEMMOVABLE_TYPE /* nothing */
 #  define MOZ_NEEDS_MEMMOVABLE_MEMBERS /* nothing */
 #  define MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS /* nothing */
 #  define MOZ_INIT_OUTSIDE_CTOR /* nothing */
 #  define MOZ_IS_CLASS_INIT /* nothing */
 #  define MOZ_NON_PARAM /* nothing */
 #  define MOZ_NON_AUTOABLE /* nothing */
 #  define MOZ_REQUIRED_BASE_METHOD /* nothing */
+#  define MOZ_MUST_RETURN_FROM_CALLER /* nothing */
+#  define MOZ_MAY_CALL_AFTER_MUST_RETURN /* nothing */
 #endif /* MOZ_CLANG_PLUGIN */
 
 #define MOZ_RAII MOZ_NON_TEMPORARY_CLASS MOZ_STACK_CLASS
 
 #endif /* __cplusplus */
 
 /**
  * Printf style formats.  MOZ_FORMAT_PRINTF can be used to annotate a