Bug 1684092 - Part 2: Move [[nodiscard]] to the head of function declarations in js/src/. r=jandem
authorChris Peterson <cpeterson@mozilla.com>
Fri, 12 Feb 2021 04:09:23 +0000
changeset 567115 331046f56c0184220e20e49f419fb350fdd1b39f
parent 567114 bfaa95b5e04a36143ef2d3cff446cdda75cb5fab
child 567116 1f385759e3f5f8e8070ef7f0442562d74cbb97e8
push id38197
push usernerli@mozilla.com
push dateFri, 12 Feb 2021 10:01:55 +0000
treeherdermozilla-central@67d5bc077f46 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjandem
bugs1684092
milestone87.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 1684092 - Part 2: Move [[nodiscard]] to the head of function declarations in js/src/. r=jandem The [[nodiscard]] attribute must precede a function declaration's declaration specifiers (like static, extern, inline, or virtual). The __attribute__((warn_unused_result)) attribute does not have this order restriction. Differential Revision: https://phabricator.services.mozilla.com/D100413
js/public/BuildId.h
js/public/SourceText.h
js/public/String.h
js/public/UbiNode.h
js/public/UbiNodeCensus.h
js/public/UbiNodeDominatorTree.h
js/src/builtin/AtomicsObject.h
js/src/builtin/Eval.h
js/src/builtin/HandlerFunction-inl.h
js/src/builtin/MapObject.cpp
js/src/builtin/MapObject.h
js/src/builtin/Profilers.h
js/src/builtin/Promise.cpp
js/src/builtin/Promise.h
js/src/builtin/Reflect.h
js/src/builtin/RegExp.h
js/src/builtin/Stream.cpp
js/src/builtin/Stream.h
js/src/builtin/String.h
js/src/builtin/Symbol.h
js/src/builtin/WeakMapObject.h
js/src/builtin/WeakRefObject.h
js/src/builtin/WeakSetObject.h
js/src/builtin/intl/Collator.h
js/src/builtin/intl/DateTimeFormat.h
js/src/builtin/intl/DisplayNames.h
js/src/builtin/intl/IntlObject.h
js/src/builtin/intl/LanguageTag.h
js/src/builtin/intl/ListFormat.h
js/src/builtin/intl/Locale.h
js/src/builtin/intl/NumberFormat.h
js/src/builtin/intl/PluralRules.h
js/src/builtin/intl/RelativeTimeFormat.h
js/src/builtin/streams/MiscellaneousOperations-inl.h
js/src/builtin/streams/MiscellaneousOperations.h
js/src/builtin/streams/PipeToState-inl.h
js/src/builtin/streams/PipeToState.cpp
js/src/builtin/streams/QueueWithSizes-inl.h
js/src/builtin/streams/QueueWithSizes.h
js/src/builtin/streams/QueueingStrategies.cpp
js/src/builtin/streams/ReadableStream.cpp
js/src/builtin/streams/ReadableStream.h
js/src/builtin/streams/ReadableStreamController.h
js/src/builtin/streams/ReadableStreamDefaultControllerOperations.h
js/src/builtin/streams/ReadableStreamDefaultReader.cpp
js/src/builtin/streams/ReadableStreamInternals.h
js/src/builtin/streams/ReadableStreamOperations.cpp
js/src/builtin/streams/ReadableStreamOperations.h
js/src/builtin/streams/ReadableStreamReader-inl.h
js/src/builtin/streams/ReadableStreamReader.h
js/src/builtin/streams/StreamAPI.cpp
js/src/builtin/streams/WritableStream-inl.h
js/src/builtin/streams/WritableStream.h
js/src/builtin/streams/WritableStreamDefaultControllerOperations.cpp
js/src/builtin/streams/WritableStreamDefaultControllerOperations.h
js/src/builtin/streams/WritableStreamDefaultWriter-inl.h
js/src/builtin/streams/WritableStreamDefaultWriter.cpp
js/src/builtin/streams/WritableStreamDefaultWriter.h
js/src/builtin/streams/WritableStreamOperations.h
js/src/builtin/streams/WritableStreamWriterOperations.h
js/src/ctypes/CTypes.cpp
js/src/debugger/DebugAPI.h
js/src/debugger/DebugScript.h
js/src/debugger/Debugger.cpp
js/src/debugger/Debugger.h
js/src/debugger/Environment.h
js/src/debugger/Frame.h
js/src/debugger/Object.h
js/src/ds/InlineTable.h
js/src/ds/LifoAlloc.h
js/src/ds/PageProtectingVector.h
js/src/frontend/BytecodeCompilation.h
js/src/frontend/BytecodeEmitter.h
js/src/frontend/CompilationStencil.h
js/src/frontend/ErrorReporter.h
js/src/frontend/FoldConstants.cpp
js/src/frontend/FoldConstants.h
js/src/frontend/FullParseHandler.h
js/src/frontend/NameCollections.h
js/src/frontend/ParseNodeVerify.h
js/src/frontend/TokenKind.h
js/src/frontend/TokenStream.h
js/src/gc/Nursery.h
js/src/gc/Statistics.h
js/src/gc/WeakMap.h
js/src/irregexp/RegExpAPI.cpp
js/src/jsapi.cpp
js/src/jsapi.h
js/src/jsnum.h
js/src/shell/WasmTesting.h
js/src/shell/js.cpp
js/src/shell/jsshell.h
js/src/util/StringBuffer.h
js/src/vm/ArrayBufferObject.cpp
js/src/vm/ArrayBufferObject.h
js/src/vm/AsyncIteration.cpp
js/src/vm/AsyncIteration.h
js/src/vm/BigIntType.h
js/src/vm/BytecodeUtil.cpp
js/src/vm/BytecodeUtil.h
js/src/vm/Compartment-inl.h
js/src/vm/CompilationAndEvaluation.cpp
js/src/vm/ErrorReporting.h
js/src/vm/Iteration.cpp
js/src/vm/JSObject-inl.h
js/src/vm/JSObject.cpp
js/src/vm/JSObject.h
js/src/vm/JSScript.cpp
js/src/vm/JSScript.h
js/src/vm/List-inl.h
js/src/vm/List.h
js/src/vm/NativeObject-inl.h
js/src/vm/NativeObject.h
js/src/vm/PromiseObject.h
js/src/vm/RegExpObject.h
js/src/vm/SavedFrame.h
js/src/vm/SavedStacks.cpp
js/src/vm/Shape.h
--- a/js/public/BuildId.h
+++ b/js/public/BuildId.h
@@ -52,17 +52,17 @@ extern JS_PUBLIC_API void SetProcessBuil
  *   * the buildId defined by the embedder-provided BuildIdOp set by
  *     JS::SetProcessBuildIdOp, and
  *   * CPU feature information for the current CPU.
  *
  * Embedders may use this function to tag cached data whose validity depends
  * on having consistent buildId *and* on the CPU supporting features identical
  * to those in play when the cached data was computed.
  */
-extern MOZ_MUST_USE JS_PUBLIC_API bool GetOptimizedEncodingBuildId(
+[[nodiscard]] extern JS_PUBLIC_API bool GetOptimizedEncodingBuildId(
     BuildIdCharVector* buildId);
 
 /**
  * Script bytecode is dependent on the buildId and a few other things.
  *
  * This function produces a buildId that includes:
  *
  *   * The buildId defined by the embedder-provided BuildIdOp set by
@@ -71,14 +71,14 @@ extern MOZ_MUST_USE JS_PUBLIC_API bool G
  *     other state XDR buffers depend on.
  *
  * Note: this value may depend on runtime preferences so isn't guaranteed to be
  * stable across restarts.
  *
  * Embedders should use this function to tag transcoded bytecode.
  * See Transcoding.h.
  */
-extern MOZ_MUST_USE JS_PUBLIC_API bool GetScriptTranscodingBuildId(
+[[nodiscard]] extern JS_PUBLIC_API bool GetScriptTranscodingBuildId(
     BuildIdCharVector* buildId);
 
 }  // namespace JS
 
 #endif /* js_BuildId_h */
--- a/js/public/SourceText.h
+++ b/js/public/SourceText.h
@@ -133,19 +133,19 @@ class SourceText final {
    * If |ownership == TakeOwnership|, *this function* takes ownership of
    * |units|, *even if* this function fails, and you MUST NOT free |units|
    * yourself.  This single-owner-friendly approach reduces risk of leaks on
    * failure.
    *
    * |units| may be null if |unitsLength == 0|; if so, this will silently be
    * initialized using non-null, unowned units.
    */
-  MOZ_IS_CLASS_INIT MOZ_MUST_USE bool init(JSContext* cx, const Unit* units,
-                                           size_t unitsLength,
-                                           SourceOwnership ownership) {
+  [[nodiscard]] MOZ_IS_CLASS_INIT bool init(JSContext* cx, const Unit* units,
+                                            size_t unitsLength,
+                                            SourceOwnership ownership) {
     MOZ_ASSERT_IF(units == nullptr, unitsLength == 0);
 
     // Ideally we'd use |Unit| and not cast below, but the risk of a static
     // initializer is too great.
     static const CharT emptyString[] = {'\0'};
 
     // Initialize all fields *before* checking length.  This ensures that
     // if |ownership == SourceOwnership::TakeOwnership|, |units| will be
@@ -177,19 +177,19 @@ class SourceText final {
    *
    * (We can't just write this to accept |const CharT*|, because then in the
    * UTF-16 case this overload and the one above would be identical.  So we
    * use SFINAE to expose the |CharT| overload only if it's different.)
    */
   template <typename Char,
             typename = std::enable_if_t<std::is_same_v<Char, CharT> &&
                                         !std::is_same_v<Char, Unit>>>
-  MOZ_IS_CLASS_INIT MOZ_MUST_USE bool init(JSContext* cx, const Char* chars,
-                                           size_t charsLength,
-                                           SourceOwnership ownership) {
+  [[nodiscard]] MOZ_IS_CLASS_INIT bool init(JSContext* cx, const Char* chars,
+                                            size_t charsLength,
+                                            SourceOwnership ownership) {
     return init(cx, reinterpret_cast<const Unit*>(chars), charsLength,
                 ownership);
   }
 
   /**
    * Initialize this using source units transferred out of |data|.
    */
   [[nodiscard]] bool init(JSContext* cx,
--- a/js/public/String.h
+++ b/js/public/String.h
@@ -188,38 +188,38 @@ MOZ_ALWAYS_INLINE void LossyCopyLinearSt
 }
 
 /**
  * Copy characters in |s[start..start + len]| to |dest[0..len]|.
  *
  * This function is fallible.  If you already have a linear string, use the
  * infallible |JS::CopyLinearStringChars| above instead.
  */
-inline MOZ_MUST_USE bool CopyStringChars(JSContext* cx, char16_t* dest,
-                                         JSString* s, size_t len,
-                                         size_t start = 0) {
+[[nodiscard]] inline bool CopyStringChars(JSContext* cx, char16_t* dest,
+                                          JSString* s, size_t len,
+                                          size_t start = 0) {
   JSLinearString* linear = StringToLinearString(cx, s);
   if (!linear) {
     return false;
   }
 
   CopyLinearStringChars(dest, linear, len, start);
   return true;
 }
 
 /**
  * Copy characters in |s[start..start + len]| to |dest[0..len]|, lossily
  * truncating 16-bit values to |char| if necessary.
  *
  * This function is fallible.  If you already have a linear string, use the
  * infallible |JS::LossyCopyLinearStringChars| above instead.
  */
-inline MOZ_MUST_USE bool LossyCopyStringChars(JSContext* cx, char* dest,
-                                              JSString* s, size_t len,
-                                              size_t start = 0) {
+[[nodiscard]] inline bool LossyCopyStringChars(JSContext* cx, char* dest,
+                                               JSString* s, size_t len,
+                                               size_t start = 0) {
   JSLinearString* linear = StringToLinearString(cx, s);
   if (!linear) {
     return false;
   }
 
   LossyCopyLinearStringChars(dest, linear, len, start);
   return true;
 }
--- a/js/public/UbiNode.h
+++ b/js/public/UbiNode.h
@@ -289,17 +289,17 @@ class BaseStackFrame {
   //         V
   //     SavedFrame
   //
   // is lossy because we cannot serialize and deserialize the SavedFrame's
   // principals in the offline heap snapshot, so JS::ubi::StackFrame
   // simplifies the principals check into the boolean isSystem() state. This
   // is fine because we only expose JS::ubi::Stack to devtools and chrome
   // code, and not to the web platform.
-  virtual MOZ_MUST_USE bool constructSavedFrameStack(
+  [[nodiscard]] virtual bool constructSavedFrameStack(
       JSContext* cx, MutableHandleObject outSavedFrameStack) const = 0;
 
   // Trace the concrete implementation of JS::ubi::StackFrame.
   virtual void trace(JSTracer* trc) = 0;
 };
 
 // A traits template with a specialization for each backing type that implements
 // the ubi::BaseStackFrame interface. Each specialization must be the a subclass
--- a/js/public/UbiNodeCensus.h
+++ b/js/public/UbiNodeCensus.h
@@ -104,24 +104,24 @@ struct CountType {
   // to this type. Return a nullptr on OOM.
   virtual CountBasePtr makeCount() = 0;
 
   // Trace |count| and all its children, for garbage collection.
   virtual void traceCount(CountBase& count, JSTracer* trc) = 0;
 
   // Implement the 'count' method for counts returned by this CountType
   // instance's 'newCount' method.
-  virtual MOZ_MUST_USE bool count(CountBase& count,
-                                  mozilla::MallocSizeOf mallocSizeOf,
-                                  const Node& node) = 0;
+  [[nodiscard]] virtual bool count(CountBase& count,
+                                   mozilla::MallocSizeOf mallocSizeOf,
+                                   const Node& node) = 0;
 
   // Implement the 'report' method for counts returned by this CountType
   // instance's 'newCount' method.
-  virtual MOZ_MUST_USE bool report(JSContext* cx, CountBase& count,
-                                   MutableHandleValue report) = 0;
+  [[nodiscard]] virtual bool report(JSContext* cx, CountBase& count,
+                                    MutableHandleValue report) = 0;
 };
 
 using CountTypePtr = js::UniquePtr<CountType>;
 
 // An abstract base class for count tree nodes.
 class CountBase {
   // In lieu of a vtable, each CountBase points to its type, which
   // carries not only the implementations of the CountBase methods, but also
--- a/js/public/UbiNodeDominatorTree.h
+++ b/js/public/UbiNodeDominatorTree.h
@@ -317,20 +317,20 @@ class JS_PUBLIC_API DominatorTree {
         finger2 = doms[finger2];
       }
     }
     return finger1;
   }
 
   // Do the post order traversal of the heap graph and populate our
   // predecessor sets.
-  static MOZ_MUST_USE bool doTraversal(JSContext* cx, AutoCheckCannotGC& noGC,
-                                       const Node& root,
-                                       JS::ubi::Vector<Node>& postOrder,
-                                       PredecessorSets& predecessorSets) {
+  [[nodiscard]] static bool doTraversal(JSContext* cx, AutoCheckCannotGC& noGC,
+                                        const Node& root,
+                                        JS::ubi::Vector<Node>& postOrder,
+                                        PredecessorSets& predecessorSets) {
     uint32_t nodeCount = 0;
     auto onNode = [&](const Node& node) {
       nodeCount++;
       if (MOZ_UNLIKELY(nodeCount == UINT32_MAX)) {
         return false;
       }
       return postOrder.append(node);
     };
@@ -349,33 +349,33 @@ class JS_PUBLIC_API DominatorTree {
     };
 
     PostOrder traversal(cx, noGC);
     return traversal.addStart(root) && traversal.traverse(onNode, onEdge);
   }
 
   // Populates the given `map` with an entry for each node to its index in
   // `postOrder`.
-  static MOZ_MUST_USE bool mapNodesToTheirIndices(
+  [[nodiscard]] static bool mapNodesToTheirIndices(
       JS::ubi::Vector<Node>& postOrder, NodeToIndexMap& map) {
     MOZ_ASSERT(map.empty());
     MOZ_ASSERT(postOrder.length() < UINT32_MAX);
     uint32_t length = postOrder.length();
     if (!map.reserve(length)) {
       return false;
     }
     for (uint32_t i = 0; i < length; i++) {
       map.putNewInfallible(postOrder[i], i);
     }
     return true;
   }
 
   // Convert the Node -> NodeSet predecessorSets to a index -> Vector<index>
   // form.
-  static MOZ_MUST_USE bool convertPredecessorSetsToVectors(
+  [[nodiscard]] static bool convertPredecessorSetsToVectors(
       const Node& root, JS::ubi::Vector<Node>& postOrder,
       PredecessorSets& predecessorSets, NodeToIndexMap& nodeToPostOrderIndex,
       JS::ubi::Vector<JS::ubi::Vector<uint32_t>>& predecessorVectors) {
     MOZ_ASSERT(postOrder.length() < UINT32_MAX);
     uint32_t length = postOrder.length();
 
     MOZ_ASSERT(predecessorVectors.length() == 0);
     if (!predecessorVectors.growBy(length)) {
@@ -405,18 +405,18 @@ class JS_PUBLIC_API DominatorTree {
       }
     }
     predecessorSets.clearAndCompact();
     return true;
   }
 
   // Initialize `doms` such that the immediate dominator of the `root` is the
   // `root` itself and all others are `UNDEFINED`.
-  static MOZ_MUST_USE bool initializeDominators(JS::ubi::Vector<uint32_t>& doms,
-                                                uint32_t length) {
+  [[nodiscard]] static bool initializeDominators(
+      JS::ubi::Vector<uint32_t>& doms, uint32_t length) {
     MOZ_ASSERT(doms.length() == 0);
     if (!doms.growByUninitialized(length)) {
       return false;
     }
     doms[length - 1] = length - 1;
     for (uint32_t i = 0; i < length - 1; i++) {
       doms[i] = UNDEFINED;
     }
--- a/js/src/builtin/AtomicsObject.h
+++ b/js/src/builtin/AtomicsObject.h
@@ -24,17 +24,17 @@ class AtomicsObject : public NativeObjec
  public:
   static const JSClass class_;
 };
 
 class FutexThread {
   friend class AutoLockFutexAPI;
 
  public:
-  static MOZ_MUST_USE bool initialize();
+  [[nodiscard]] static bool initialize();
   static void destroy();
 
   static void lock();
   static void unlock();
 
   FutexThread();
   [[nodiscard]] bool initInstance();
   void destroyInstance();
--- a/js/src/builtin/Eval.h
+++ b/js/src/builtin/Eval.h
@@ -13,22 +13,22 @@
 
 namespace js {
 
 // The C++ native for 'eval' (ES5 15.1.2.1). The function is named "indirect
 // eval" because "direct eval" calls (as defined by the spec) will emit
 // JSOp::Eval which in turn calls DirectEval. Thus, even though IndirectEval is
 // the callee function object for *all* calls to eval, it is by construction
 // only ever called in the case indirect eval.
-extern MOZ_MUST_USE bool IndirectEval(JSContext* cx, unsigned argc, Value* vp);
+[[nodiscard]] extern bool IndirectEval(JSContext* cx, unsigned argc, Value* vp);
 
 // Performs a direct eval of |v| (a string containing code, or another value
 // that will be vacuously returned), which must correspond to the currently-
 // executing stack frame, which must be a script frame.
-extern MOZ_MUST_USE bool DirectEval(JSContext* cx, HandleValue v,
-                                    MutableHandleValue vp);
+[[nodiscard]] extern bool DirectEval(JSContext* cx, HandleValue v,
+                                     MutableHandleValue vp);
 
 // True iff fun is a built-in eval function.
 extern bool IsAnyBuiltinEval(JSFunction* fun);
 
 }  // namespace js
 
 #endif /* builtin_Eval_h */
--- a/js/src/builtin/HandlerFunction-inl.h
+++ b/js/src/builtin/HandlerFunction-inl.h
@@ -35,79 +35,79 @@ namespace js {
 // extended slots.
 constexpr size_t HandlerFunctionSlot_Target = 0;
 constexpr size_t HandlerFunctionSlot_Extra = 1;
 
 static_assert(HandlerFunctionSlot_Extra < FunctionExtended::NUM_EXTENDED_SLOTS,
               "handler function slots shouldn't exceed available extended "
               "slots");
 
-inline MOZ_MUST_USE JSFunction* NewHandler(JSContext* cx, Native handler,
-                                           JS::Handle<JSObject*> target) {
+[[nodiscard]] inline JSFunction* NewHandler(JSContext* cx, Native handler,
+                                            JS::Handle<JSObject*> target) {
   cx->check(target);
 
   JS::Handle<PropertyName*> funName = cx->names().empty;
   JS::Rooted<JSFunction*> handlerFun(
       cx, NewNativeFunction(cx, handler, 0, funName,
                             gc::AllocKind::FUNCTION_EXTENDED, GenericObject));
   if (!handlerFun) {
     return nullptr;
   }
   handlerFun->setExtendedSlot(HandlerFunctionSlot_Target,
                               JS::ObjectValue(*target));
   return handlerFun;
 }
 
-inline MOZ_MUST_USE JSFunction* NewHandlerWithExtra(
+[[nodiscard]] inline JSFunction* NewHandlerWithExtra(
     JSContext* cx, Native handler, JS::Handle<JSObject*> target,
     JS::Handle<JSObject*> extra) {
   cx->check(extra);
   JSFunction* handlerFun = NewHandler(cx, handler, target);
   if (handlerFun) {
     handlerFun->setExtendedSlot(HandlerFunctionSlot_Extra,
                                 JS::ObjectValue(*extra));
   }
   return handlerFun;
 }
 
-inline MOZ_MUST_USE JSFunction* NewHandlerWithExtraValue(
+[[nodiscard]] inline JSFunction* NewHandlerWithExtraValue(
     JSContext* cx, Native handler, JS::Handle<JSObject*> target,
     JS::Handle<JS::Value> extra) {
   cx->check(extra);
   JSFunction* handlerFun = NewHandler(cx, handler, target);
   if (handlerFun) {
     handlerFun->setExtendedSlot(HandlerFunctionSlot_Extra, extra);
   }
   return handlerFun;
 }
 
 /**
  * Within the call of a handler function that "closes over" a target value that
  * is always a |T*| object (and never a wrapper around one), return that |T*|.
  */
 template <class T>
-inline MOZ_MUST_USE T* TargetFromHandler(const JS::CallArgs& args) {
+[[nodiscard]] inline T* TargetFromHandler(const JS::CallArgs& args) {
   JSFunction& func = args.callee().as<JSFunction>();
   return &func.getExtendedSlot(HandlerFunctionSlot_Target).toObject().as<T>();
 }
 
 /**
  * Within the call of a handler function that "closes over" a target value and
  * an extra value, return that extra value.
  */
-inline MOZ_MUST_USE JS::Value ExtraValueFromHandler(const JS::CallArgs& args) {
+[[nodiscard]] inline JS::Value ExtraValueFromHandler(const JS::CallArgs& args) {
   JSFunction& func = args.callee().as<JSFunction>();
   return func.getExtendedSlot(HandlerFunctionSlot_Extra);
 }
 
 /**
  * Within the call of a handler function that "closes over" a target value and
  * an extra value, where that extra value is always a |T*| object (and never a
  * wrapper around one), return that |T*|.
  */
 template <class T>
-inline MOZ_MUST_USE T* ExtraFromHandler(const JS::CallArgs& args) {
+[[nodiscard]] inline T* ExtraFromHandler(const JS::CallArgs& args) {
   return &ExtraValueFromHandler(args).toObject().as<T>();
 }
 
 }  // namespace js
 
 #endif  // builtin_HandlerFunction_inl_h
--- a/js/src/builtin/MapObject.cpp
+++ b/js/src/builtin/MapObject.cpp
@@ -531,18 +531,18 @@ class js::OrderedHashTableRef : public g
       TraceManuallyBarrieredEdge(trc, &key, "ordered hash table key");
       unbarrieredTable->rekeyOneEntry(prior, key);
     }
     DeleteNurseryKeys(object);
   }
 };
 
 template <typename ObjectT>
-inline static MOZ_MUST_USE bool PostWriteBarrierImpl(ObjectT* obj,
-                                                     const Value& keyValue) {
+[[nodiscard]] inline static bool PostWriteBarrierImpl(ObjectT* obj,
+                                                      const Value& keyValue) {
   if (MOZ_LIKELY(!keyValue.isObject() && !keyValue.isBigInt())) {
     MOZ_ASSERT_IF(keyValue.isGCThing(), !IsInsideNursery(keyValue.toGCThing()));
     return true;
   }
 
   if (IsInsideNursery(obj)) {
     return true;
   }
@@ -560,23 +560,23 @@ inline static MOZ_MUST_USE bool PostWrit
 
     keyValue.toGCThing()->storeBuffer()->putGeneric(
         OrderedHashTableRef<ObjectT>(obj));
   }
 
   return keys->append(keyValue);
 }
 
-inline static MOZ_MUST_USE bool PostWriteBarrier(MapObject* map,
-                                                 const Value& key) {
+[[nodiscard]] inline static bool PostWriteBarrier(MapObject* map,
+                                                  const Value& key) {
   return PostWriteBarrierImpl(map, key);
 }
 
-inline static MOZ_MUST_USE bool PostWriteBarrier(SetObject* set,
-                                                 const Value& key) {
+[[nodiscard]] inline static bool PostWriteBarrier(SetObject* set,
+                                                  const Value& key) {
   return PostWriteBarrierImpl(set, key);
 }
 
 bool MapObject::getKeysAndValuesInterleaved(
     HandleObject obj, JS::MutableHandle<GCVector<JS::Value>> entries) {
   ValueMap* map = obj->as<MapObject>().getData();
   if (!map) {
     return false;
--- a/js/src/builtin/MapObject.h
+++ b/js/src/builtin/MapObject.h
@@ -108,39 +108,39 @@ class MapObject : public NativeObject {
       "IteratorKind Entries must match self-hosting define for item kind "
       "key-and-value.");
 
   static const JSClass class_;
   static const JSClass protoClass_;
 
   enum { NurseryKeysSlot, HasNurseryMemorySlot, SlotCount };
 
-  static MOZ_MUST_USE bool getKeysAndValuesInterleaved(
+  [[nodiscard]] static bool getKeysAndValuesInterleaved(
       HandleObject obj, JS::MutableHandle<GCVector<JS::Value>> entries);
-  static MOZ_MUST_USE bool entries(JSContext* cx, unsigned argc, Value* vp);
+  [[nodiscard]] static bool entries(JSContext* cx, unsigned argc, Value* vp);
   static MapObject* create(JSContext* cx, HandleObject proto = nullptr);
 
   // Publicly exposed Map calls for JSAPI access (webidl maplike/setlike
   // interfaces, etc.)
   static uint32_t size(JSContext* cx, HandleObject obj);
-  static MOZ_MUST_USE bool get(JSContext* cx, HandleObject obj, HandleValue key,
-                               MutableHandleValue rval);
-  static MOZ_MUST_USE bool has(JSContext* cx, HandleObject obj, HandleValue key,
-                               bool* rval);
-  static MOZ_MUST_USE bool delete_(JSContext* cx, HandleObject obj,
-                                   HandleValue key, bool* rval);
+  [[nodiscard]] static bool get(JSContext* cx, HandleObject obj,
+                                HandleValue key, MutableHandleValue rval);
+  [[nodiscard]] static bool has(JSContext* cx, HandleObject obj,
+                                HandleValue key, bool* rval);
+  [[nodiscard]] static bool delete_(JSContext* cx, HandleObject obj,
+                                    HandleValue key, bool* rval);
 
   // Set call for public JSAPI exposure. Does not actually return map object
   // as stated in spec, expects caller to return a value. for instance, with
   // webidl maplike/setlike, should return interface object.
-  static MOZ_MUST_USE bool set(JSContext* cx, HandleObject obj, HandleValue key,
-                               HandleValue val);
-  static MOZ_MUST_USE bool clear(JSContext* cx, HandleObject obj);
-  static MOZ_MUST_USE bool iterator(JSContext* cx, IteratorKind kind,
-                                    HandleObject obj, MutableHandleValue iter);
+  [[nodiscard]] static bool set(JSContext* cx, HandleObject obj,
+                                HandleValue key, HandleValue val);
+  [[nodiscard]] static bool clear(JSContext* cx, HandleObject obj);
+  [[nodiscard]] static bool iterator(JSContext* cx, IteratorKind kind,
+                                     HandleObject obj, MutableHandleValue iter);
 
   using UnbarrieredTable =
       OrderedHashMap<Value, Value, UnbarrieredHashPolicy, ZoneAllocPolicy>;
   friend class OrderedHashTableRef<MapObject>;
 
   static void sweepAfterMinorGC(JSFreeOp* fop, MapObject* mapobj);
 
  private:
@@ -153,41 +153,41 @@ class MapObject : public NativeObject {
 
   static bool finishInit(JSContext* cx, HandleObject ctor, HandleObject proto);
 
   ValueMap* getData() { return static_cast<ValueMap*>(getPrivate()); }
   static ValueMap& extract(HandleObject o);
   static ValueMap& extract(const CallArgs& args);
   static void trace(JSTracer* trc, JSObject* obj);
   static void finalize(JSFreeOp* fop, JSObject* obj);
-  static MOZ_MUST_USE bool construct(JSContext* cx, unsigned argc, Value* vp);
+  [[nodiscard]] static bool construct(JSContext* cx, unsigned argc, Value* vp);
 
   static bool is(HandleValue v);
   static bool is(HandleObject o);
 
-  static MOZ_MUST_USE bool iterator_impl(JSContext* cx, const CallArgs& args,
-                                         IteratorKind kind);
+  [[nodiscard]] static bool iterator_impl(JSContext* cx, const CallArgs& args,
+                                          IteratorKind kind);
 
-  static MOZ_MUST_USE bool size_impl(JSContext* cx, const CallArgs& args);
-  static MOZ_MUST_USE bool size(JSContext* cx, unsigned argc, Value* vp);
-  static MOZ_MUST_USE bool get_impl(JSContext* cx, const CallArgs& args);
-  static MOZ_MUST_USE bool get(JSContext* cx, unsigned argc, Value* vp);
-  static MOZ_MUST_USE bool has_impl(JSContext* cx, const CallArgs& args);
-  static MOZ_MUST_USE bool has(JSContext* cx, unsigned argc, Value* vp);
-  static MOZ_MUST_USE bool set_impl(JSContext* cx, const CallArgs& args);
-  static MOZ_MUST_USE bool set(JSContext* cx, unsigned argc, Value* vp);
-  static MOZ_MUST_USE bool delete_impl(JSContext* cx, const CallArgs& args);
-  static MOZ_MUST_USE bool delete_(JSContext* cx, unsigned argc, Value* vp);
-  static MOZ_MUST_USE bool keys_impl(JSContext* cx, const CallArgs& args);
-  static MOZ_MUST_USE bool keys(JSContext* cx, unsigned argc, Value* vp);
-  static MOZ_MUST_USE bool values_impl(JSContext* cx, const CallArgs& args);
-  static MOZ_MUST_USE bool values(JSContext* cx, unsigned argc, Value* vp);
-  static MOZ_MUST_USE bool entries_impl(JSContext* cx, const CallArgs& args);
-  static MOZ_MUST_USE bool clear_impl(JSContext* cx, const CallArgs& args);
-  static MOZ_MUST_USE bool clear(JSContext* cx, unsigned argc, Value* vp);
+  [[nodiscard]] static bool size_impl(JSContext* cx, const CallArgs& args);
+  [[nodiscard]] static bool size(JSContext* cx, unsigned argc, Value* vp);
+  [[nodiscard]] static bool get_impl(JSContext* cx, const CallArgs& args);
+  [[nodiscard]] static bool get(JSContext* cx, unsigned argc, Value* vp);
+  [[nodiscard]] static bool has_impl(JSContext* cx, const CallArgs& args);
+  [[nodiscard]] static bool has(JSContext* cx, unsigned argc, Value* vp);
+  [[nodiscard]] static bool set_impl(JSContext* cx, const CallArgs& args);
+  [[nodiscard]] static bool set(JSContext* cx, unsigned argc, Value* vp);
+  [[nodiscard]] static bool delete_impl(JSContext* cx, const CallArgs& args);
+  [[nodiscard]] static bool delete_(JSContext* cx, unsigned argc, Value* vp);
+  [[nodiscard]] static bool keys_impl(JSContext* cx, const CallArgs& args);
+  [[nodiscard]] static bool keys(JSContext* cx, unsigned argc, Value* vp);
+  [[nodiscard]] static bool values_impl(JSContext* cx, const CallArgs& args);
+  [[nodiscard]] static bool values(JSContext* cx, unsigned argc, Value* vp);
+  [[nodiscard]] static bool entries_impl(JSContext* cx, const CallArgs& args);
+  [[nodiscard]] static bool clear_impl(JSContext* cx, const CallArgs& args);
+  [[nodiscard]] static bool clear(JSContext* cx, unsigned argc, Value* vp);
 };
 
 class MapIteratorObject : public NativeObject {
  public:
   static const JSClass class_;
 
   enum { TargetSlot, RangeSlot, KindSlot, SlotCount };
 
@@ -208,18 +208,18 @@ class MapIteratorObject : public NativeO
   static size_t objectMoved(JSObject* obj, JSObject* old);
 
   void init(MapObject* mapObj, MapObject::IteratorKind kind) {
     initFixedSlot(TargetSlot, JS::ObjectValue(*mapObj));
     initFixedSlot(RangeSlot, JS::PrivateValue(nullptr));
     initFixedSlot(KindSlot, JS::Int32Value(int32_t(kind)));
   }
 
-  static MOZ_MUST_USE bool next(MapIteratorObject* mapIterator,
-                                ArrayObject* resultPairObj);
+  [[nodiscard]] static bool next(MapIteratorObject* mapIterator,
+                                 ArrayObject* resultPairObj);
 
   static JSObject* createResultPair(JSContext* cx);
 
  private:
   inline MapObject::IteratorKind kind() const;
 };
 
 class SetObject : public NativeObject {
@@ -237,33 +237,33 @@ class SetObject : public NativeObject {
       "IteratorKind Entries must match self-hosting define for item kind "
       "key-and-value.");
 
   static const JSClass class_;
   static const JSClass protoClass_;
 
   enum { NurseryKeysSlot, HasNurseryMemorySlot, SlotCount };
 
-  static MOZ_MUST_USE bool keys(JSContext* cx, HandleObject obj,
-                                JS::MutableHandle<GCVector<JS::Value>> keys);
-  static MOZ_MUST_USE bool values(JSContext* cx, unsigned argc, Value* vp);
-  static MOZ_MUST_USE bool add(JSContext* cx, HandleObject obj,
-                               HandleValue key);
+  [[nodiscard]] static bool keys(JSContext* cx, HandleObject obj,
+                                 JS::MutableHandle<GCVector<JS::Value>> keys);
+  [[nodiscard]] static bool values(JSContext* cx, unsigned argc, Value* vp);
+  [[nodiscard]] static bool add(JSContext* cx, HandleObject obj,
+                                HandleValue key);
 
   // Publicly exposed Set calls for JSAPI access (webidl maplike/setlike
   // interfaces, etc.)
   static SetObject* create(JSContext* cx, HandleObject proto = nullptr);
   static uint32_t size(JSContext* cx, HandleObject obj);
-  static MOZ_MUST_USE bool has(JSContext* cx, HandleObject obj, HandleValue key,
-                               bool* rval);
-  static MOZ_MUST_USE bool clear(JSContext* cx, HandleObject obj);
-  static MOZ_MUST_USE bool iterator(JSContext* cx, IteratorKind kind,
-                                    HandleObject obj, MutableHandleValue iter);
-  static MOZ_MUST_USE bool delete_(JSContext* cx, HandleObject obj,
-                                   HandleValue key, bool* rval);
+  [[nodiscard]] static bool has(JSContext* cx, HandleObject obj,
+                                HandleValue key, bool* rval);
+  [[nodiscard]] static bool clear(JSContext* cx, HandleObject obj);
+  [[nodiscard]] static bool iterator(JSContext* cx, IteratorKind kind,
+                                     HandleObject obj, MutableHandleValue iter);
+  [[nodiscard]] static bool delete_(JSContext* cx, HandleObject obj,
+                                    HandleValue key, bool* rval);
 
   using UnbarrieredTable =
       OrderedHashSet<Value, UnbarrieredHashPolicy, ZoneAllocPolicy>;
   friend class OrderedHashTableRef<SetObject>;
 
   static void sweepAfterMinorGC(JSFreeOp* fop, SetObject* setobj);
 
  private:
@@ -283,32 +283,32 @@ class SetObject : public NativeObject {
   static void finalize(JSFreeOp* fop, JSObject* obj);
   static bool construct(JSContext* cx, unsigned argc, Value* vp);
 
   static bool is(HandleValue v);
   static bool is(HandleObject o);
 
   static bool isBuiltinAdd(HandleValue add);
 
-  static MOZ_MUST_USE bool iterator_impl(JSContext* cx, const CallArgs& args,
-                                         IteratorKind kind);
+  [[nodiscard]] static bool iterator_impl(JSContext* cx, const CallArgs& args,
+                                          IteratorKind kind);
 
-  static MOZ_MUST_USE bool size_impl(JSContext* cx, const CallArgs& args);
-  static MOZ_MUST_USE bool size(JSContext* cx, unsigned argc, Value* vp);
-  static MOZ_MUST_USE bool has_impl(JSContext* cx, const CallArgs& args);
-  static MOZ_MUST_USE bool has(JSContext* cx, unsigned argc, Value* vp);
-  static MOZ_MUST_USE bool add_impl(JSContext* cx, const CallArgs& args);
-  static MOZ_MUST_USE bool add(JSContext* cx, unsigned argc, Value* vp);
-  static MOZ_MUST_USE bool delete_impl(JSContext* cx, const CallArgs& args);
-  static MOZ_MUST_USE bool delete_(JSContext* cx, unsigned argc, Value* vp);
-  static MOZ_MUST_USE bool values_impl(JSContext* cx, const CallArgs& args);
-  static MOZ_MUST_USE bool entries_impl(JSContext* cx, const CallArgs& args);
-  static MOZ_MUST_USE bool entries(JSContext* cx, unsigned argc, Value* vp);
-  static MOZ_MUST_USE bool clear_impl(JSContext* cx, const CallArgs& args);
-  static MOZ_MUST_USE bool clear(JSContext* cx, unsigned argc, Value* vp);
+  [[nodiscard]] static bool size_impl(JSContext* cx, const CallArgs& args);
+  [[nodiscard]] static bool size(JSContext* cx, unsigned argc, Value* vp);
+  [[nodiscard]] static bool has_impl(JSContext* cx, const CallArgs& args);
+  [[nodiscard]] static bool has(JSContext* cx, unsigned argc, Value* vp);
+  [[nodiscard]] static bool add_impl(JSContext* cx, const CallArgs& args);
+  [[nodiscard]] static bool add(JSContext* cx, unsigned argc, Value* vp);
+  [[nodiscard]] static bool delete_impl(JSContext* cx, const CallArgs& args);
+  [[nodiscard]] static bool delete_(JSContext* cx, unsigned argc, Value* vp);
+  [[nodiscard]] static bool values_impl(JSContext* cx, const CallArgs& args);
+  [[nodiscard]] static bool entries_impl(JSContext* cx, const CallArgs& args);
+  [[nodiscard]] static bool entries(JSContext* cx, unsigned argc, Value* vp);
+  [[nodiscard]] static bool clear_impl(JSContext* cx, const CallArgs& args);
+  [[nodiscard]] static bool clear(JSContext* cx, unsigned argc, Value* vp);
 };
 
 class SetIteratorObject : public NativeObject {
  public:
   static const JSClass class_;
 
   enum { TargetSlot, RangeSlot, KindSlot, SlotCount };
 
@@ -329,34 +329,34 @@ class SetIteratorObject : public NativeO
   static size_t objectMoved(JSObject* obj, JSObject* old);
 
   void init(SetObject* setObj, SetObject::IteratorKind kind) {
     initFixedSlot(TargetSlot, JS::ObjectValue(*setObj));
     initFixedSlot(RangeSlot, JS::PrivateValue(nullptr));
     initFixedSlot(KindSlot, JS::Int32Value(int32_t(kind)));
   }
 
-  static MOZ_MUST_USE bool next(SetIteratorObject* setIterator,
-                                ArrayObject* resultObj);
+  [[nodiscard]] static bool next(SetIteratorObject* setIterator,
+                                 ArrayObject* resultObj);
 
   static JSObject* createResult(JSContext* cx);
 
  private:
   inline SetObject::IteratorKind kind() const;
 };
 
 using SetInitGetPrototypeOp = NativeObject* (*)(JSContext*,
                                                 Handle<GlobalObject*>);
 using SetInitIsBuiltinOp = bool (*)(HandleValue);
 
 template <SetInitGetPrototypeOp getPrototypeOp, SetInitIsBuiltinOp isBuiltinOp>
-static MOZ_MUST_USE bool IsOptimizableInitForSet(JSContext* cx,
-                                                 HandleObject setObject,
-                                                 HandleValue iterable,
-                                                 bool* optimized) {
+[[nodiscard]] static bool IsOptimizableInitForSet(JSContext* cx,
+                                                  HandleObject setObject,
+                                                  HandleValue iterable,
+                                                  bool* optimized) {
   MOZ_ASSERT(!*optimized);
 
   if (!iterable.isObject()) {
     return true;
   }
 
   RootedObject array(cx, &iterable.toObject());
   if (!IsPackedArray(array)) {
--- a/js/src/builtin/Profilers.h
+++ b/js/src/builtin/Profilers.h
@@ -24,65 +24,65 @@ typedef int pid_t;
  *
  * The profileName is used by some profilers to describe the current profiling
  * run. It may be used for part of the filename of the output, but the
  * specifics depend on the profiler. Many profilers will ignore it. Passing in
  * nullptr is legal; some profilers may use it to output to stdout or similar.
  *
  * Returns true if no profilers fail to start.
  */
-extern MOZ_MUST_USE JS_PUBLIC_API bool JS_StartProfiling(
+[[nodiscard]] extern JS_PUBLIC_API bool JS_StartProfiling(
     const char* profileName, pid_t pid);
 
 /**
  * Stop any profilers that were previously started with JS_StartProfiling.
  * Returns true if no profilers fail to stop.
  */
-extern MOZ_MUST_USE JS_PUBLIC_API bool JS_StopProfiling(
+[[nodiscard]] extern JS_PUBLIC_API bool JS_StopProfiling(
     const char* profileName);
 
 /**
  * Write the current profile data to the given file, if applicable to whatever
  * profiler is being used.
  */
-extern MOZ_MUST_USE JS_PUBLIC_API bool JS_DumpProfile(const char* outfile,
-                                                      const char* profileName);
+[[nodiscard]] extern JS_PUBLIC_API bool JS_DumpProfile(const char* outfile,
+                                                       const char* profileName);
 
 /**
  * Pause currently active profilers (only supported by some profilers). Returns
  * whether any profilers failed to pause. (Profilers that do not support
  * pause/resume do not count.)
  */
-extern MOZ_MUST_USE JS_PUBLIC_API bool JS_PauseProfilers(
+[[nodiscard]] extern JS_PUBLIC_API bool JS_PauseProfilers(
     const char* profileName);
 
 /**
  * Resume suspended profilers
  */
-extern MOZ_MUST_USE JS_PUBLIC_API bool JS_ResumeProfilers(
+[[nodiscard]] extern JS_PUBLIC_API bool JS_ResumeProfilers(
     const char* profileName);
 
 /**
  * The profiling API calls are not able to report errors, so they use a
  * thread-unsafe global memory buffer to hold the last error encountered. This
  * should only be called after something returns false.
  */
 JS_PUBLIC_API const char* JS_UnsafeGetLastProfilingError();
 
 #ifdef MOZ_CALLGRIND
 
-extern MOZ_MUST_USE JS_FRIEND_API bool js_StopCallgrind();
+[[nodiscard]] extern JS_FRIEND_API bool js_StopCallgrind();
 
-extern MOZ_MUST_USE JS_FRIEND_API bool js_StartCallgrind();
+[[nodiscard]] extern JS_FRIEND_API bool js_StartCallgrind();
 
-extern MOZ_MUST_USE JS_FRIEND_API bool js_DumpCallgrind(const char* outfile);
+[[nodiscard]] extern JS_FRIEND_API bool js_DumpCallgrind(const char* outfile);
 
 #endif /* MOZ_CALLGRIND */
 
 #ifdef __linux__
 
-extern MOZ_MUST_USE JS_FRIEND_API bool js_StartPerf();
+[[nodiscard]] extern JS_FRIEND_API bool js_StartPerf();
 
-extern MOZ_MUST_USE JS_FRIEND_API bool js_StopPerf();
+[[nodiscard]] extern JS_FRIEND_API bool js_StopPerf();
 
 #endif /* __linux__ */
 
 #endif /* builtin_Profilers_h */
--- a/js/src/builtin/Promise.cpp
+++ b/js/src/builtin/Promise.cpp
@@ -583,17 +583,17 @@ static bool MaybeGetAndClearExceptionAnd
                                               MutableHandleSavedFrame stack) {
   if (!cx->isExceptionPending()) {
     return false;
   }
 
   return GetAndClearExceptionAndStack(cx, rval, stack);
 }
 
-static MOZ_MUST_USE bool RunRejectFunction(
+[[nodiscard]] static bool RunRejectFunction(
     JSContext* cx, HandleObject onRejectedFunc, HandleValue result,
     HandleObject promiseObj, HandleSavedFrame unwrappedRejectionStack,
     UnhandledRejectionBehavior behavior);
 
 // ES2016, 25.4.1.1.1, Steps 1.a-b.
 // Extracting all of this internal spec algorithm into a helper function would
 // be tedious, so the check in step 1 and the entirety of step 2 aren't
 // included.
@@ -860,17 +860,17 @@ static void RemovePromiseFlags(PromiseOb
 static bool PromiseHasAnyFlag(PromiseObject& promise, int32_t flag) {
   return promise.flags() & flag;
 }
 
 static bool ResolvePromiseFunction(JSContext* cx, unsigned argc, Value* vp);
 static bool RejectPromiseFunction(JSContext* cx, unsigned argc, Value* vp);
 
 // ES2016, 25.4.1.3.
-static MOZ_MUST_USE MOZ_ALWAYS_INLINE bool CreateResolvingFunctions(
+[[nodiscard]] static MOZ_ALWAYS_INLINE bool CreateResolvingFunctions(
     JSContext* cx, HandleObject promise, MutableHandleObject resolveFn,
     MutableHandleObject rejectFn) {
   HandlePropertyName funName = cx->names().empty;
   resolveFn.set(NewNativeFunction(cx, ResolvePromiseFunction, 1, funName,
                                   gc::AllocKind::FUNCTION_EXTENDED,
                                   GenericObject));
   if (!resolveFn) {
     return false;
@@ -910,22 +910,22 @@ static bool IsSettledMaybeWrappedPromise
       return false;
     }
   }
 
   return promise->as<PromiseObject>().state() != JS::PromiseState::Pending;
 }
 
 // ES2016, 25.4.1.7.
-static MOZ_MUST_USE bool RejectMaybeWrappedPromise(
+[[nodiscard]] static bool RejectMaybeWrappedPromise(
     JSContext* cx, HandleObject promiseObj, HandleValue reason,
     HandleSavedFrame unwrappedRejectionStack);
 
 // ES2016, 25.4.1.7.
-static MOZ_MUST_USE bool RejectPromiseInternal(
+[[nodiscard]] static bool RejectPromiseInternal(
     JSContext* cx, Handle<PromiseObject*> promise, HandleValue reason,
     HandleSavedFrame unwrappedRejectionStack = nullptr);
 
 // ES2016, 25.4.1.3.1.
 static bool RejectPromiseFunction(JSContext* cx, unsigned argc, Value* vp) {
   CallArgs args = CallArgsFromVp(argc, vp);
 
   JSFunction* reject = &args.callee().as<JSFunction>();
@@ -962,35 +962,35 @@ static bool RejectPromiseFunction(JSCont
   // Step 6.
   if (!RejectMaybeWrappedPromise(cx, promise, reasonVal, nullptr)) {
     return false;
   }
   args.rval().setUndefined();
   return true;
 }
 
-static MOZ_MUST_USE bool FulfillMaybeWrappedPromise(JSContext* cx,
-                                                    HandleObject promiseObj,
-                                                    HandleValue value_);
-
-static MOZ_MUST_USE bool EnqueuePromiseResolveThenableJob(
+[[nodiscard]] static bool FulfillMaybeWrappedPromise(JSContext* cx,
+                                                     HandleObject promiseObj,
+                                                     HandleValue value_);
+
+[[nodiscard]] static bool EnqueuePromiseResolveThenableJob(
     JSContext* cx, HandleValue promiseToResolve, HandleValue thenable,
     HandleValue thenVal);
 
-static MOZ_MUST_USE bool EnqueuePromiseResolveThenableBuiltinJob(
+[[nodiscard]] static bool EnqueuePromiseResolveThenableBuiltinJob(
     JSContext* cx, HandleObject promiseToResolve, HandleObject thenable);
 
 static bool Promise_then_impl(JSContext* cx, HandleValue promiseVal,
                               HandleValue onFulfilled, HandleValue onRejected,
                               MutableHandleValue rval, bool rvalUsed);
 
 // ES2016, 25.4.1.3.2, steps 6-13.
-static MOZ_MUST_USE bool ResolvePromiseInternal(JSContext* cx,
-                                                HandleObject promise,
-                                                HandleValue resolutionVal) {
+[[nodiscard]] static bool ResolvePromiseInternal(JSContext* cx,
+                                                 HandleObject promise,
+                                                 HandleValue resolutionVal) {
   cx->check(promise, resolutionVal);
   MOZ_ASSERT(!IsSettledMaybeWrappedPromise(promise));
 
   // Step 7 (reordered).
   if (!resolutionVal.isObject()) {
     return FulfillMaybeWrappedPromise(cx, promise, resolutionVal);
   }
 
@@ -1255,28 +1255,28 @@ static bool PromiseReactionJob(JSContext
   // Note: the global we pass here might be from a different compartment
   // than job and promise. While it's somewhat unusual to pass objects
   // from multiple compartments, in this case we specifically need the
   // global to be unwrapped because wrapping and unwrapping aren't
   // necessarily symmetric for globals.
   return cx->runtime()->enqueuePromiseJob(cx, job, promise, global);
 }
 
-static MOZ_MUST_USE bool TriggerPromiseReactions(JSContext* cx,
-                                                 HandleValue reactionsVal,
-                                                 JS::PromiseState state,
-                                                 HandleValue valueOrReason);
+[[nodiscard]] static bool TriggerPromiseReactions(JSContext* cx,
+                                                  HandleValue reactionsVal,
+                                                  JS::PromiseState state,
+                                                  HandleValue valueOrReason);
 
 // ES2016, Commoned-out implementation of 25.4.1.4. and 25.4.1.7.
 //
 // This method takes an additional optional |unwrappedRejectionStack| parameter,
 // which is only used for debugging purposes.
 // It allows callers to to pass in the stack of some exception which
 // triggered the rejection of the promise.
-static MOZ_MUST_USE bool ResolvePromise(
+[[nodiscard]] static bool ResolvePromise(
     JSContext* cx, Handle<PromiseObject*> promise, HandleValue valueOrReason,
     JS::PromiseState state,
     HandleSavedFrame unwrappedRejectionStack = nullptr) {
   // Step 1.
   MOZ_ASSERT(promise->state() == JS::PromiseState::Pending);
   MOZ_ASSERT(state == JS::PromiseState::Fulfilled ||
              state == JS::PromiseState::Rejected);
   MOZ_ASSERT_IF(unwrappedRejectionStack, state == JS::PromiseState::Rejected);
@@ -1309,27 +1309,27 @@ static MOZ_MUST_USE bool ResolvePromise(
   PromiseObject::onSettled(cx, promise, unwrappedRejectionStack);
 
   // Step 7 of FulfillPromise.
   // Step 8 of RejectPromise.
   return TriggerPromiseReactions(cx, reactionsVal, state, valueOrReason);
 }
 
 // ES2016, 25.4.1.7.
-static MOZ_MUST_USE bool RejectPromiseInternal(
+[[nodiscard]] static bool RejectPromiseInternal(
     JSContext* cx, Handle<PromiseObject*> promise, HandleValue reason,
     HandleSavedFrame unwrappedRejectionStack) {
   return ResolvePromise(cx, promise, reason, JS::PromiseState::Rejected,
                         unwrappedRejectionStack);
 }
 
 // ES2016, 25.4.1.4.
-static MOZ_MUST_USE bool FulfillMaybeWrappedPromise(JSContext* cx,
-                                                    HandleObject promiseObj,
-                                                    HandleValue value_) {
+[[nodiscard]] static bool FulfillMaybeWrappedPromise(JSContext* cx,
+                                                     HandleObject promiseObj,
+                                                     HandleValue value_) {
   Rooted<PromiseObject*> promise(cx);
   RootedValue value(cx, value_);
 
   mozilla::Maybe<AutoRealm> ar;
   if (!IsProxy(promiseObj)) {
     promise = &promiseObj->as<PromiseObject>();
   } else {
     JSObject* unwrappedPromiseObj = UncheckedUnwrap(promiseObj);
@@ -1345,37 +1345,37 @@ static MOZ_MUST_USE bool FulfillMaybeWra
     }
   }
 
   return ResolvePromise(cx, promise, value, JS::PromiseState::Fulfilled);
 }
 
 static bool GetCapabilitiesExecutor(JSContext* cx, unsigned argc, Value* vp);
 static bool PromiseConstructor(JSContext* cx, unsigned argc, Value* vp);
-static MOZ_MUST_USE PromiseObject* CreatePromiseObjectInternal(
+[[nodiscard]] static PromiseObject* CreatePromiseObjectInternal(
     JSContext* cx, HandleObject proto = nullptr, bool protoIsWrapped = false,
     bool informDebugger = true);
 
 enum GetCapabilitiesExecutorSlots {
   GetCapabilitiesExecutorSlots_Resolve,
   GetCapabilitiesExecutorSlots_Reject
 };
 
-static MOZ_MUST_USE PromiseObject*
+[[nodiscard]] static PromiseObject*
 CreatePromiseObjectWithoutResolutionFunctions(JSContext* cx) {
   PromiseObject* promise = CreatePromiseObjectInternal(cx);
   if (!promise) {
     return nullptr;
   }
 
   AddPromiseFlags(*promise, PROMISE_FLAG_DEFAULT_RESOLVING_FUNCTIONS);
   return promise;
 }
 
-static MOZ_MUST_USE PromiseObject* CreatePromiseWithDefaultResolutionFunctions(
+[[nodiscard]] static PromiseObject* CreatePromiseWithDefaultResolutionFunctions(
     JSContext* cx, MutableHandleObject resolve, MutableHandleObject reject) {
   // ES2016, 25.4.3.1., as if called with GetCapabilitiesExecutor as the
   // executor argument.
 
   // Steps 1-2 (Not applicable).
 
   // Steps 3-7.
   Rooted<PromiseObject*> promise(cx, CreatePromiseObjectInternal(cx));
@@ -1392,17 +1392,17 @@ static MOZ_MUST_USE PromiseObject* Creat
 
   // Steps 9-10 (Not applicable).
 
   // Step 11.
   return promise;
 }
 
 // ES2016, 25.4.1.5.
-static MOZ_MUST_USE bool NewPromiseCapability(
+[[nodiscard]] static bool NewPromiseCapability(
     JSContext* cx, HandleObject C, MutableHandle<PromiseCapability> capability,
     bool canOmitResolutionFunctions) {
   RootedValue cVal(cx, ObjectValue(*C));
 
   // Steps 1-2.
   if (!IsConstructor(C)) {
     ReportValueError(cx, JSMSG_NOT_CONSTRUCTOR, JSDVG_SEARCH_STACK, cVal,
                      nullptr);
@@ -1507,17 +1507,17 @@ static bool GetCapabilitiesExecutor(JSCo
   F->setExtendedSlot(GetCapabilitiesExecutorSlots_Reject, args.get(1));
 
   // Step 7.
   args.rval().setUndefined();
   return true;
 }
 
 // ES2016, 25.4.1.7.
-static MOZ_MUST_USE bool RejectMaybeWrappedPromise(
+[[nodiscard]] static bool RejectMaybeWrappedPromise(
     JSContext* cx, HandleObject promiseObj, HandleValue reason_,
     HandleSavedFrame unwrappedRejectionStack) {
   Rooted<PromiseObject*> promise(cx);
   RootedValue reason(cx, reason_);
 
   mozilla::Maybe<AutoRealm> ar;
   if (!IsProxy(promiseObj)) {
     promise = &promiseObj->as<PromiseObject>();
@@ -1606,37 +1606,37 @@ static bool ForEachReaction(JSContext* c
       return false;
     }
   }
 
   return true;
 }
 
 // ES2016, 25.4.1.8.
-static MOZ_MUST_USE bool TriggerPromiseReactions(JSContext* cx,
-                                                 HandleValue reactionsVal,
-                                                 JS::PromiseState state,
-                                                 HandleValue valueOrReason) {
+[[nodiscard]] static bool TriggerPromiseReactions(JSContext* cx,
+                                                  HandleValue reactionsVal,
+                                                  JS::PromiseState state,
+                                                  HandleValue valueOrReason) {
   MOZ_ASSERT(state == JS::PromiseState::Fulfilled ||
              state == JS::PromiseState::Rejected);
 
   return ForEachReaction(cx, reactionsVal, [&](MutableHandleObject reaction) {
     return EnqueuePromiseReactionJob(cx, reaction, valueOrReason, state);
   });
 }
 
-static MOZ_MUST_USE bool RunFulfillFunction(JSContext* cx,
-                                            HandleObject onFulfilledFunc,
-                                            HandleValue result,
-                                            HandleObject promiseObj);
+[[nodiscard]] static bool RunFulfillFunction(JSContext* cx,
+                                             HandleObject onFulfilledFunc,
+                                             HandleValue result,
+                                             HandleObject promiseObj);
 
 // Implements PromiseReactionJob optimized for the case when the reaction
 // handler is one of the default resolving functions as created by the
 // CreateResolvingFunctions abstract operation.
-static MOZ_MUST_USE bool DefaultResolvingPromiseReactionJob(
+[[nodiscard]] static bool DefaultResolvingPromiseReactionJob(
     JSContext* cx, Handle<PromiseReactionRecord*> reaction) {
   MOZ_ASSERT(reaction->targetState() != JS::PromiseState::Pending);
 
   Rooted<PromiseObject*> promiseToResolve(cx,
                                           reaction->defaultResolvingPromise());
 
   // Testing functions allow to directly settle a promise without going
   // through the resolving functions. In that case the normal bookkeeping to
@@ -1678,17 +1678,17 @@ static MOZ_MUST_USE bool DefaultResolvin
 
   callee = reaction->getFixedSlot(ReactionRecordSlot_Reject).toObjectOrNull();
 
   return RunRejectFunction(cx, callee, handlerResult, promiseObj,
                            unwrappedRejectionStack,
                            reaction->unhandledRejectionBehavior());
 }
 
-static MOZ_MUST_USE bool AsyncFunctionPromiseReactionJob(
+[[nodiscard]] static bool AsyncFunctionPromiseReactionJob(
     JSContext* cx, Handle<PromiseReactionRecord*> reaction) {
   MOZ_ASSERT(reaction->isAsyncFunction());
 
   int32_t handler = reaction->handler().toInt32();
   RootedValue argument(cx, reaction->handlerArg());
   Rooted<AsyncFunctionGeneratorObject*> generator(
       cx, reaction->asyncFunctionGenerator());
 
@@ -1698,17 +1698,17 @@ static MOZ_MUST_USE bool AsyncFunctionPr
   if (handler == PromiseHandlerAsyncFunctionAwaitedFulfilled) {
     return AsyncFunctionAwaitedFulfilled(cx, generator, argument);
   }
 
   MOZ_ASSERT(handler == PromiseHandlerAsyncFunctionAwaitedRejected);
   return AsyncFunctionAwaitedRejected(cx, generator, argument);
 }
 
-static MOZ_MUST_USE bool AsyncGeneratorPromiseReactionJob(
+[[nodiscard]] static bool AsyncGeneratorPromiseReactionJob(
     JSContext* cx, Handle<PromiseReactionRecord*> reaction) {
   MOZ_ASSERT(reaction->isAsyncGenerator());
 
   RootedValue argument(cx, reaction->handlerArg());
   Rooted<AsyncGeneratorObject*> asyncGenObj(cx, reaction->asyncGenerator());
 
   // Await's handlers don't return a value, nor throw any exceptions.
   // They fail only on OOM.
@@ -1982,17 +1982,17 @@ static bool PromiseResolveThenableJob(JS
   if (!MaybeGetAndClearExceptionAndStack(cx, &rval, &stack)) {
     return false;
   }
 
   RootedValue rejectVal(cx, ObjectValue(*rejectFn));
   return Call(cx, rejectVal, UndefinedHandleValue, rval, &rval);
 }
 
-static MOZ_MUST_USE bool OriginalPromiseThenWithoutSettleHandlers(
+[[nodiscard]] static bool OriginalPromiseThenWithoutSettleHandlers(
     JSContext* cx, Handle<PromiseObject*> promise,
     Handle<PromiseObject*> promiseToResolve);
 
 /**
  * Specialization of PromiseResolveThenableJob when the `thenable` is a
  * built-in Promise object and the `then` property is the built-in
  * `Promise.prototype.then` function.
  *
@@ -2048,17 +2048,17 @@ static bool PromiseResolveBuiltinThenabl
 
 /**
  * Tells the embedding to enqueue a Promise resolve thenable job, based on
  * three parameters:
  * promiseToResolve_ - The promise to resolve, obviously.
  * thenable_ - The thenable to resolve the Promise with.
  * thenVal - The `then` function to invoke with the `thenable` as the receiver.
  */
-static MOZ_MUST_USE bool EnqueuePromiseResolveThenableJob(
+[[nodiscard]] static bool EnqueuePromiseResolveThenableJob(
     JSContext* cx, HandleValue promiseToResolve_, HandleValue thenable_,
     HandleValue thenVal) {
   // Need to re-root these to enable wrapping them below.
   RootedValue promiseToResolve(cx, promiseToResolve_);
   RootedValue thenable(cx, thenable_);
 
   // We enter the `then` callable's compartment so that the job function is
   // created in that compartment.
@@ -2116,17 +2116,17 @@ static MOZ_MUST_USE bool EnqueuePromiseR
 }
 
 /**
  * Tells the embedding to enqueue a Promise resolve thenable built-in job,
  * based on two parameters:
  * promiseToResolve - The promise to resolve, obviously.
  * thenable - The thenable to resolve the Promise with.
  */
-static MOZ_MUST_USE bool EnqueuePromiseResolveThenableBuiltinJob(
+[[nodiscard]] static bool EnqueuePromiseResolveThenableBuiltinJob(
     JSContext* cx, HandleObject promiseToResolve, HandleObject thenable) {
   cx->check(promiseToResolve, thenable);
   MOZ_ASSERT(promiseToResolve->is<PromiseObject>());
   MOZ_ASSERT(thenable->is<PromiseObject>());
 
   HandlePropertyName funName = cx->names().empty;
   RootedFunction job(
       cx, NewNativeFunction(cx, PromiseResolveBuiltinThenableJob, 0, funName,
@@ -2141,21 +2141,21 @@ static MOZ_MUST_USE bool EnqueuePromiseR
   job->setExtendedSlot(BuiltinThenableJobSlot_Thenable, ObjectValue(*thenable));
 
   Rooted<GlobalObject*> incumbentGlobal(cx,
                                         cx->runtime()->getIncumbentGlobal(cx));
   return cx->runtime()->enqueuePromiseJob(cx, job, promiseToResolve,
                                           incumbentGlobal);
 }
 
-static MOZ_MUST_USE bool AddDummyPromiseReactionForDebugger(
+[[nodiscard]] static bool AddDummyPromiseReactionForDebugger(
     JSContext* cx, Handle<PromiseObject*> promise,
     HandleObject dependentPromise);
 
-static MOZ_MUST_USE bool AddPromiseReaction(
+[[nodiscard]] static bool AddPromiseReaction(
     JSContext* cx, Handle<PromiseObject*> promise,
     Handle<PromiseReactionRecord*> reaction);
 
 static JSFunction* GetResolveFunctionFromReject(JSFunction* reject) {
   MOZ_ASSERT(reject->maybeNative() == RejectPromiseFunction);
   Value resolveFunVal =
       reject->getExtendedSlot(RejectFunctionSlot_ResolveFunction);
   MOZ_ASSERT(IsNativeFunction(resolveFunVal, ResolvePromiseFunction));
@@ -2220,17 +2220,17 @@ static void ClearResolutionFunctionSlots
   resolve->setExtendedSlot(ResolveFunctionSlot_RejectFunction,
                            UndefinedValue());
 
   reject->setExtendedSlot(RejectFunctionSlot_Promise, UndefinedValue());
   reject->setExtendedSlot(RejectFunctionSlot_ResolveFunction, UndefinedValue());
 }
 
 // ES2016, 25.4.3.1. steps 3-7.
-static MOZ_MUST_USE MOZ_ALWAYS_INLINE PromiseObject*
+[[nodiscard]] static MOZ_ALWAYS_INLINE PromiseObject*
 CreatePromiseObjectInternal(JSContext* cx, HandleObject proto /* = nullptr */,
                             bool protoIsWrapped /* = false */,
                             bool informDebugger /* = true */) {
   // Step 3.
   // Enter the unwrapped proto's compartment, if that's different from
   // the current one.
   // All state stored in a Promise's fixed slots must be created in the
   // same compartment, so we get all of that out of the way here.
@@ -2482,32 +2482,32 @@ class MOZ_STACK_CLASS PromiseForOfIterat
   using JS::ForOfIterator::ForOfIterator;
 
   bool isOptimizedDenseArrayIteration() {
     MOZ_ASSERT(valueIsIterable());
     return index != NOT_ARRAY && IsPackedArray(iterator);
   }
 };
 
-static MOZ_MUST_USE bool PerformPromiseAll(
+[[nodiscard]] static bool PerformPromiseAll(
     JSContext* cx, PromiseForOfIterator& iterator, HandleObject C,
     Handle<PromiseCapability> resultCapability, HandleValue promiseResolve,
     bool* done);
 
-static MOZ_MUST_USE bool PerformPromiseAllSettled(
+[[nodiscard]] static bool PerformPromiseAllSettled(
     JSContext* cx, PromiseForOfIterator& iterator, HandleObject C,
     Handle<PromiseCapability> resultCapability, HandleValue promiseResolve,
     bool* done);
 
-static MOZ_MUST_USE bool PerformPromiseAny(
+[[nodiscard]] static bool PerformPromiseAny(
     JSContext* cx, PromiseForOfIterator& iterator, HandleObject C,
     Handle<PromiseCapability> resultCapability, HandleValue promiseResolve,
     bool* done);
 
-static MOZ_MUST_USE bool PerformPromiseRace(
+[[nodiscard]] static bool PerformPromiseRace(
     JSContext* cx, PromiseForOfIterator& iterator, HandleObject C,
     Handle<PromiseCapability> resultCapability, HandleValue promiseResolve,
     bool* done);
 
 enum class CombinatorKind { All, AllSettled, Any, Race };
 
 // ES2020 draft rev e97c95d064750fb949b6778584702dd658cf5624
 //
@@ -2515,18 +2515,18 @@ enum class CombinatorKind { All, AllSett
 // 25.6.4.1 Promise.all ( iterable )
 // 25.6.4.2 Promise.allSettled ( iterable )
 // 25.6.4.4 Promise.race ( iterable )
 //
 // Promise.any (Stage 3 proposal)
 // https://tc39.es/proposal-promise-any/
 //
 // Promise.any ( iterable )
-static MOZ_MUST_USE bool CommonPromiseCombinator(JSContext* cx, CallArgs& args,
-                                                 CombinatorKind kind) {
+[[nodiscard]] static bool CommonPromiseCombinator(JSContext* cx, CallArgs& args,
+                                                  CombinatorKind kind) {
   HandleValue iterable = args.get(0);
 
   // Step 2 (moved from NewPromiseCapability, step 1).
   HandleValue CVal = args.thisv();
   if (!CVal.isObject()) {
     const char* message;
     switch (kind) {
       case CombinatorKind::All:
@@ -2649,21 +2649,21 @@ static MOZ_MUST_USE bool CommonPromiseCo
 
 // ES2020 draft rev dc1e21c454bd316810be1c0e7af0131a2d7f38e9
 // 25.6.4.1 Promise.all ( iterable )
 static bool Promise_static_all(JSContext* cx, unsigned argc, Value* vp) {
   CallArgs args = CallArgsFromVp(argc, vp);
   return CommonPromiseCombinator(cx, args, CombinatorKind::All);
 }
 
-static MOZ_MUST_USE bool PerformPromiseThen(
+[[nodiscard]] static bool PerformPromiseThen(
     JSContext* cx, Handle<PromiseObject*> promise, HandleValue onFulfilled_,
     HandleValue onRejected_, Handle<PromiseCapability> resultCapability);
 
-static MOZ_MUST_USE bool PerformPromiseThenWithoutSettleHandlers(
+[[nodiscard]] static bool PerformPromiseThenWithoutSettleHandlers(
     JSContext* cx, Handle<PromiseObject*> promise,
     Handle<PromiseObject*> promiseToResolve,
     Handle<PromiseCapability> resultCapability);
 
 static JSFunction* NewPromiseCombinatorElementFunction(
     JSContext* cx, Native native,
     Handle<PromiseCombinatorDataHolder*> dataHolder, uint32_t index);
 
@@ -2792,20 +2792,20 @@ static bool PromiseAllResolveElementFunc
   }
 
   // Step 8 (omitted).
 
   // Step 9.
   return resultCapability.promise();
 }
 
-static MOZ_MUST_USE bool RunFulfillFunction(JSContext* cx,
-                                            HandleObject onFulfilledFunc,
-                                            HandleValue result,
-                                            HandleObject promiseObj) {
+[[nodiscard]] static bool RunFulfillFunction(JSContext* cx,
+                                             HandleObject onFulfilledFunc,
+                                             HandleValue result,
+                                             HandleObject promiseObj) {
   cx->check(onFulfilledFunc);
   cx->check(result);
   cx->check(promiseObj);
 
   // If |onFulfilledFunc| couldn't be optimized away, just call it.
   if (onFulfilledFunc) {
     RootedValue calleeOrRval(cx, ObjectValue(*onFulfilledFunc));
     return Call(cx, calleeOrRval, UndefinedHandleValue, result, &calleeOrRval);
@@ -2826,17 +2826,17 @@ static MOZ_MUST_USE bool RunFulfillFunct
   if (PromiseHasAnyFlag(*promise, PROMISE_FLAG_DEFAULT_RESOLVING_FUNCTIONS)) {
     return ResolvePromiseInternal(cx, promise, result);
   }
 
   // Otherwise we're done.
   return true;
 }
 
-static MOZ_MUST_USE bool RunRejectFunction(
+[[nodiscard]] static bool RunRejectFunction(
     JSContext* cx, HandleObject onRejectedFunc, HandleValue result,
     HandleObject promiseObj, HandleSavedFrame unwrappedRejectionStack,
     UnhandledRejectionBehavior behavior) {
   cx->check(onRejectedFunc);
   cx->check(result);
   cx->check(promiseObj);
 
   // If |onRejectedFunc| couldn't be optimized away, just call it.
@@ -2875,32 +2875,32 @@ static MOZ_MUST_USE bool RunRejectFuncti
   if (PromiseHasAnyFlag(*promise, PROMISE_FLAG_DEFAULT_RESOLVING_FUNCTIONS)) {
     return RejectPromiseInternal(cx, promise, result, unwrappedRejectionStack);
   }
 
   // Otherwise we're done.
   return true;
 }
 
-static MOZ_MUST_USE JSObject* CommonStaticResolveRejectImpl(
+[[nodiscard]] static JSObject* CommonStaticResolveRejectImpl(
     JSContext* cx, HandleValue thisVal, HandleValue argVal,
     ResolutionMode mode);
 
 static bool IsPromiseSpecies(JSContext* cx, JSFunction* species);
 
 // ES2020 draft rev e97c95d064750fb949b6778584702dd658cf5624
 // 25.6.4.1.1 Runtime Semantics: PerformPromiseAll, steps 5-6 and step 8.
 // 25.6.4.2.1 Runtime Semantics: PerformPromiseAllSettled, steps 5-6 and step 8.
 // 25.6.4.4.1 Runtime Semantics: PerformPromiseRace, steps 3-5.
 //
 // Promise.any (Stage 3 proposal)
 // https://tc39.es/proposal-promise-any/
 // Runtime Semantics: PerformPromiseAny, steps 6-8.
 template <typename T>
-static MOZ_MUST_USE bool CommonPerformPromiseCombinator(
+[[nodiscard]] static bool CommonPerformPromiseCombinator(
     JSContext* cx, PromiseForOfIterator& iterator, HandleObject C,
     HandleObject resultPromise, HandleValue promiseResolve, bool* done,
     bool resolveReturnsUndefined, T getResolveAndReject) {
   RootedObject promiseCtor(
       cx, GlobalObject::getOrCreatePromiseConstructor(cx, cx->global()));
   if (!promiseCtor) {
     return false;
   }
@@ -3173,17 +3173,17 @@ static MOZ_MUST_USE bool CommonPerformPr
         }
       }
     }
   }
 }
 
 // Create the elements for the Promise combinators Promise.all and
 // Promise.allSettled.
-static MOZ_MUST_USE bool NewPromiseCombinatorElements(
+[[nodiscard]] static bool NewPromiseCombinatorElements(
     JSContext* cx, Handle<PromiseCapability> resultCapability,
     MutableHandle<PromiseCombinatorElements> elements) {
   // We have to be very careful about which compartments we create things for
   // the Promise combinators. In particular, we have to maintain the invariant
   // that anything stored in a reserved slot is same-compartment with the object
   // whose reserved slot it's in. But we want to create the values array in the
   // compartment of the result capability's Promise, because that array can get
   // exposed as the Promise's resolution value to code that has access to the
@@ -3225,17 +3225,17 @@ static MOZ_MUST_USE bool NewPromiseCombi
     }
 
     elements.initialize(array);
   }
   return true;
 }
 
 // Retrieve the combinator elements from the data holder.
-static MOZ_MUST_USE bool GetPromiseCombinatorElements(
+[[nodiscard]] static bool GetPromiseCombinatorElements(
     JSContext* cx, Handle<PromiseCombinatorDataHolder*> data,
     MutableHandle<PromiseCombinatorElements> elements) {
   bool needsWrapping = false;
   JSObject* valuesObj = &data->valuesArray().toObject();
   if (IsProxy(valuesObj)) {
     // See comment for NewPromiseCombinatorElements for why we unwrap here.
     valuesObj = UncheckedUnwrap(valuesObj);
 
@@ -3306,17 +3306,17 @@ static bool PromiseCombinatorElementFunc
   MOZ_ASSERT(idx >= 0);
   *index = uint32_t(idx);
 
   return false;
 }
 
 // ES2020 draft rev dc1e21c454bd316810be1c0e7af0131a2d7f38e9
 // 25.6.4.1.1 PerformPromiseAll (iteratorRecord, constructor, resultCapability)
-static MOZ_MUST_USE bool PerformPromiseAll(
+[[nodiscard]] static bool PerformPromiseAll(
     JSContext* cx, PromiseForOfIterator& iterator, HandleObject C,
     Handle<PromiseCapability> resultCapability, HandleValue promiseResolve,
     bool* done) {
   *done = false;
 
   // Step 1.
   MOZ_ASSERT(C->isConstructor());
 
@@ -3443,17 +3443,17 @@ static bool PromiseAllResolveElementFunc
 // 25.6.4.3 Promise.race ( iterable )
 static bool Promise_static_race(JSContext* cx, unsigned argc, Value* vp) {
   CallArgs args = CallArgsFromVp(argc, vp);
   return CommonPromiseCombinator(cx, args, CombinatorKind::Race);
 }
 
 // ES2020 draft rev dc1e21c454bd316810be1c0e7af0131a2d7f38e9
 // 25.6.4.3.1 PerformPromiseRace (iteratorRecord, constructor, resultCapability)
-static MOZ_MUST_USE bool PerformPromiseRace(
+[[nodiscard]] static bool PerformPromiseRace(
     JSContext* cx, PromiseForOfIterator& iterator, HandleObject C,
     Handle<PromiseCapability> resultCapability, HandleValue promiseResolve,
     bool* done) {
   *done = false;
 
   // Step 1.
   MOZ_ASSERT(C->isConstructor());
 
@@ -3498,17 +3498,17 @@ static bool Promise_static_allSettled(JS
   CallArgs args = CallArgsFromVp(argc, vp);
   return CommonPromiseCombinator(cx, args, CombinatorKind::AllSettled);
 }
 
 // ES2020 draft rev e97c95d064750fb949b6778584702dd658cf5624
 // 25.6.4.2 Promise.allSettled ( iterable )
 //
 // PerformPromiseAllSettled ( iteratorRecord, constructor, resultCapability )
-static MOZ_MUST_USE bool PerformPromiseAllSettled(
+[[nodiscard]] static bool PerformPromiseAllSettled(
     JSContext* cx, PromiseForOfIterator& iterator, HandleObject C,
     Handle<PromiseCapability> resultCapability, HandleValue promiseResolve,
     bool* done) {
   *done = false;
 
   // Step 1.
   MOZ_ASSERT(C->isConstructor());
 
@@ -3709,17 +3709,17 @@ static bool PromiseAnyRejectElementFunct
 static void ThrowAggregateError(JSContext* cx,
                                 Handle<PromiseCombinatorElements> errors,
                                 HandleObject promise);
 
 // Promise.any (Stage 3 proposal)
 // https://tc39.es/proposal-promise-any/
 //
 // PerformPromiseAny ( iteratorRecord, constructor, resultCapability )
-static MOZ_MUST_USE bool PerformPromiseAny(
+[[nodiscard]] static bool PerformPromiseAny(
     JSContext* cx, PromiseForOfIterator& iterator, HandleObject C,
     Handle<PromiseCapability> resultCapability, HandleValue promiseResolve,
     bool* done) {
   *done = false;
 
   // Step 1.
   MOZ_ASSERT(C->isConstructor());
 
@@ -3915,17 +3915,17 @@ static void ThrowAggregateError(JSContex
 }
 
 // https://tc39.github.io/ecma262/#sec-promise.reject
 //
 // Unified implementation of
 // 25.6.4.4 Promise.reject ( r )
 // 25.6.4.5 Promise.resolve ( x )
 // 25.6.4.5.1 PromiseResolve ( C, x )
-static MOZ_MUST_USE JSObject* CommonStaticResolveRejectImpl(
+[[nodiscard]] static JSObject* CommonStaticResolveRejectImpl(
     JSContext* cx, HandleValue thisVal, HandleValue argVal,
     ResolutionMode mode) {
   // Steps 1-2 of Promise.reject and Promise.resolve.
   // Step 1: Let C be the this value.
   // Step 2: If Type(C) is not Object, throw a TypeError exception.
   if (!thisVal.isObject()) {
     const char* msg = mode == ResolveMode ? "Receiver of Promise.resolve call"
                                           : "Receiver of Promise.reject call";
@@ -4326,17 +4326,17 @@ static bool PromiseThenNewPromiseCapabil
                             resultCapability)) {
       return nullptr;
     }
   }
 
   return newPromise;
 }
 
-static MOZ_MUST_USE bool OriginalPromiseThenWithoutSettleHandlers(
+[[nodiscard]] static bool OriginalPromiseThenWithoutSettleHandlers(
     JSContext* cx, Handle<PromiseObject*> promise,
     Handle<PromiseObject*> promiseToResolve) {
   cx->check(promise);
 
   // Steps 3-4.
   Rooted<PromiseCapability> resultCapability(cx);
   if (!PromiseThenNewPromiseCapability(
           cx, promise, CreateDependentPromise::SkipIfCtorUnobservable,
@@ -4344,17 +4344,17 @@ static MOZ_MUST_USE bool OriginalPromise
     return false;
   }
 
   // Step 5.
   return PerformPromiseThenWithoutSettleHandlers(cx, promise, promiseToResolve,
                                                  resultCapability);
 }
 
-static MOZ_MUST_USE bool PerformPromiseThenWithReaction(
+[[nodiscard]] static bool PerformPromiseThenWithReaction(
     JSContext* cx, Handle<PromiseObject*> promise,
     Handle<PromiseReactionRecord*> reaction);
 
 [[nodiscard]] bool js::ReactToUnwrappedPromise(
     JSContext* cx, Handle<PromiseObject*> unwrappedPromise,
     HandleObject onFulfilled_, HandleObject onRejected_,
     UnhandledRejectionBehavior behavior) {
   cx->check(onFulfilled_);
@@ -4465,17 +4465,17 @@ static bool OriginalPromiseThenBuiltin(J
   return promise;
 }
 
 bool js::IsPromiseForAsyncFunctionOrGenerator(JSObject* promise) {
   return promise->is<PromiseObject>() &&
          PromiseHasAnyFlag(promise->as<PromiseObject>(), PROMISE_FLAG_ASYNC);
 }
 
-static MOZ_MUST_USE PromiseObject* CreatePromiseObjectForAsyncGenerator(
+[[nodiscard]] static PromiseObject* CreatePromiseObjectForAsyncGenerator(
     JSContext* cx) {
   PromiseObject* promise = CreatePromiseObjectWithoutResolutionFunctions(cx);
   if (!promise) {
     return nullptr;
   }
 
   AddPromiseFlags(*promise, PROMISE_FLAG_ASYNC);
   return promise;
@@ -4507,20 +4507,21 @@ static MOZ_MUST_USE PromiseObject* Creat
   return ResolvePromiseInternal(cx, resultPromise, value);
 }
 
 // https://tc39.github.io/ecma262/#await
 //
 // Helper function that performs 6.2.3.1 Await(promise) steps 2 and 9.
 // The same steps are also used in a few other places in the spec.
 template <typename T>
-static MOZ_MUST_USE bool InternalAwait(JSContext* cx, HandleValue value,
-                                       HandleObject resultPromise,
-                                       PromiseHandler onFulfilled,
-                                       PromiseHandler onRejected, T extraStep) {
+[[nodiscard]] static bool InternalAwait(JSContext* cx, HandleValue value,
+                                        HandleObject resultPromise,
+                                        PromiseHandler onFulfilled,
+                                        PromiseHandler onRejected,
+                                        T extraStep) {
   // Step 2: Let promise be ? PromiseResolve(%Promise%, « value »).
   RootedObject promise(cx, PromiseObject::unforgeableResolve(cx, value));
   if (!promise) {
     return false;
   }
 
   // This downcast is safe because unforgeableResolve either returns `value`
   // (only if it is already a possibly-wrapped promise) or creates a new
@@ -4783,17 +4784,17 @@ bool js::AsyncFromSyncIteratorMethod(JSC
 
   // Step 11: Return promiseCapability.[[Promise]].
   args.rval().setObject(*resultPromise);
   return true;
 }
 
 enum class ResumeNextKind { Enqueue, Reject, Resolve };
 
-static MOZ_MUST_USE bool AsyncGeneratorResumeNext(
+[[nodiscard]] static bool AsyncGeneratorResumeNext(
     JSContext* cx, Handle<AsyncGeneratorObject*> generator, ResumeNextKind kind,
     HandleValue valueOrException = UndefinedHandleValue, bool done = false);
 
 // 25.5.3.3 AsyncGeneratorResolve ( generator, value, done )
 [[nodiscard]] bool js::AsyncGeneratorResolve(
     JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj, HandleValue value,
     bool done) {
   return AsyncGeneratorResumeNext(cx, asyncGenObj, ResumeNextKind::Resolve,
@@ -4807,17 +4808,17 @@ static MOZ_MUST_USE bool AsyncGeneratorR
   return AsyncGeneratorResumeNext(cx, asyncGenObj, ResumeNextKind::Reject,
                                   exception);
 }
 
 // Unified implementation of:
 // 25.5.3.3 AsyncGeneratorResolve ( generator, value, done )
 // 25.5.3.4 AsyncGeneratorReject ( generator, exception )
 // 25.5.3.5 AsyncGeneratorResumeNext ( generator )
-static MOZ_MUST_USE bool AsyncGeneratorResumeNext(
+[[nodiscard]] static bool AsyncGeneratorResumeNext(
     JSContext* cx, Handle<AsyncGeneratorObject*> generator, ResumeNextKind kind,
     HandleValue valueOrException_ /* = UndefinedHandleValue */,
     bool done /* = false */) {
   RootedValue valueOrException(cx, valueOrException_);
 
   // Many paths through the algorithm end in recursive tail-calls.
   // We implement these with a loop.
   while (true) {
@@ -5262,17 +5263,17 @@ bool Promise_then_noRetVal(JSContext* cx
 // ES2016, 25.4.5.3.
 bool js::Promise_then(JSContext* cx, unsigned argc, Value* vp) {
   CallArgs args = CallArgsFromVp(argc, vp);
   return Promise_then_impl(cx, args.thisv(), args.get(0), args.get(1),
                            args.rval(), true);
 }
 
 // ES2016, 25.4.5.3.1.
-static MOZ_MUST_USE bool PerformPromiseThen(
+[[nodiscard]] static bool PerformPromiseThen(
     JSContext* cx, Handle<PromiseObject*> promise, HandleValue onFulfilled_,
     HandleValue onRejected_, Handle<PromiseCapability> resultCapability) {
   // Step 1 (implicit).
   // Step 2 (implicit).
 
   // Step 3.
   RootedValue onFulfilled(cx, onFulfilled_);
   if (!IsCallable(onFulfilled)) {
@@ -5291,17 +5292,17 @@ static MOZ_MUST_USE bool PerformPromiseT
                             IncumbentGlobalObject::Yes));
   if (!reaction) {
     return false;
   }
 
   return PerformPromiseThenWithReaction(cx, promise, reaction);
 }
 
-static MOZ_MUST_USE bool PerformPromiseThenWithoutSettleHandlers(
+[[nodiscard]] static bool PerformPromiseThenWithoutSettleHandlers(
     JSContext* cx, Handle<PromiseObject*> promise,
     Handle<PromiseObject*> promiseToResolve,
     Handle<PromiseCapability> resultCapability) {
   // Step 1 (implicit).
   // Step 2 (implicit).
 
   // Step 3.
   HandleValue onFulfilled = NullHandleValue;
@@ -5319,17 +5320,17 @@ static MOZ_MUST_USE bool PerformPromiseT
 
   reaction->setIsDefaultResolvingHandler(promiseToResolve);
 
   return PerformPromiseThenWithReaction(cx, promise, reaction);
 }
 
 // https://tc39.github.io/ecma262/#sec-performpromisethen
 // 25.6.5.4.1 PerformPromiseThen steps 8-11.
-static MOZ_MUST_USE bool PerformPromiseThenWithReaction(
+[[nodiscard]] static bool PerformPromiseThenWithReaction(
     JSContext* cx, Handle<PromiseObject*> unwrappedPromise,
     Handle<PromiseReactionRecord*> reaction) {
   // Step 8: If promise.[[PromiseState]] is "pending", then
   JS::PromiseState state = unwrappedPromise->state();
   int32_t flags = unwrappedPromise->flags();
   if (state == JS::PromiseState::Pending) {
     // Step 8.a: Append fulfillReaction as the last element of the List that is
     //           promise.[[PromiseFulfillReactions]].
@@ -5378,17 +5379,17 @@ static MOZ_MUST_USE bool PerformPromiseT
   }
 
   // Step 11: Set promise.[[PromiseIsHandled]] to true.
   unwrappedPromise->setHandled();
 
   return true;
 }
 
-static MOZ_MUST_USE bool AddPromiseReaction(
+[[nodiscard]] static bool AddPromiseReaction(
     JSContext* cx, Handle<PromiseObject*> unwrappedPromise,
     Handle<PromiseReactionRecord*> reaction) {
   MOZ_RELEASE_ASSERT(reaction->is<PromiseReactionRecord>());
   RootedValue reactionVal(cx, ObjectValue(*reaction));
 
   // The code that creates Promise reactions can handle wrapped Promises,
   // unwrapping them as needed. That means that the `promise` and `reaction`
   // objects we have here aren't necessarily from the same compartment. In
@@ -5452,17 +5453,17 @@ static MOZ_MUST_USE bool AddPromiseReact
       return false;
     }
     reactions->setDenseElement(len, reactionVal);
   }
 
   return true;
 }
 
-static MOZ_MUST_USE bool AddDummyPromiseReactionForDebugger(
+[[nodiscard]] static bool AddDummyPromiseReactionForDebugger(
     JSContext* cx, Handle<PromiseObject*> promise,
     HandleObject dependentPromise) {
   if (promise->state() != JS::PromiseState::Pending) {
     return true;
   }
 
   // `dependentPromise` should be a maybe-wrapped Promise.
   MOZ_ASSERT(UncheckedUnwrap(dependentPromise)->is<PromiseObject>());
@@ -5691,17 +5692,17 @@ void PromiseObject::copyUserInteractionF
 
 // We can skip `await` with an already resolved value only if the current frame
 // is the topmost JS frame and the current job is the last job in the job queue.
 // This guarantees that any new job enqueued in the current turn will be
 // executed immediately after the current job.
 //
 // Currently we only support skipping jobs when the async function is resumed
 // at least once.
-static MOZ_MUST_USE bool IsTopMostAsyncFunctionCall(JSContext* cx) {
+[[nodiscard]] static bool IsTopMostAsyncFunctionCall(JSContext* cx) {
   FrameIter iter(cx);
 
   // The current frame should be the async function.
   if (iter.done()) {
     return false;
   }
 
   if (!iter.isFunctionFrame() && iter.isModuleFrame()) {
--- a/js/src/builtin/Promise.h
+++ b/js/src/builtin/Promise.h
@@ -79,17 +79,17 @@ enum class UnhandledRejectionBehavior { 
  *
  * Note: Reactions pushed using this function contain a null `promise` field.
  * That field is only ever used by devtools, which have to treat these reactions
  * specially.
  *
  * 0. The sense of "react" here is the sense of the term as defined by Web IDL:
  *    https://heycam.github.io/webidl/#dfn-perform-steps-once-promise-is-settled
  */
-extern MOZ_MUST_USE bool ReactToUnwrappedPromise(
+[[nodiscard]] extern bool ReactToUnwrappedPromise(
     JSContext* cx, JS::Handle<PromiseObject*> unwrappedPromise,
     JS::Handle<JSObject*> onFulfilled_, JS::Handle<JSObject*> onRejected_,
     UnhandledRejectionBehavior behavior);
 
 /**
  * PromiseResolve ( C, x )
  *
  * The abstract operation PromiseResolve, given a constructor and a value,
@@ -173,44 +173,44 @@ struct PromiseReactionRecordBuilder {
   // Note that resolve, reject, and result may not be same-compartment with cx,
   // or with the promise we're inspecting. This function presents the values
   // exactly as they appear in the reaction record. They may also be wrapped or
   // unwrapped.
   //
   // Some reaction records refer to internal resolution or rejection functions
   // that are not naturally represented as debuggee JavaScript functions. In
   // this case, resolve and reject may be nullptr.
-  virtual MOZ_MUST_USE bool then(JSContext* cx, JS::Handle<JSObject*> resolve,
-                                 JS::Handle<JSObject*> reject,
-                                 JS::Handle<JSObject*> result) = 0;
+  [[nodiscard]] virtual bool then(JSContext* cx, JS::Handle<JSObject*> resolve,
+                                  JS::Handle<JSObject*> reject,
+                                  JS::Handle<JSObject*> result) = 0;
 
   // A reaction record created when one native promise is resolved to another.
   // The 'promise' argument is the promise that will be settled in the same way
   // the promise this reaction record is attached to is settled.
   //
   // Note that promise may not be same-compartment with cx. This function
   // presents the promise exactly as it appears in the reaction record.
-  virtual MOZ_MUST_USE bool direct(
+  [[nodiscard]] virtual bool direct(
       JSContext* cx, JS::Handle<PromiseObject*> unwrappedPromise) = 0;
 
   // A reaction record that resumes an asynchronous function suspended at an
   // await expression. The 'generator' argument is the generator object
   // representing the call.
   //
   // Note that generator may not be same-compartment with cx. This function
   // presents the generator exactly as it appears in the reaction record.
-  virtual MOZ_MUST_USE bool asyncFunction(
+  [[nodiscard]] virtual bool asyncFunction(
       JSContext* cx,
       JS::Handle<AsyncFunctionGeneratorObject*> unwrappedGenerator) = 0;
 
   // A reaction record that resumes an asynchronous generator suspended at an
   // await expression. The 'generator' argument is the generator object
   // representing the call.
   //
   // Note that generator may not be same-compartment with cx. This function
   // presents the generator exactly as it appears in the reaction record.
-  virtual MOZ_MUST_USE bool asyncGenerator(
+  [[nodiscard]] virtual bool asyncGenerator(
       JSContext* cx, JS::Handle<AsyncGeneratorObject*> unwrappedGenerator) = 0;
 };
 
 }  // namespace js
 
 #endif  // builtin_Promise_h
--- a/js/src/builtin/Reflect.h
+++ b/js/src/builtin/Reflect.h
@@ -12,20 +12,20 @@
 namespace js {
 
 extern const JSClass ReflectClass;
 
 }  // namespace js
 
 namespace js {
 
-extern MOZ_MUST_USE bool Reflect_getPrototypeOf(JSContext* cx, unsigned argc,
-                                                Value* vp);
+[[nodiscard]] extern bool Reflect_getPrototypeOf(JSContext* cx, unsigned argc,
+                                                 Value* vp);
 
-extern MOZ_MUST_USE bool Reflect_isExtensible(JSContext* cx, unsigned argc,
-                                              Value* vp);
+[[nodiscard]] extern bool Reflect_isExtensible(JSContext* cx, unsigned argc,
+                                               Value* vp);
 
-extern MOZ_MUST_USE bool Reflect_ownKeys(JSContext* cx, unsigned argc,
-                                         Value* vp);
+[[nodiscard]] extern bool Reflect_ownKeys(JSContext* cx, unsigned argc,
+                                          Value* vp);
 
 }  // namespace js
 
 #endif /* builtin_Reflect_h */
--- a/js/src/builtin/RegExp.h
+++ b/js/src/builtin/RegExp.h
@@ -32,112 +32,113 @@ JSObject* InitRegExpClass(JSContext* cx,
                                        MutableHandleValue rval);
 
 // Translation from MatchPairs to a JS array in regexp_exec()'s output format.
 [[nodiscard]] bool CreateRegExpMatchResult(JSContext* cx, HandleRegExpShared re,
                                            HandleString input,
                                            const MatchPairs& matches,
                                            MutableHandleValue rval);
 
-extern MOZ_MUST_USE bool RegExpMatcher(JSContext* cx, unsigned argc, Value* vp);
-
-extern MOZ_MUST_USE bool RegExpMatcherRaw(JSContext* cx, HandleObject regexp,
-                                          HandleString input,
-                                          int32_t maybeLastIndex,
-                                          MatchPairs* maybeMatches,
-                                          MutableHandleValue output);
-
-extern MOZ_MUST_USE bool RegExpSearcher(JSContext* cx, unsigned argc,
+[[nodiscard]] extern bool RegExpMatcher(JSContext* cx, unsigned argc,
                                         Value* vp);
 
-extern MOZ_MUST_USE bool RegExpSearcherRaw(JSContext* cx, HandleObject regexp,
+[[nodiscard]] extern bool RegExpMatcherRaw(JSContext* cx, HandleObject regexp,
                                            HandleString input,
-                                           int32_t lastIndex,
+                                           int32_t maybeLastIndex,
                                            MatchPairs* maybeMatches,
-                                           int32_t* result);
+                                           MutableHandleValue output);
 
-extern MOZ_MUST_USE bool RegExpTester(JSContext* cx, unsigned argc, Value* vp);
+[[nodiscard]] extern bool RegExpSearcher(JSContext* cx, unsigned argc,
+                                         Value* vp);
 
-extern MOZ_MUST_USE bool RegExpTesterRaw(JSContext* cx, HandleObject regexp,
-                                         HandleString input, int32_t lastIndex,
-                                         int32_t* endIndex);
+[[nodiscard]] extern bool RegExpSearcherRaw(JSContext* cx, HandleObject regexp,
+                                            HandleString input,
+                                            int32_t lastIndex,
+                                            MatchPairs* maybeMatches,
+                                            int32_t* result);
 
-extern MOZ_MUST_USE bool intrinsic_GetElemBaseForLambda(JSContext* cx,
-                                                        unsigned argc,
-                                                        Value* vp);
+[[nodiscard]] extern bool RegExpTester(JSContext* cx, unsigned argc, Value* vp);
 
-extern MOZ_MUST_USE bool intrinsic_GetStringDataProperty(JSContext* cx,
+[[nodiscard]] extern bool RegExpTesterRaw(JSContext* cx, HandleObject regexp,
+                                          HandleString input, int32_t lastIndex,
+                                          int32_t* endIndex);
+
+[[nodiscard]] extern bool intrinsic_GetElemBaseForLambda(JSContext* cx,
                                                          unsigned argc,
                                                          Value* vp);
 
+[[nodiscard]] extern bool intrinsic_GetStringDataProperty(JSContext* cx,
+                                                          unsigned argc,
+                                                          Value* vp);
+
 /*
  * The following functions are for use by self-hosted code.
  */
 
 /*
  * Behaves like RegExp(source, flags).
  * |source| must be a valid regular expression pattern, |flags| is a raw
  * integer value representing the regular expression flags.
  * Must be called without |new|.
  *
  * Dedicated function for RegExp.prototype[@@replace] and
  * RegExp.prototype[@@split] optimized paths.
  */
-extern MOZ_MUST_USE bool regexp_construct_raw_flags(JSContext* cx,
+[[nodiscard]] extern bool regexp_construct_raw_flags(JSContext* cx,
+                                                     unsigned argc, Value* vp);
+
+[[nodiscard]] extern bool IsRegExp(JSContext* cx, HandleValue value,
+                                   bool* result);
+
+[[nodiscard]] extern bool RegExpCreate(JSContext* cx, HandleValue pattern,
+                                       HandleValue flags,
+                                       MutableHandleValue rval);
+
+[[nodiscard]] extern bool RegExpPrototypeOptimizable(JSContext* cx,
+                                                     unsigned argc, Value* vp);
+
+[[nodiscard]] extern bool RegExpPrototypeOptimizableRaw(JSContext* cx,
+                                                        JSObject* proto);
+
+[[nodiscard]] extern bool RegExpInstanceOptimizable(JSContext* cx,
                                                     unsigned argc, Value* vp);
 
-extern MOZ_MUST_USE bool IsRegExp(JSContext* cx, HandleValue value,
-                                  bool* result);
-
-extern MOZ_MUST_USE bool RegExpCreate(JSContext* cx, HandleValue pattern,
-                                      HandleValue flags,
-                                      MutableHandleValue rval);
-
-extern MOZ_MUST_USE bool RegExpPrototypeOptimizable(JSContext* cx,
-                                                    unsigned argc, Value* vp);
-
-extern MOZ_MUST_USE bool RegExpPrototypeOptimizableRaw(JSContext* cx,
+[[nodiscard]] extern bool RegExpInstanceOptimizableRaw(JSContext* cx,
+                                                       JSObject* obj,
                                                        JSObject* proto);
 
-extern MOZ_MUST_USE bool RegExpInstanceOptimizable(JSContext* cx, unsigned argc,
-                                                   Value* vp);
-
-extern MOZ_MUST_USE bool RegExpInstanceOptimizableRaw(JSContext* cx,
-                                                      JSObject* obj,
-                                                      JSObject* proto);
-
-extern MOZ_MUST_USE bool RegExpGetSubstitution(
+[[nodiscard]] extern bool RegExpGetSubstitution(
     JSContext* cx, HandleArrayObject matchResult, HandleLinearString string,
     size_t position, HandleLinearString replacement, size_t firstDollarIndex,
     HandleValue namedCaptures, MutableHandleValue rval);
 
-extern MOZ_MUST_USE bool GetFirstDollarIndex(JSContext* cx, unsigned argc,
-                                             Value* vp);
+[[nodiscard]] extern bool GetFirstDollarIndex(JSContext* cx, unsigned argc,
+                                              Value* vp);
 
-extern MOZ_MUST_USE bool GetFirstDollarIndexRaw(JSContext* cx, JSString* str,
-                                                int32_t* index);
+[[nodiscard]] extern bool GetFirstDollarIndexRaw(JSContext* cx, JSString* str,
+                                                 int32_t* index);
 
 extern int32_t GetFirstDollarIndexRawFlat(JSLinearString* text);
 
 // RegExp ClassSpec members used in RegExpObject.cpp.
-extern MOZ_MUST_USE bool regexp_construct(JSContext* cx, unsigned argc,
-                                          Value* vp);
+[[nodiscard]] extern bool regexp_construct(JSContext* cx, unsigned argc,
+                                           Value* vp);
 extern const JSPropertySpec regexp_static_props[];
 extern const JSPropertySpec regexp_properties[];
 extern const JSFunctionSpec regexp_methods[];
 
 // Used in RegExpObject::isOriginalFlagGetter.
-extern MOZ_MUST_USE bool regexp_global(JSContext* cx, unsigned argc,
-                                       JS::Value* vp);
-extern MOZ_MUST_USE bool regexp_ignoreCase(JSContext* cx, unsigned argc,
+[[nodiscard]] extern bool regexp_global(JSContext* cx, unsigned argc,
+                                        JS::Value* vp);
+[[nodiscard]] extern bool regexp_ignoreCase(JSContext* cx, unsigned argc,
+                                            JS::Value* vp);
+[[nodiscard]] extern bool regexp_multiline(JSContext* cx, unsigned argc,
                                            JS::Value* vp);
-extern MOZ_MUST_USE bool regexp_multiline(JSContext* cx, unsigned argc,
-                                          JS::Value* vp);
-extern MOZ_MUST_USE bool regexp_dotAll(JSContext* cx, unsigned argc,
-                                       JS::Value* vp);
-extern MOZ_MUST_USE bool regexp_sticky(JSContext* cx, unsigned argc,
-                                       JS::Value* vp);
-extern MOZ_MUST_USE bool regexp_unicode(JSContext* cx, unsigned argc,
+[[nodiscard]] extern bool regexp_dotAll(JSContext* cx, unsigned argc,
                                         JS::Value* vp);
+[[nodiscard]] extern bool regexp_sticky(JSContext* cx, unsigned argc,
+                                        JS::Value* vp);
+[[nodiscard]] extern bool regexp_unicode(JSContext* cx, unsigned argc,
+                                         JS::Value* vp);
 
 } /* namespace js */
 
 #endif /* builtin_RegExp_h */
--- a/js/src/builtin/Stream.cpp
+++ b/js/src/builtin/Stream.cpp
@@ -102,17 +102,17 @@ const JSClass ByteStreamChunk::class_ = 
  * Streams spec, 3.10.3
  *      new ReadableByteStreamController ( stream, underlyingSource,
  *                                         highWaterMark )
  * Steps 3 - 16.
  *
  * Note: All arguments must be same-compartment with cx. ReadableStream
  * controllers are always created in the same compartment as the stream.
  */
-static MOZ_MUST_USE ReadableByteStreamController*
+[[nodiscard]] static ReadableByteStreamController*
 CreateReadableByteStreamController(JSContext* cx,
                                    Handle<ReadableStream*> stream,
                                    HandleValue underlyingByteSource,
                                    HandleValue highWaterMarkVal)
 {
     cx->check(stream, underlyingByteSource, highWaterMarkVal);
 
     Rooted<ReadableByteStreamController*> controller(cx,
@@ -385,23 +385,23 @@ static const JSClassOps ReadableByteStre
 JS_STREAMS_CLASS_SPEC(ReadableByteStreamController, 0, SlotCount,
                       ClassSpec::DontDefineConstructor,
                       JSCLASS_BACKGROUND_FINALIZE,
                       &ReadableByteStreamControllerClassOps);
 
 // Streams spec, 3.11.5.1. [[CancelSteps]] ()
 // Unified with 3.9.5.1 above.
 
-static MOZ_MUST_USE bool ReadableByteStreamControllerHandleQueueDrain(
+[[nodiscard]] static bool ReadableByteStreamControllerHandleQueueDrain(
     JSContext* cx, Handle<ReadableStreamController*> unwrappedController);
 
 /**
  * Streams spec, 3.11.5.2. [[PullSteps]] ( forAuthorCode )
  */
-static MOZ_MUST_USE PromiseObject* ReadableByteStreamControllerPullSteps(
+[[nodiscard]] static PromiseObject* ReadableByteStreamControllerPullSteps(
     JSContext* cx, Handle<ReadableByteStreamController*> unwrappedController) {
   // Step 1: Let stream be this.[[controlledReadableByteStream]].
   Rooted<ReadableStream*> unwrappedStream(cx, unwrappedController->stream());
 
   // Step 2: Assert: ! ReadableStreamHasDefaultReader(stream) is true.
 #ifdef DEBUG
   bool result;
   if (!ReadableStreamHasDefaultReader(cx, unwrappedStream, &result)) {
@@ -602,17 +602,17 @@ static MOZ_MUST_USE PromiseObject* Reada
 
 // Streams spec, 3.13.2. IsReadableByteStreamController ( x )
 // Implemented via is<ReadableByteStreamController>()
 
 // Streams spec, 3.13.3.
 //      ReadableByteStreamControllerCallPullIfNeeded ( controller )
 // Unified with 3.9.2 above.
 
-static MOZ_MUST_USE bool ReadableByteStreamControllerInvalidateBYOBRequest(
+[[nodiscard]] static bool ReadableByteStreamControllerInvalidateBYOBRequest(
     JSContext* cx, Handle<ReadableByteStreamController*> unwrappedController);
 
 /**
  * Streams spec, 3.13.5.
  *      ReadableByteStreamControllerClearPendingPullIntos ( controller )
  */
 [[nodiscard]] bool js::ReadableByteStreamControllerClearPendingPullIntos(
     JSContext* cx, Handle<ReadableByteStreamController*> unwrappedController) {
@@ -704,17 +704,17 @@ static MOZ_MUST_USE bool ReadableByteStr
 // Streams spec 3.13.14.
 //      ReadableByteStreamControllerGetDesiredSize ( controller )
 // Unified with 3.10.8 above.
 
 /**
  * Streams spec, 3.13.15.
  *      ReadableByteStreamControllerHandleQueueDrain ( controller )
  */
-static MOZ_MUST_USE bool ReadableByteStreamControllerHandleQueueDrain(
+[[nodiscard]] static bool ReadableByteStreamControllerHandleQueueDrain(
     JSContext* cx, Handle<ReadableStreamController*> unwrappedController) {
   MOZ_ASSERT(unwrappedController->is<ReadableByteStreamController>());
 
   // Step 1: Assert: controller.[[controlledReadableStream]].[[state]]
   //                 is "readable".
   Rooted<ReadableStream*> unwrappedStream(cx, unwrappedController->stream());
   MOZ_ASSERT(unwrappedStream->readable());
 
@@ -741,17 +741,17 @@ enum BYOBRequestSlots {
   BYOBRequestSlot_View,
   BYOBRequestSlotCount
 };
 
 /**
  * Streams spec 3.13.16.
  *      ReadableByteStreamControllerInvalidateBYOBRequest ( controller )
  */
-static MOZ_MUST_USE bool ReadableByteStreamControllerInvalidateBYOBRequest(
+[[nodiscard]] static bool ReadableByteStreamControllerInvalidateBYOBRequest(
     JSContext* cx, Handle<ReadableByteStreamController*> unwrappedController) {
   // Step 1: If controller.[[byobRequest]] is undefined, return.
   RootedValue unwrappedBYOBRequestVal(cx, unwrappedController->byobRequest());
   if (unwrappedBYOBRequestVal.isUndefined()) {
     return true;
   }
 
   RootedNativeObject unwrappedBYOBRequest(
--- a/js/src/builtin/Stream.h
+++ b/js/src/builtin/Stream.h
@@ -15,22 +15,22 @@
 struct JS_PUBLIC_API JSContext;
 
 namespace js {
 
 class PromiseObject;
 class ReadableByteStreamController;
 class ReadableStreamController;
 
-extern MOZ_MUST_USE bool ReadableByteStreamControllerClearPendingPullIntos(
+[[nodiscard]] extern bool ReadableByteStreamControllerClearPendingPullIntos(
     JSContext* cx,
     JS::Handle<ReadableByteStreamController*> unwrappedController);
 
-extern MOZ_MUST_USE bool ReadableByteStreamControllerClose(
+[[nodiscard]] extern bool ReadableByteStreamControllerClose(
     JSContext* cx,
     JS::Handle<ReadableByteStreamController*> unwrappedController);
 
-extern MOZ_MUST_USE PromiseObject* ReadableStreamControllerPullSteps(
+[[nodiscard]] extern PromiseObject* ReadableStreamControllerPullSteps(
     JSContext* cx, JS::Handle<ReadableStreamController*> unwrappedController);
 
 }  // namespace js
 
 #endif /* builtin_Stream_h */
--- a/js/src/builtin/String.h
+++ b/js/src/builtin/String.h
@@ -52,27 +52,27 @@ extern bool str_endsWith(JSContext* cx, 
 
 #if JS_HAS_INTL_API
 /**
  * Returns the input string converted to lower case based on the language
  * specific case mappings for the input locale.
  *
  * Usage: lowerCase = intl_toLocaleLowerCase(string, locale)
  */
-extern MOZ_MUST_USE bool intl_toLocaleLowerCase(JSContext* cx, unsigned argc,
-                                                Value* vp);
+[[nodiscard]] extern bool intl_toLocaleLowerCase(JSContext* cx, unsigned argc,
+                                                 Value* vp);
 
 /**
  * Returns the input string converted to upper case based on the language
  * specific case mappings for the input locale.
  *
  * Usage: upperCase = intl_toLocaleUpperCase(string, locale)
  */
-extern MOZ_MUST_USE bool intl_toLocaleUpperCase(JSContext* cx, unsigned argc,
-                                                Value* vp);
+[[nodiscard]] extern bool intl_toLocaleUpperCase(JSContext* cx, unsigned argc,
+                                                 Value* vp);
 #endif
 
 ArrayObject* StringSplitString(JSContext* cx, HandleString str,
                                HandleString sep, uint32_t limit);
 
 JSString* StringFlatReplaceString(JSContext* cx, HandleString string,
                                   HandleString pattern,
                                   HandleString replacement);
--- a/js/src/builtin/Symbol.h
+++ b/js/src/builtin/Symbol.h
@@ -32,34 +32,35 @@ class SymbolObject : public NativeObject
     return getFixedSlot(PRIMITIVE_VALUE_SLOT).toSymbol();
   }
 
  private:
   inline void setPrimitiveValue(JS::Symbol* symbol) {
     setFixedSlot(PRIMITIVE_VALUE_SLOT, SymbolValue(symbol));
   }
 
-  static MOZ_MUST_USE bool construct(JSContext* cx, unsigned argc, Value* vp);
+  [[nodiscard]] static bool construct(JSContext* cx, unsigned argc, Value* vp);
 
   // Static methods.
-  static MOZ_MUST_USE bool for_(JSContext* cx, unsigned argc, Value* vp);
-  static MOZ_MUST_USE bool keyFor(JSContext* cx, unsigned argc, Value* vp);
+  [[nodiscard]] static bool for_(JSContext* cx, unsigned argc, Value* vp);
+  [[nodiscard]] static bool keyFor(JSContext* cx, unsigned argc, Value* vp);
 
   // Methods defined on Symbol.prototype.
-  static MOZ_MUST_USE bool toString_impl(JSContext* cx, const CallArgs& args);
-  static MOZ_MUST_USE bool toString(JSContext* cx, unsigned argc, Value* vp);
-  static MOZ_MUST_USE bool valueOf_impl(JSContext* cx, const CallArgs& args);
-  static MOZ_MUST_USE bool valueOf(JSContext* cx, unsigned argc, Value* vp);
-  static MOZ_MUST_USE bool toPrimitive(JSContext* cx, unsigned argc, Value* vp);
+  [[nodiscard]] static bool toString_impl(JSContext* cx, const CallArgs& args);
+  [[nodiscard]] static bool toString(JSContext* cx, unsigned argc, Value* vp);
+  [[nodiscard]] static bool valueOf_impl(JSContext* cx, const CallArgs& args);
+  [[nodiscard]] static bool valueOf(JSContext* cx, unsigned argc, Value* vp);
+  [[nodiscard]] static bool toPrimitive(JSContext* cx, unsigned argc,
+                                        Value* vp);
 
   // Properties defined on Symbol.prototype.
-  static MOZ_MUST_USE bool descriptionGetter_impl(JSContext* cx,
-                                                  const CallArgs& args);
-  static MOZ_MUST_USE bool descriptionGetter(JSContext* cx, unsigned argc,
-                                             Value* vp);
+  [[nodiscard]] static bool descriptionGetter_impl(JSContext* cx,
+                                                   const CallArgs& args);
+  [[nodiscard]] static bool descriptionGetter(JSContext* cx, unsigned argc,
+                                              Value* vp);
 
   static const JSPropertySpec properties[];
   static const JSFunctionSpec methods[];
   static const JSFunctionSpec staticMethods[];
   static const ClassSpec classSpec_;
 };
 
 } /* namespace js */
--- a/js/src/builtin/WeakMapObject.h
+++ b/js/src/builtin/WeakMapObject.h
@@ -21,17 +21,17 @@ class WeakCollectionObject : public Nati
     return static_cast<ObjectValueWeakMap*>(getPrivate());
   }
 
   size_t sizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) {
     ObjectValueWeakMap* map = getMap();
     return map ? map->sizeOfIncludingThis(aMallocSizeOf) : 0;
   }
 
-  static MOZ_MUST_USE bool nondeterministicGetKeys(
+  [[nodiscard]] static bool nondeterministicGetKeys(
       JSContext* cx, Handle<WeakCollectionObject*> obj,
       MutableHandleObject ret);
 
  protected:
   static const JSClassOps classOps_;
 };
 
 class WeakMapObject : public WeakCollectionObject {
@@ -40,29 +40,29 @@ class WeakMapObject : public WeakCollect
   static const JSClass protoClass_;
 
  private:
   static const ClassSpec classSpec_;
 
   static const JSPropertySpec properties[];
   static const JSFunctionSpec methods[];
 
-  static MOZ_MUST_USE bool construct(JSContext* cx, unsigned argc, Value* vp);
+  [[nodiscard]] static bool construct(JSContext* cx, unsigned argc, Value* vp);
 
-  static MOZ_MUST_USE MOZ_ALWAYS_INLINE bool is(HandleValue v);
+  [[nodiscard]] static MOZ_ALWAYS_INLINE bool is(HandleValue v);
 
-  static MOZ_MUST_USE MOZ_ALWAYS_INLINE bool has_impl(JSContext* cx,
-                                                      const CallArgs& args);
-  static MOZ_MUST_USE bool has(JSContext* cx, unsigned argc, Value* vp);
-  static MOZ_MUST_USE MOZ_ALWAYS_INLINE bool get_impl(JSContext* cx,
-                                                      const CallArgs& args);
-  static MOZ_MUST_USE bool get(JSContext* cx, unsigned argc, Value* vp);
-  static MOZ_MUST_USE MOZ_ALWAYS_INLINE bool delete_impl(JSContext* cx,
-                                                         const CallArgs& args);
-  static MOZ_MUST_USE bool delete_(JSContext* cx, unsigned argc, Value* vp);
-  static MOZ_MUST_USE MOZ_ALWAYS_INLINE bool set_impl(JSContext* cx,
-                                                      const CallArgs& args);
-  static MOZ_MUST_USE bool set(JSContext* cx, unsigned argc, Value* vp);
+  [[nodiscard]] static MOZ_ALWAYS_INLINE bool has_impl(JSContext* cx,
+                                                       const CallArgs& args);
+  [[nodiscard]] static bool has(JSContext* cx, unsigned argc, Value* vp);
+  [[nodiscard]] static MOZ_ALWAYS_INLINE bool get_impl(JSContext* cx,
+                                                       const CallArgs& args);
+  [[nodiscard]] static bool get(JSContext* cx, unsigned argc, Value* vp);
+  [[nodiscard]] static MOZ_ALWAYS_INLINE bool delete_impl(JSContext* cx,
+                                                          const CallArgs& args);
+  [[nodiscard]] static bool delete_(JSContext* cx, unsigned argc, Value* vp);
+  [[nodiscard]] static MOZ_ALWAYS_INLINE bool set_impl(JSContext* cx,
+                                                       const CallArgs& args);
+  [[nodiscard]] static bool set(JSContext* cx, unsigned argc, Value* vp);
 };
 
 }  // namespace js
 
 #endif /* builtin_WeakMapObject_h */
--- a/js/src/builtin/WeakRefObject.h
+++ b/js/src/builtin/WeakRefObject.h
@@ -21,17 +21,17 @@ class WeakRefObject : public NativeObjec
   void setTarget(JSObject* target);
 
  private:
   static const JSClassOps classOps_;
   static const ClassSpec classSpec_;
   static const JSPropertySpec properties[];
   static const JSFunctionSpec methods[];
 
-  static MOZ_MUST_USE bool construct(JSContext* cx, unsigned argc, Value* vp);
+  [[nodiscard]] static bool construct(JSContext* cx, unsigned argc, Value* vp);
   static void trace(JSTracer* trc, JSObject* obj);
   static void finalize(JSFreeOp* op, JSObject* obj);
 
   static bool preserveDOMWrapper(JSContext* cx, HandleObject obj);
 
   static bool deref(JSContext* cx, unsigned argc, Value* vp);
   static void readBarrier(JSContext* cx, Handle<WeakRefObject*> self);
 };
--- a/js/src/builtin/WeakSetObject.h
+++ b/js/src/builtin/WeakSetObject.h
@@ -20,29 +20,29 @@ class WeakSetObject : public WeakCollect
 
  private:
   static const ClassSpec classSpec_;
 
   static const JSPropertySpec properties[];
   static const JSFunctionSpec methods[];
 
   static WeakSetObject* create(JSContext* cx, HandleObject proto = nullptr);
-  static MOZ_MUST_USE bool construct(JSContext* cx, unsigned argc, Value* vp);
+  [[nodiscard]] static bool construct(JSContext* cx, unsigned argc, Value* vp);
 
-  static MOZ_MUST_USE MOZ_ALWAYS_INLINE bool is(HandleValue v);
+  [[nodiscard]] static MOZ_ALWAYS_INLINE bool is(HandleValue v);
 
-  static MOZ_MUST_USE MOZ_ALWAYS_INLINE bool add_impl(JSContext* cx,
-                                                      const CallArgs& args);
-  static MOZ_MUST_USE bool add(JSContext* cx, unsigned argc, Value* vp);
-  static MOZ_MUST_USE MOZ_ALWAYS_INLINE bool delete_impl(JSContext* cx,
-                                                         const CallArgs& args);
-  static MOZ_MUST_USE bool delete_(JSContext* cx, unsigned argc, Value* vp);
-  static MOZ_MUST_USE MOZ_ALWAYS_INLINE bool has_impl(JSContext* cx,
-                                                      const CallArgs& args);
-  static MOZ_MUST_USE bool has(JSContext* cx, unsigned argc, Value* vp);
+  [[nodiscard]] static MOZ_ALWAYS_INLINE bool add_impl(JSContext* cx,
+                                                       const CallArgs& args);
+  [[nodiscard]] static bool add(JSContext* cx, unsigned argc, Value* vp);
+  [[nodiscard]] static MOZ_ALWAYS_INLINE bool delete_impl(JSContext* cx,
+                                                          const CallArgs& args);
+  [[nodiscard]] static bool delete_(JSContext* cx, unsigned argc, Value* vp);
+  [[nodiscard]] static MOZ_ALWAYS_INLINE bool has_impl(JSContext* cx,
+                                                       const CallArgs& args);
+  [[nodiscard]] static bool has(JSContext* cx, unsigned argc, Value* vp);
 
   static bool isBuiltinAdd(HandleValue add);
 };
 
 }  // namespace js
 
 template <>
 inline bool JSObject::is<js::WeakCollectionObject>() const {
--- a/js/src/builtin/intl/Collator.h
+++ b/js/src/builtin/intl/Collator.h
@@ -58,47 +58,47 @@ class CollatorObject : public NativeObje
 
 /**
  * Returns a new instance of the standard built-in Collator constructor.
  * Self-hosted code cannot cache this constructor (as it does for others in
  * Utilities.js) because it is initialized after self-hosted code is compiled.
  *
  * Usage: collator = intl_Collator(locales, options)
  */
-extern MOZ_MUST_USE bool intl_Collator(JSContext* cx, unsigned argc,
-                                       JS::Value* vp);
+[[nodiscard]] extern bool intl_Collator(JSContext* cx, unsigned argc,
+                                        JS::Value* vp);
 
 /**
  * Returns an array with the collation type identifiers per Unicode
  * Technical Standard 35, Unicode Locale Data Markup Language, for the
  * collations supported for the given locale. "standard" and "search" are
  * excluded.
  *
  * Usage: collations = intl_availableCollations(locale)
  */
-extern MOZ_MUST_USE bool intl_availableCollations(JSContext* cx, unsigned argc,
-                                                  JS::Value* vp);
+[[nodiscard]] extern bool intl_availableCollations(JSContext* cx, unsigned argc,
+                                                   JS::Value* vp);
 
 /**
  * Compares x and y (which must be String values), and returns a number less
  * than 0 if x < y, 0 if x = y, or a number greater than 0 if x > y according
  * to the sort order for the locale and collation options of the given
  * Collator.
  *
  * Spec: ECMAScript Internationalization API Specification, 10.3.2.
  *
  * Usage: result = intl_CompareStrings(collator, x, y)
  */
-extern MOZ_MUST_USE bool intl_CompareStrings(JSContext* cx, unsigned argc,
-                                             JS::Value* vp);
+[[nodiscard]] extern bool intl_CompareStrings(JSContext* cx, unsigned argc,
+                                              JS::Value* vp);
 
 /**
  * Returns true if the given locale sorts upper-case before lower-case
  * characters.
  *
  * Usage: result = intl_isUpperCaseFirst(locale)
  */
-extern MOZ_MUST_USE bool intl_isUpperCaseFirst(JSContext* cx, unsigned argc,
-                                               JS::Value* vp);
+[[nodiscard]] extern bool intl_isUpperCaseFirst(JSContext* cx, unsigned argc,
+                                                JS::Value* vp);
 
 }  // namespace js
 
 #endif /* builtin_intl_Collator_h */
--- a/js/src/builtin/intl/DateTimeFormat.h
+++ b/js/src/builtin/intl/DateTimeFormat.h
@@ -73,98 +73,99 @@ class DateTimeFormatObject : public Nati
 
 /**
  * Returns a new instance of the standard built-in DateTimeFormat constructor.
  * Self-hosted code cannot cache this constructor (as it does for others in
  * Utilities.js) because it is initialized after self-hosted code is compiled.
  *
  * Usage: dateTimeFormat = intl_DateTimeFormat(locales, options)
  */
-extern MOZ_MUST_USE bool intl_DateTimeFormat(JSContext* cx, unsigned argc,
-                                             JS::Value* vp);
+[[nodiscard]] extern bool intl_DateTimeFormat(JSContext* cx, unsigned argc,
+                                              JS::Value* vp);
 
 /**
  * Returns an array with the calendar type identifiers per Unicode
  * Technical Standard 35, Unicode Locale Data Markup Language, for the
  * supported calendars for the given locale. The default calendar is
  * element 0.
  *
  * Usage: calendars = intl_availableCalendars(locale)
  */
-extern MOZ_MUST_USE bool intl_availableCalendars(JSContext* cx, unsigned argc,
-                                                 JS::Value* vp);
+[[nodiscard]] extern bool intl_availableCalendars(JSContext* cx, unsigned argc,
+                                                  JS::Value* vp);
 
 /**
  * Returns the calendar type identifier per Unicode Technical Standard 35,
  * Unicode Locale Data Markup Language, for the default calendar for the given
  * locale.
  *
  * Usage: calendar = intl_defaultCalendar(locale)
  */
-extern MOZ_MUST_USE bool intl_defaultCalendar(JSContext* cx, unsigned argc,
-                                              JS::Value* vp);
+[[nodiscard]] extern bool intl_defaultCalendar(JSContext* cx, unsigned argc,
+                                               JS::Value* vp);
 
 /**
  * 6.4.1 IsValidTimeZoneName ( timeZone )
  *
  * Verifies that the given string is a valid time zone name. If it is a valid
  * time zone name, its IANA time zone name is returned. Otherwise returns null.
  *
  * ES2017 Intl draft rev 4a23f407336d382ed5e3471200c690c9b020b5f3
  *
  * Usage: ianaTimeZone = intl_IsValidTimeZoneName(timeZone)
  */
-extern MOZ_MUST_USE bool intl_IsValidTimeZoneName(JSContext* cx, unsigned argc,
-                                                  JS::Value* vp);
+[[nodiscard]] extern bool intl_IsValidTimeZoneName(JSContext* cx, unsigned argc,
+                                                   JS::Value* vp);
 
 /**
  * Return the canonicalized time zone name. Canonicalization resolves link
  * names to their target time zones.
  *
  * Usage: ianaTimeZone = intl_canonicalizeTimeZone(timeZone)
  */
-extern MOZ_MUST_USE bool intl_canonicalizeTimeZone(JSContext* cx, unsigned argc,
-                                                   JS::Value* vp);
+[[nodiscard]] extern bool intl_canonicalizeTimeZone(JSContext* cx,
+                                                    unsigned argc,
+                                                    JS::Value* vp);
 
 /**
  * Return the default time zone name. The time zone name is not canonicalized.
  *
  * Usage: icuDefaultTimeZone = intl_defaultTimeZone()
  */
-extern MOZ_MUST_USE bool intl_defaultTimeZone(JSContext* cx, unsigned argc,
-                                              JS::Value* vp);
+[[nodiscard]] extern bool intl_defaultTimeZone(JSContext* cx, unsigned argc,
+                                               JS::Value* vp);
 
 /**
  * Return the raw offset from GMT in milliseconds for the default time zone.
  *
  * Usage: defaultTimeZoneOffset = intl_defaultTimeZoneOffset()
  */
-extern MOZ_MUST_USE bool intl_defaultTimeZoneOffset(JSContext* cx,
-                                                    unsigned argc,
-                                                    JS::Value* vp);
+[[nodiscard]] extern bool intl_defaultTimeZoneOffset(JSContext* cx,
+                                                     unsigned argc,
+                                                     JS::Value* vp);
 
 /**
  * Return true if the given string is the default time zone as returned by
  * intl_defaultTimeZone(). Otherwise return false.
  *
  * Usage: isIcuDefaultTimeZone = intl_isDefaultTimeZone(icuDefaultTimeZone)
  */
-extern MOZ_MUST_USE bool intl_isDefaultTimeZone(JSContext* cx, unsigned argc,
-                                                JS::Value* vp);
+[[nodiscard]] extern bool intl_isDefaultTimeZone(JSContext* cx, unsigned argc,
+                                                 JS::Value* vp);
 
 /**
  * Return a pattern in the date-time format pattern language of Unicode
  * Technical Standard 35, Unicode Locale Data Markup Language, for the
  * best-fit date-time format pattern corresponding to skeleton for the
  * given locale.
  *
  * Usage: pattern = intl_patternForSkeleton(locale, skeleton, hourCycle)
  */
-extern MOZ_MUST_USE bool intl_patternForSkeleton(JSContext* cx, unsigned argc,
-                                                 JS::Value* vp);
+[[nodiscard]] extern bool intl_patternForSkeleton(JSContext* cx, unsigned argc,
+                                                  JS::Value* vp);
 
 /**
  * Return a pattern in the date-time format pattern language of Unicode
  * Technical Standard 35, Unicode Locale Data Markup Language, for the
  * best-fit date-time style for the given locale.
  * The function takes six arguments:
  *
  *   locale
@@ -187,47 +188,47 @@ extern MOZ_MUST_USE bool intl_patternFor
  * http://unicode.org/reports/tr35/tr35-dates.html#Date_Format_Patterns
  *
  * If `undefined` is passed to `dateStyle` or `timeStyle`, the respective
  * portions of the pattern will not be included in the result.
  *
  * Usage: pattern = intl_patternForStyle(locale, dateStyle, timeStyle, timeZone,
  *                                       hour12, hourCycle)
  */
-extern MOZ_MUST_USE bool intl_patternForStyle(JSContext* cx, unsigned argc,
-                                              JS::Value* vp);
+[[nodiscard]] extern bool intl_patternForStyle(JSContext* cx, unsigned argc,
+                                               JS::Value* vp);
 
 /**
  * Return a skeleton for the pattern in the date-time format pattern language of
  * Unicode Technical Standard 35, Unicode Locale Data Markup Language.
  *
  * Usage: skeleton = intl_skeletonForPattern(pattern)
  */
-extern MOZ_MUST_USE bool intl_skeletonForPattern(JSContext* cx, unsigned argc,
-                                                 JS::Value* vp);
+[[nodiscard]] extern bool intl_skeletonForPattern(JSContext* cx, unsigned argc,
+                                                  JS::Value* vp);
 
 /**
  * Returns a String value representing x (which must be a Number value)
  * according to the effective locale and the formatting options of the
  * given DateTimeFormat.
  *
  * Spec: ECMAScript Internationalization API Specification, 12.3.2.
  *
  * Usage: formatted = intl_FormatDateTime(dateTimeFormat, x, formatToParts)
  */
-extern MOZ_MUST_USE bool intl_FormatDateTime(JSContext* cx, unsigned argc,
-                                             JS::Value* vp);
+[[nodiscard]] extern bool intl_FormatDateTime(JSContext* cx, unsigned argc,
+                                              JS::Value* vp);
 
 /**
  * Returns a String value representing the range between x and y (which both
  * must be Number values) according to the effective locale and the formatting
  * options of the given DateTimeFormat.
  *
  * Spec: Intl.DateTimeFormat.prototype.formatRange proposal
  *
  * Usage: formatted = intl_FormatDateTimeRange(dateTimeFmt, x, y, formatToParts)
  */
-extern MOZ_MUST_USE bool intl_FormatDateTimeRange(JSContext* cx, unsigned argc,
-                                                  JS::Value* vp);
+[[nodiscard]] extern bool intl_FormatDateTimeRange(JSContext* cx, unsigned argc,
+                                                   JS::Value* vp);
 
 }  // namespace js
 
 #endif /* builtin_intl_DateTimeFormat_h */
--- a/js/src/builtin/intl/DisplayNames.h
+++ b/js/src/builtin/intl/DisplayNames.h
@@ -80,14 +80,14 @@ class DisplayNamesObject : public Native
 
 /**
  * Return the display name for the requested code or undefined if no applicable
  * display name was found.
  *
  * Usage: result = intl_ComputeDisplayName(displayNames, locale, calendar,
  *                                         style, fallback, type, code)
  */
-extern MOZ_MUST_USE bool intl_ComputeDisplayName(JSContext* cx, unsigned argc,
-                                                 Value* vp);
+[[nodiscard]] extern bool intl_ComputeDisplayName(JSContext* cx, unsigned argc,
+                                                  Value* vp);
 
 }  // namespace js
 
 #endif /* builtin_intl_DisplayNames_h */
--- a/js/src/builtin/intl/IntlObject.h
+++ b/js/src/builtin/intl/IntlObject.h
@@ -35,32 +35,32 @@ extern const JSClass IntlClass;
  *     1 for bn-IN
  *   weekendEnd
  *     an integer in the range 1=Sunday to 7=Saturday indicating the day
  *     considered the end of a weekend, e.g. 1 for en-US, 1 for en-GB,
  *     1 for bn-IN (note that "weekend" is *not* necessarily two days)
  *
  * NOTE: "calendar" and "locale" properties are *not* added to the object.
  */
-extern MOZ_MUST_USE bool intl_GetCalendarInfo(JSContext* cx, unsigned argc,
-                                              JS::Value* vp);
+[[nodiscard]] extern bool intl_GetCalendarInfo(JSContext* cx, unsigned argc,
+                                               JS::Value* vp);
 
 /**
  * Returns a plain object with locale information for a single valid locale
  * (callers must perform this validation).  The object will have these
  * properties:
  *
  *   direction
  *     a string with a value "ltr" for left-to-right locale, and "rtl" for
  *     right-to-left locale.
  *   locale
  *     a BCP47 compilant locale string for the resolved locale.
  */
-extern MOZ_MUST_USE bool intl_GetLocaleInfo(JSContext* cx, unsigned argc,
-                                            JS::Value* vp);
+[[nodiscard]] extern bool intl_GetLocaleInfo(JSContext* cx, unsigned argc,
+                                             JS::Value* vp);
 
 /**
  * Returns an Array with CLDR-based fields display names.
  * The function takes three arguments:
  *
  *   locale
  *     BCP47 compliant locale string
  *   style
@@ -91,43 +91,43 @@ extern MOZ_MUST_USE bool intl_GetLocaleI
  *
  * [
  *   'year',
  *   'January',
  *   'Monday',
  *   'AM'
  * ]
  */
-extern MOZ_MUST_USE bool intl_ComputeDisplayNames(JSContext* cx, unsigned argc,
-                                                  JS::Value* vp);
+[[nodiscard]] extern bool intl_ComputeDisplayNames(JSContext* cx, unsigned argc,
+                                                   JS::Value* vp);
 /**
  * Compares a BCP 47 language tag against the locales in availableLocales and
  * returns the best available match -- or |undefined| if no match was found.
  * Uses the fallback mechanism of RFC 4647, section 3.4.
  *
  * The set of available locales consulted doesn't necessarily include the
  * default locale or any generalized forms of it (e.g. "de" is a more-general
  * form of "de-CH"). If you want to be sure to consider the default local and
  * its generalized forms (you usually will), pass the default locale as the
  * value of |defaultOrNull|; otherwise pass null.
  *
  * Spec: ECMAScript Internationalization API Specification, 9.2.2.
  * Spec: RFC 4647, section 3.4.
  *
  * Usage: result = intl_BestAvailableLocale("Collator", locale, defaultOrNull)
  */
-extern MOZ_MUST_USE bool intl_BestAvailableLocale(JSContext* cx, unsigned argc,
-                                                  JS::Value* vp);
+[[nodiscard]] extern bool intl_BestAvailableLocale(JSContext* cx, unsigned argc,
+                                                   JS::Value* vp);
 
 /**
  * Returns the input locale in its canonicalized form if ICU supports that
  * locale (perhaps via fallback, e.g. supporting "de-ZA" through "de" support
  * implied by a "de-DE" locale). Otherwise uses the last-ditch locale.
  *
  * Usage: result = intl_supportedLocaleOrFallback(locale)
  */
-extern MOZ_MUST_USE bool intl_supportedLocaleOrFallback(JSContext* cx,
-                                                        unsigned argc,
-                                                        JS::Value* vp);
+[[nodiscard]] extern bool intl_supportedLocaleOrFallback(JSContext* cx,
+                                                         unsigned argc,
+                                                         JS::Value* vp);
 
 }  // namespace js
 
 #endif /* builtin_intl_IntlObject_h */
--- a/js/src/builtin/intl/LanguageTag.h
+++ b/js/src/builtin/intl/LanguageTag.h
@@ -752,17 +752,17 @@ class UnicodeExtensionKeyword final {
       : key_{key[0], key[1]}, type_(type) {}
 
   UnicodeKeySpan key() const { return {key_, sizeof(key_)}; }
   JSLinearString* type() const { return type_; }
 
   void trace(JSTracer* trc);
 };
 
-extern MOZ_MUST_USE bool ApplyUnicodeExtensionToTag(
+[[nodiscard]] extern bool ApplyUnicodeExtensionToTag(
     JSContext* cx, LanguageTag& tag,
     JS::HandleVector<UnicodeExtensionKeyword> keywords);
 
 }  // namespace intl
 
 }  // namespace js
 
 #endif /* builtin_intl_LanguageTag_h */
--- a/js/src/builtin/intl/ListFormat.h
+++ b/js/src/builtin/intl/ListFormat.h
@@ -57,14 +57,14 @@ class ListFormatObject : public NativeOb
 };
 
 /**
  * Returns a string representing the array of string values |list| according to
  * the effective locale and the formatting options of the given ListFormat.
  *
  * Usage: formatted = intl_FormatList(listFormat, list, formatToParts)
  */
-extern MOZ_MUST_USE bool intl_FormatList(JSContext* cx, unsigned argc,
-                                         Value* vp);
+[[nodiscard]] extern bool intl_FormatList(JSContext* cx, unsigned argc,
+                                          Value* vp);
 
 }  // namespace js
 
 #endif /* builtin_intl_ListFormat_h */
--- a/js/src/builtin/intl/Locale.h
+++ b/js/src/builtin/intl/Locale.h
@@ -42,21 +42,21 @@ class LocaleObject : public NativeObject
   const Value& unicodeExtension() const {
     return getFixedSlot(UNICODE_EXTENSION_SLOT);
   }
 
  private:
   static const ClassSpec classSpec_;
 };
 
-extern MOZ_MUST_USE bool intl_ValidateAndCanonicalizeLanguageTag(JSContext* cx,
-                                                                 unsigned argc,
-                                                                 Value* vp);
+[[nodiscard]] extern bool intl_ValidateAndCanonicalizeLanguageTag(JSContext* cx,
+                                                                  unsigned argc,
+                                                                  Value* vp);
 
-extern MOZ_MUST_USE bool intl_TryValidateAndCanonicalizeLanguageTag(
+[[nodiscard]] extern bool intl_TryValidateAndCanonicalizeLanguageTag(
     JSContext* cx, unsigned argc, Value* vp);
 
-extern MOZ_MUST_USE bool intl_ValidateAndCanonicalizeUnicodeExtensionType(
+[[nodiscard]] extern bool intl_ValidateAndCanonicalizeUnicodeExtensionType(
     JSContext* cx, unsigned argc, Value* vp);
 
 }  // namespace js
 
 #endif /* builtin_intl_Locale_h */
--- a/js/src/builtin/intl/NumberFormat.h
+++ b/js/src/builtin/intl/NumberFormat.h
@@ -71,50 +71,50 @@ class NumberFormatObject : public Native
 
 /**
  * Returns a new instance of the standard built-in NumberFormat constructor.
  * Self-hosted code cannot cache this constructor (as it does for others in
  * Utilities.js) because it is initialized after self-hosted code is compiled.
  *
  * Usage: numberFormat = intl_NumberFormat(locales, options)
  */
-extern MOZ_MUST_USE bool intl_NumberFormat(JSContext* cx, unsigned argc,
-                                           Value* vp);
+[[nodiscard]] extern bool intl_NumberFormat(JSContext* cx, unsigned argc,
+                                            Value* vp);
 
 /**
  * Returns the numbering system type identifier per Unicode
  * Technical Standard 35, Unicode Locale Data Markup Language, for the
  * default numbering system for the given locale.
  *
  * Usage: defaultNumberingSystem = intl_numberingSystem(locale)
  */
-extern MOZ_MUST_USE bool intl_numberingSystem(JSContext* cx, unsigned argc,
-                                              Value* vp);
+[[nodiscard]] extern bool intl_numberingSystem(JSContext* cx, unsigned argc,
+                                               Value* vp);
 
 /**
  * Returns a string representing the number x according to the effective
  * locale and the formatting options of the given NumberFormat.
  *
  * Spec: ECMAScript Internationalization API Specification, 11.3.2.
  *
  * Usage: formatted = intl_FormatNumber(numberFormat, x, formatToParts,
  *                                      unitStyle)
  */
-extern MOZ_MUST_USE bool intl_FormatNumber(JSContext* cx, unsigned argc,
-                                           Value* vp);
+[[nodiscard]] extern bool intl_FormatNumber(JSContext* cx, unsigned argc,
+                                            Value* vp);
 
 #if DEBUG || MOZ_SYSTEM_ICU
 /**
  * Returns an object with all available measurement units.
  *
  * Usage: units = intl_availableMeasurementUnits()
  */
-extern MOZ_MUST_USE bool intl_availableMeasurementUnits(JSContext* cx,
-                                                        unsigned argc,
-                                                        Value* vp);
+[[nodiscard]] extern bool intl_availableMeasurementUnits(JSContext* cx,
+                                                         unsigned argc,
+                                                         Value* vp);
 #endif
 
 namespace intl {
 
 /**
  * Class to create a number formatter skeleton.
  *
  * The skeleton syntax is documented at:
--- a/js/src/builtin/intl/PluralRules.h
+++ b/js/src/builtin/intl/PluralRules.h
@@ -89,27 +89,27 @@ class PluralRulesObject : public NativeO
  * Returns a plural rule for the number x according to the effective
  * locale and the formatting options of the given PluralRules.
  *
  * A plural rule is a grammatical category that expresses count distinctions
  * (such as "one", "two", "few" etc.).
  *
  * Usage: rule = intl_SelectPluralRule(pluralRules, x)
  */
-extern MOZ_MUST_USE bool intl_SelectPluralRule(JSContext* cx, unsigned argc,
-                                               JS::Value* vp);
+[[nodiscard]] extern bool intl_SelectPluralRule(JSContext* cx, unsigned argc,
+                                                JS::Value* vp);
 
 /**
  * Returns an array of plural rules categories for a given pluralRules object.
  *
  * Usage: categories = intl_GetPluralCategories(pluralRules)
  *
  * Example:
  *
  * pluralRules = new Intl.PluralRules('pl', {type: 'cardinal'});
  * intl_getPluralCategories(pluralRules); // ['one', 'few', 'many', 'other']
  */
-extern MOZ_MUST_USE bool intl_GetPluralCategories(JSContext* cx, unsigned argc,
-                                                  JS::Value* vp);
+[[nodiscard]] extern bool intl_GetPluralCategories(JSContext* cx, unsigned argc,
+                                                   JS::Value* vp);
 
 }  // namespace js
 
 #endif /* builtin_intl_PluralRules_h */
--- a/js/src/builtin/intl/RelativeTimeFormat.h
+++ b/js/src/builtin/intl/RelativeTimeFormat.h
@@ -64,18 +64,18 @@ class RelativeTimeFormatObject : public 
  * |t| should be a number representing a number to be formatted.
  * |unit| should be "second", "minute", "hour", "day", "week", "month",
  *                  "quarter", or "year".
  * |numeric| should be "always" or "auto".
  *
  * Usage: formatted = intl_FormatRelativeTime(relativeTimeFormat, t,
  *                                            unit, numeric, formatToParts)
  */
-extern MOZ_MUST_USE bool intl_FormatRelativeTime(JSContext* cx, unsigned argc,
-                                                 JS::Value* vp);
+[[nodiscard]] extern bool intl_FormatRelativeTime(JSContext* cx, unsigned argc,
+                                                  JS::Value* vp);
 
 namespace intl {
 
 using FieldType = js::ImmutablePropertyNamePtr JSAtomState::*;
 
 [[nodiscard]] bool FormattedRelativeTimeToParts(
     JSContext* cx, const UFormattedValue* formattedValue, double timeValue,
     FieldType relativeTimeUnit, MutableHandleValue result);
--- a/js/src/builtin/streams/MiscellaneousOperations-inl.h
+++ b/js/src/builtin/streams/MiscellaneousOperations-inl.h
@@ -29,20 +29,20 @@
 
 namespace js {
 
 /**
  * Streams spec, 6.3.5. PromiseCall ( F, V, args )
  * There must be 0-2 |args| arguments, all convertible to JS::Handle<JS::Value>.
  */
 template <class... Args>
-inline MOZ_MUST_USE JSObject* PromiseCall(JSContext* cx,
-                                          JS::Handle<JS::Value> F,
-                                          JS::Handle<JS::Value> V,
-                                          Args&&... args) {
+[[nodiscard]] inline JSObject* PromiseCall(JSContext* cx,
+                                           JS::Handle<JS::Value> F,
+                                           JS::Handle<JS::Value> V,
+                                           Args&&... args) {
   cx->check(F);
   cx->check(V);
   cx->check(args...);
 
   // Step 1: Assert: ! IsCallable(F) is true.
   MOZ_ASSERT(IsCallable(F));
 
   // Step 2: Assert: V is not undefined.
@@ -59,57 +59,57 @@ inline MOZ_MUST_USE JSObject* PromiseCal
 
   // Step 6: Otherwise, return a promise resolved with returnValue.[[Value]].
   return PromiseObject::unforgeableResolve(cx, rval);
 }
 
 /**
  * Resolve the unwrapped promise |unwrappedPromise| with |value|.
  */
-inline MOZ_MUST_USE bool ResolveUnwrappedPromiseWithValue(
+[[nodiscard]] inline bool ResolveUnwrappedPromiseWithValue(
     JSContext* cx, JSObject* unwrappedPromise, JS::Handle<JS::Value> value) {
   cx->check(value);
 
   JS::Rooted<JSObject*> promise(cx, unwrappedPromise);
   if (!cx->compartment()->wrap(cx, &promise)) {
     return false;
   }
 
   return JS::ResolvePromise(cx, promise, value);
 }
 
 /**
  * Resolve the unwrapped promise |unwrappedPromise| with |undefined|.
  */
-inline MOZ_MUST_USE bool ResolveUnwrappedPromiseWithUndefined(
+[[nodiscard]] inline bool ResolveUnwrappedPromiseWithUndefined(
     JSContext* cx, JSObject* unwrappedPromise) {
   return ResolveUnwrappedPromiseWithValue(cx, unwrappedPromise,
                                           JS::UndefinedHandleValue);
 }
 
 /**
  * Reject the unwrapped promise |unwrappedPromise| with |error|, overwriting
  * |*unwrappedPromise| with its wrapped form.
  */
-inline MOZ_MUST_USE bool RejectUnwrappedPromiseWithError(
+[[nodiscard]] inline bool RejectUnwrappedPromiseWithError(
     JSContext* cx, JS::MutableHandle<JSObject*> unwrappedPromise,
     JS::Handle<JS::Value> error) {
   cx->check(error);
 
   if (!cx->compartment()->wrap(cx, unwrappedPromise)) {
     return false;
   }
 
   return JS::RejectPromise(cx, unwrappedPromise, error);
 }
 
 /**
  * Reject the unwrapped promise |unwrappedPromise| with |error|.
  */
-inline MOZ_MUST_USE bool RejectUnwrappedPromiseWithError(
+[[nodiscard]] inline bool RejectUnwrappedPromiseWithError(
     JSContext* cx, JSObject* unwrappedPromise, JS::Handle<JS::Value> error) {
   JS::Rooted<JSObject*> promise(cx, unwrappedPromise);
   return RejectUnwrappedPromiseWithError(cx, &promise, error);
 }
 
 }  // namespace js
 
 #endif  // builtin_streams_MiscellaneousOperations_inl_h
--- a/js/src/builtin/streams/MiscellaneousOperations.h
+++ b/js/src/builtin/streams/MiscellaneousOperations.h
@@ -19,20 +19,20 @@
 #include "vm/PromiseObject.h"  // js::PromiseObject
 
 struct JS_PUBLIC_API JSContext;
 
 namespace js {
 
 class PropertyName;
 
-extern MOZ_MUST_USE PromiseObject* PromiseRejectedWithPendingError(
+[[nodiscard]] extern PromiseObject* PromiseRejectedWithPendingError(
     JSContext* cx);
 
-inline MOZ_MUST_USE bool ReturnPromiseRejectedWithPendingError(
+[[nodiscard]] inline bool ReturnPromiseRejectedWithPendingError(
     JSContext* cx, const JS::CallArgs& args) {
   PromiseObject* promise = PromiseRejectedWithPendingError(cx);
   if (!promise) {
     return false;
   }
 
   args.rval().setObject(*promise);
   return true;
@@ -44,41 +44,41 @@ inline MOZ_MUST_USE bool ReturnPromiseRe
  *                                            algoArgCount, extraArgs )
  *
  * This function only partly implements the standard algorithm. We do not
  * actually create a new JSFunction completely encapsulating the new algorithm.
  * Instead, this just gets the specified method and checks for errors. It's the
  * caller's responsibility to make sure that later, when the algorithm is
  * "performed", the appropriate steps are carried out.
  */
-extern MOZ_MUST_USE bool CreateAlgorithmFromUnderlyingMethod(
+[[nodiscard]] extern bool CreateAlgorithmFromUnderlyingMethod(
     JSContext* cx, JS::Handle<JS::Value> underlyingObject,
     const char* methodNameForErrorMessage, JS::Handle<PropertyName*> methodName,
     JS::MutableHandle<JS::Value> method);
 
 /**
  * Streams spec, 6.3.2. InvokeOrNoop ( O, P, args )
  * As it happens, all callers pass exactly one argument.
  */
-extern MOZ_MUST_USE bool InvokeOrNoop(JSContext* cx, JS::Handle<JS::Value> O,
-                                      JS::Handle<PropertyName*> P,
-                                      JS::Handle<JS::Value> arg,
-                                      JS::MutableHandle<JS::Value> rval);
+[[nodiscard]] extern bool InvokeOrNoop(JSContext* cx, JS::Handle<JS::Value> O,
+                                       JS::Handle<PropertyName*> P,
+                                       JS::Handle<JS::Value> arg,
+                                       JS::MutableHandle<JS::Value> rval);
 
 /**
  * Streams spec, 6.3.7. ValidateAndNormalizeHighWaterMark ( highWaterMark )
  */
-extern MOZ_MUST_USE bool ValidateAndNormalizeHighWaterMark(
+[[nodiscard]] extern bool ValidateAndNormalizeHighWaterMark(
     JSContext* cx, JS::Handle<JS::Value> highWaterMarkVal,
     double* highWaterMark);
 
 /**
  * Streams spec, 6.3.8. MakeSizeAlgorithmFromSizeFunction ( size )
  */
-extern MOZ_MUST_USE bool MakeSizeAlgorithmFromSizeFunction(
+[[nodiscard]] extern bool MakeSizeAlgorithmFromSizeFunction(
     JSContext* cx, JS::Handle<JS::Value> size);
 
 template <class T>
 inline bool IsMaybeWrapped(const JS::Handle<JS::Value> v) {
   return v.isObject() && v.toObject().canUnwrapAs<T>();
 }
 
 }  // namespace js
--- a/js/src/builtin/streams/PipeToState-inl.h
+++ b/js/src/builtin/streams/PipeToState-inl.h
@@ -33,17 +33,17 @@ namespace js {
  * operation.
  *
  * The pipe-to operation must be known to have had an |AbortSignal| associated
  * with it.
  *
  * If the signal is a wrapper, it will be unwrapped, so the result might not be
  * an object from the currently active compartment.
  */
-inline MOZ_MUST_USE JSObject* UnwrapSignalFromPipeToState(
+[[nodiscard]] inline JSObject* UnwrapSignalFromPipeToState(
     JSContext* cx, JS::Handle<PipeToState*> pipeToState) {
   cx->check(pipeToState);
 
   MOZ_ASSERT(pipeToState->hasSignal());
   return UnwrapAndDowncastValue(
       cx, pipeToState->getFixedSlot(PipeToState::Slot_Signal),
       cx->runtime()->maybeAbortSignalClass());
 }
--- a/js/src/builtin/streams/PipeToState.cpp
+++ b/js/src/builtin/streams/PipeToState.cpp
@@ -91,18 +91,18 @@ static WritableStream* GetUnwrappedDest(
   return UnwrapStreamFromWriter(cx, writer);
 }
 
 static bool WritableAndNotClosing(const WritableStream* unwrappedDest) {
   return unwrappedDest->writable() &&
          WritableStreamCloseQueuedOrInFlight(unwrappedDest);
 }
 
-static MOZ_MUST_USE bool Finalize(JSContext* cx, Handle<PipeToState*> state,
-                                  Handle<Maybe<Value>> error) {
+[[nodiscard]] static bool Finalize(JSContext* cx, Handle<PipeToState*> state,
+                                   Handle<Maybe<Value>> error) {
   cx->check(state);
   cx->check(error);
 
   // Step 1: Perform ! WritableStreamDefaultWriterRelease(writer).
   Rooted<WritableStreamDefaultWriter*> writer(cx, state->writer());
   cx->check(writer);
   if (!WritableStreamDefaultWriterRelease(cx, writer)) {
     return false;
@@ -126,17 +126,17 @@ static MOZ_MUST_USE bool Finalize(JSCont
     Rooted<Value> errorVal(cx, *error.get());
     return PromiseObject::reject(cx, promise, errorVal);
   }
 
   // Step 5: Otherwise, resolve promise with undefined.
   return PromiseObject::resolve(cx, promise, UndefinedHandleValue);
 }
 
-static MOZ_MUST_USE bool Finalize(JSContext* cx, unsigned argc, Value* vp) {
+[[nodiscard]] static bool Finalize(JSContext* cx, unsigned argc, Value* vp) {
   CallArgs args = CallArgsFromVp(argc, vp);
 
   Rooted<PipeToState*> state(cx, TargetFromHandler<PipeToState>(args));
   cx->check(state);
 
   Rooted<Maybe<Value>> optionalError(cx, Nothing());
   if (Value maybeError = ExtraValueFromHandler(args);
       !maybeError.isMagic(JS_READABLESTREAM_PIPETO_FINALIZE_WITHOUT_ERROR)) {
@@ -152,19 +152,19 @@ static MOZ_MUST_USE bool Finalize(JSCont
   return true;
 }
 
 // Shutdown with an action, steps d-f:
 //   d. Let p be the result of performing action.
 //   e. Upon fulfillment of p, finalize, passing along originalError if it was
 //      given.
 //   f. Upon rejection of p with reason newError, finalize with newError.
-static MOZ_MUST_USE bool ActAndFinalize(JSContext* cx,
-                                        Handle<PipeToState*> state,
-                                        Handle<Maybe<Value>> error) {
+[[nodiscard]] static bool ActAndFinalize(JSContext* cx,
+                                         Handle<PipeToState*> state,
+                                         Handle<Maybe<Value>> error) {
   // Step d: Let p be the result of performing action.
   Rooted<JSObject*> p(cx);
   switch (state->shutdownAction()) {
     // This corresponds to the action performed by |abortAlgorithm| in
     // ReadableStreamPipeTo step 14.1.5.
     case PipeToState::ShutdownAction::AbortAlgorithm: {
       MOZ_ASSERT(error.get().isSome());
 
@@ -285,18 +285,18 @@ static MOZ_MUST_USE bool ActAndFinalize(
   Rooted<JSFunction*> onRejected(cx, NewHandler(cx, OnRejected, state));
   if (!onRejected) {
     return false;
   }
 
   return JS::AddPromiseReactions(cx, p, onFulfilled, onRejected);
 }
 
-static MOZ_MUST_USE bool ActAndFinalize(JSContext* cx, unsigned argc,
-                                        Value* vp) {
+[[nodiscard]] static bool ActAndFinalize(JSContext* cx, unsigned argc,
+                                         Value* vp) {
   CallArgs args = CallArgsFromVp(argc, vp);
 
   Rooted<PipeToState*> state(cx, TargetFromHandler<PipeToState>(args));
   cx->check(state);
 
   Rooted<Maybe<Value>> optionalError(cx, Nothing());
   if (Value maybeError = ExtraValueFromHandler(args);
       !maybeError.isMagic(JS_READABLESTREAM_PIPETO_FINALIZE_WITHOUT_ERROR)) {
@@ -309,17 +309,17 @@ static MOZ_MUST_USE bool ActAndFinalize(
   }
 
   args.rval().setUndefined();
   return true;
 }
 
 // Shutdown with an action: if any of the above requirements ask to shutdown
 // with an action action, optionally with an error originalError, then:
-static MOZ_MUST_USE bool ShutdownWithAction(
+[[nodiscard]] static bool ShutdownWithAction(
     JSContext* cx, Handle<PipeToState*> state,
     PipeToState::ShutdownAction action, Handle<Maybe<Value>> originalError) {
   cx->check(state);
   cx->check(originalError);
 
   // Step a: If shuttingDown is true, abort these substeps.
   if (state->shuttingDown()) {
     return true;
@@ -376,18 +376,18 @@ static MOZ_MUST_USE bool ShutdownWithAct
   // Step e: Upon fulfillment of p, finalize, passing along originalError if it
   //         was given.
   // Step f: Upon rejection of p with reason newError, finalize with newError.
   return ActAndFinalize(cx, state, originalError);
 }
 
 // Shutdown: if any of the above requirements or steps ask to shutdown,
 // optionally with an error error, then:
-static MOZ_MUST_USE bool Shutdown(JSContext* cx, Handle<PipeToState*> state,
-                                  Handle<Maybe<Value>> error) {
+[[nodiscard]] static bool Shutdown(JSContext* cx, Handle<PipeToState*> state,
+                                   Handle<Maybe<Value>> error) {
   cx->check(state);
   cx->check(error);
 
   // Step a: If shuttingDown is true, abort these substeps.
   if (state->shuttingDown()) {
     return true;
   }
 
@@ -438,17 +438,17 @@ static MOZ_MUST_USE bool Shutdown(JSCont
   return Finalize(cx, state, error);
 }
 
 /**
  * Streams spec, 3.4.11. ReadableStreamPipeTo step 14:
  * "a. Errors must be propagated forward: if source.[[state]] is or becomes
  * 'errored', then..."
  */
-static MOZ_MUST_USE bool OnSourceErrored(
+[[nodiscard]] static bool OnSourceErrored(
     JSContext* cx, Handle<PipeToState*> state,
     Handle<ReadableStream*> unwrappedSource) {
   cx->check(state);
 
   Rooted<Maybe<Value>> storedError(cx, Some(unwrappedSource->storedError()));
   if (!cx->compartment()->wrap(cx, &storedError)) {
     return false;
   }
@@ -505,19 +505,19 @@ static MOZ_MUST_USE bool OnSourceErrored
   return true;
 }
 
 /**
  * Streams spec, 3.4.11. ReadableStreamPipeTo step 14:
  * "b. Errors must be propagated backward: if dest.[[state]] is or becomes
  * 'errored', then..."
  */
-static MOZ_MUST_USE bool OnDestErrored(JSContext* cx,
-                                       Handle<PipeToState*> state,
-                                       Handle<WritableStream*> unwrappedDest) {
+[[nodiscard]] static bool OnDestErrored(JSContext* cx,
+                                        Handle<PipeToState*> state,
+                                        Handle<WritableStream*> unwrappedDest) {
   cx->check(state);
 
   Rooted<Maybe<Value>> storedError(cx, Some(unwrappedDest->storedError()));
   if (!cx->compartment()->wrap(cx, &storedError)) {
     return false;
   }
 
   // As in |OnSourceErrored| above, we must deal with the case of |dest|
@@ -549,18 +549,18 @@ static MOZ_MUST_USE bool OnDestErrored(J
   return true;
 }
 
 /**
  * Streams spec, 3.4.11. ReadableStreamPipeTo step 14:
  * "c. Closing must be propagated forward: if source.[[state]] is or becomes
  * 'closed', then..."
  */
-static MOZ_MUST_USE bool OnSourceClosed(JSContext* cx,
-                                        Handle<PipeToState*> state) {
+[[nodiscard]] static bool OnSourceClosed(JSContext* cx,
+                                         Handle<PipeToState*> state) {
   cx->check(state);
 
   Rooted<Maybe<Value>> noError(cx, Nothing());
 
   // It shouldn't be possible for |source| to become closed *during* a pending
   // read: such spontaneous closure *should* be enqueued for processing *after*
   // the settling of the pending read.  (Note also that a [[closedPromise]]
   // resolution in |ReadableStreamClose| occurs only after all pending reads are
@@ -588,18 +588,18 @@ static MOZ_MUST_USE bool OnSourceClosed(
 }
 
 /**
  * Streams spec, 3.4.11. ReadableStreamPipeTo step 14:
  * "d. Closing must be propagated backward: if
  * ! WritableStreamCloseQueuedOrInFlight(dest) is true or dest.[[state]] is
  * 'closed', then..."
  */
-static MOZ_MUST_USE bool OnDestClosed(JSContext* cx,
-                                      Handle<PipeToState*> state) {
+[[nodiscard]] static bool OnDestClosed(JSContext* cx,
+                                       Handle<PipeToState*> state) {
   cx->check(state);
 
   // i. Assert: no chunks have been read or written.
   //
   // This assertion holds when this function is called by
   // |SourceOrDestErroredOrClosed|, before any async internal piping operations
   // happen.
   //
@@ -653,17 +653,17 @@ static MOZ_MUST_USE bool OnDestClosed(JS
 }
 
 /**
  * Streams spec, 3.4.11. ReadableStreamPipeTo step 14:
  * "Error and close states must be propagated: the following conditions must be
  * applied in order.", as applied at the very start of piping, before any reads
  * from source or writes to dest have been triggered.
  */
-static MOZ_MUST_USE bool SourceOrDestErroredOrClosed(
+[[nodiscard]] static bool SourceOrDestErroredOrClosed(
     JSContext* cx, Handle<PipeToState*> state,
     Handle<ReadableStream*> unwrappedSource,
     Handle<WritableStream*> unwrappedDest, bool* erroredOrClosed) {
   cx->check(state);
 
   *erroredOrClosed = true;
 
   // a. Errors must be propagated forward: if source.[[state]] is or becomes
@@ -691,33 +691,33 @@ static MOZ_MUST_USE bool SourceOrDestErr
       unwrappedDest->closed()) {
     return OnDestClosed(cx, state);
   }
 
   *erroredOrClosed = false;
   return true;
 }
 
-static MOZ_MUST_USE bool OnSourceClosed(JSContext* cx, unsigned argc,
-                                        Value* vp) {
+[[nodiscard]] static bool OnSourceClosed(JSContext* cx, unsigned argc,
+                                         Value* vp) {
   CallArgs args = CallArgsFromVp(argc, vp);
 
   Rooted<PipeToState*> state(cx, TargetFromHandler<PipeToState>(args));
   cx->check(state);
 
   if (!OnSourceClosed(cx, state)) {
     return false;
   }
 
   args.rval().setUndefined();
   return true;
 }
 
-static MOZ_MUST_USE bool OnSourceErrored(JSContext* cx, unsigned argc,
-                                         Value* vp) {
+[[nodiscard]] static bool OnSourceErrored(JSContext* cx, unsigned argc,
+                                          Value* vp) {
   CallArgs args = CallArgsFromVp(argc, vp);
 
   Rooted<PipeToState*> state(cx, TargetFromHandler<PipeToState>(args));
   cx->check(state);
 
   Rooted<ReadableStream*> unwrappedSource(cx, GetUnwrappedSource(cx, state));
   if (!unwrappedSource) {
     return false;
@@ -726,32 +726,33 @@ static MOZ_MUST_USE bool OnSourceErrored
   if (!OnSourceErrored(cx, state, unwrappedSource)) {
     return false;
   }
 
   args.rval().setUndefined();
   return true;
 }
 
-static MOZ_MUST_USE bool OnDestClosed(JSContext* cx, unsigned argc, Value* vp) {
+[[nodiscard]] static bool OnDestClosed(JSContext* cx, unsigned argc,
+                                       Value* vp) {
   CallArgs args = CallArgsFromVp(argc, vp);
 
   Rooted<PipeToState*> state(cx, TargetFromHandler<PipeToState>(args));
   cx->check(state);
 
   if (!OnDestClosed(cx, state)) {
     return false;
   }
 
   args.rval().setUndefined();
   return true;
 }
 
-static MOZ_MUST_USE bool OnDestErrored(JSContext* cx, unsigned argc,
-                                       Value* vp) {
+[[nodiscard]] static bool OnDestErrored(JSContext* cx, unsigned argc,
+                                        Value* vp) {
   CallArgs args = CallArgsFromVp(argc, vp);
 
   Rooted<PipeToState*> state(cx, TargetFromHandler<PipeToState>(args));
   cx->check(state);
 
   Rooted<WritableStream*> unwrappedDest(cx, GetUnwrappedDest(cx, state));
   if (!unwrappedDest) {
     return false;
@@ -773,18 +774,18 @@ static inline JSObject* GetClosedPromise
       unwrapAccessorFromStream(cx, unwrappedStream);
   if (!unwrappedAccessor) {
     return nullptr;
   }
 
   return unwrappedAccessor->closedPromise();
 }
 
-static MOZ_MUST_USE bool ReadFromSource(JSContext* cx,
-                                        Handle<PipeToState*> state);
+[[nodiscard]] static bool ReadFromSource(JSContext* cx,
+                                         Handle<PipeToState*> state);
 
 static bool ReadFulfilled(JSContext* cx, Handle<PipeToState*> state,
                           Handle<JSObject*> result) {
   cx->check(state);
   cx->check(result);
 
   state->clearPendingRead();
 
@@ -875,18 +876,18 @@ static bool ReadFulfilled(JSContext* cx,
   }
 
   args.rval().setUndefined();
   return true;
 }
 
 static bool ReadFromSource(JSContext* cx, unsigned argc, Value* vp);
 
-static MOZ_MUST_USE bool ReadFromSource(JSContext* cx,
-                                        Handle<PipeToState*> state) {
+[[nodiscard]] static bool ReadFromSource(JSContext* cx,
+                                         Handle<PipeToState*> state) {
   cx->check(state);
 
   MOZ_ASSERT(!state->hasPendingRead(),
              "should only have one read in flight at a time, because multiple "
              "reads could cause the latter read to ignore backpressure "
              "signals");
 
   // "Shutdown must stop activity: if shuttingDown becomes true, the user agent
@@ -1029,19 +1030,19 @@ static bool ReadFromSource(JSContext* cx
   if (!ReadFromSource(cx, state)) {
     return false;
   }
 
   args.rval().setUndefined();
   return true;
 }
 
-static MOZ_MUST_USE bool StartPiping(JSContext* cx, Handle<PipeToState*> state,
-                                     Handle<ReadableStream*> unwrappedSource,
-                                     Handle<WritableStream*> unwrappedDest) {
+[[nodiscard]] static bool StartPiping(JSContext* cx, Handle<PipeToState*> state,
+                                      Handle<ReadableStream*> unwrappedSource,
+                                      Handle<WritableStream*> unwrappedDest) {
   cx->check(state);
 
   // "Shutdown must stop activity: if shuttingDown becomes true, the user agent
   // must not initiate further reads from reader..."
   MOZ_ASSERT(!state->shuttingDown(), "can't be shutting down when starting");
 
   // "Error and close states must be propagated: the following conditions must
   // be applied in order."
@@ -1106,18 +1107,18 @@ static MOZ_MUST_USE bool StartPiping(JSC
 }
 
 /**
  * Stream spec, 4.8.1. ReadableStreamPipeTo ( source, dest,
  *                                            preventClose, preventAbort,
  *                                            preventCancel[, signal] )
  * Step 14.1 abortAlgorithm.
  */
-static MOZ_MUST_USE bool PerformAbortAlgorithm(JSContext* cx,
-                                               Handle<PipeToState*> state) {
+[[nodiscard]] static bool PerformAbortAlgorithm(JSContext* cx,
+                                                Handle<PipeToState*> state) {
   cx->check(state);
 
   // Step 14.1: Let abortAlgorithm be the following steps:
   // Step 14.1.1: Let error be a new "AbortError" DOMException.
   // Step 14.1.2: Let actions be an empty ordered set.
   // Step 14.1.3: If preventAbort is false, append the following action to
   //              actions:
   // Step 14.1.3.1: If dest.[[state]] is "writable", return
--- a/js/src/builtin/streams/QueueWithSizes-inl.h
+++ b/js/src/builtin/streams/QueueWithSizes-inl.h
@@ -52,17 +52,17 @@ inline void QueueRemoveFirstValueAndSize
   MOZ_ASSERT(!unwrappedQueue->isEmpty(),
              "can't remove first value from an empty queue-with-sizes");
   MOZ_ASSERT((unwrappedQueue->length() % 2) == 0,
              "queue-with-sizes must consist of (value, size) element pairs and "
              "so must have even length");
   unwrappedQueue->popFirstPair(cx);
 }
 
-inline MOZ_MUST_USE bool QueueAppendValueAndSize(
+[[nodiscard]] inline bool QueueAppendValueAndSize(
     JSContext* cx, JS::Handle<ListObject*> unwrappedQueue,
     JS::Handle<JS::Value> value, double size) {
   return unwrappedQueue->appendValueAndSize(cx, value, size);
 }
 
 }  // namespace detail
 
 /**
--- a/js/src/builtin/streams/QueueWithSizes.h
+++ b/js/src/builtin/streams/QueueWithSizes.h
@@ -21,37 +21,37 @@ struct JS_PUBLIC_API JSContext;
 
 namespace js {
 
 class StreamController;
 
 /**
  * Streams spec, 6.2.1. DequeueValue ( container ) nothrow
  */
-extern MOZ_MUST_USE bool DequeueValue(
+[[nodiscard]] extern bool DequeueValue(
     JSContext* cx, JS::Handle<StreamController*> unwrappedContainer,
     JS::MutableHandle<JS::Value> chunk);
 
 /**
  * Streams spec, 6.2.1. DequeueValue ( container ) nothrow
  * when the dequeued value is ignored.
  */
 extern void DequeueValue(StreamController* unwrappedContainer, JSContext* cx);
 
 /**
  * Streams spec, 6.2.2. EnqueueValueWithSize ( container, value, size ) throws
  */
-extern MOZ_MUST_USE bool EnqueueValueWithSize(
+[[nodiscard]] extern bool EnqueueValueWithSize(
     JSContext* cx, JS::Handle<StreamController*> unwrappedContainer,
     JS::Handle<JS::Value> value, JS::Handle<JS::Value> sizeVal);
 
 /**
  * Streams spec, 6.2.4. ResetQueue ( container ) nothrow
  */
-extern MOZ_MUST_USE bool ResetQueue(
+[[nodiscard]] extern bool ResetQueue(
     JSContext* cx, JS::Handle<StreamController*> unwrappedContainer);
 
 inline bool QueueIsEmpty(ListObject* unwrappedQueue) {
   if (unwrappedQueue->isEmpty()) {
     return true;
   }
 
   MOZ_ASSERT((unwrappedQueue->length() % 2) == 0,
--- a/js/src/builtin/streams/QueueingStrategies.cpp
+++ b/js/src/builtin/streams/QueueingStrategies.cpp
@@ -34,21 +34,21 @@ using JS::Rooted;
 using JS::ToObject;
 using JS::Value;
 
 /*** 6.1. Queuing strategies ************************************************/
 
 /**
  * ECMA-262 7.3.4 CreateDataProperty(O, P, V)
  */
-static MOZ_MUST_USE bool CreateDataProperty(JSContext* cx,
-                                            Handle<JSObject*> obj,
-                                            Handle<PropertyName*> key,
-                                            Handle<Value> value,
-                                            ObjectOpResult& result) {
+[[nodiscard]] static bool CreateDataProperty(JSContext* cx,
+                                             Handle<JSObject*> obj,
+                                             Handle<PropertyName*> key,
+                                             Handle<Value> value,
+                                             ObjectOpResult& result) {
   Rooted<jsid> id(cx, js::NameToId(key));
   Rooted<JS::PropertyDescriptor> desc(cx);
   desc.setDataDescriptor(value, JSPROP_ENUMERATE);
   return js::DefineProperty(cx, obj, id, desc, result);
 }
 
 // Streams spec, 6.1.2.2. new ByteLengthQueuingStrategy({ highWaterMark })
 bool js::ByteLengthQueuingStrategy::constructor(JSContext* cx, unsigned argc,
--- a/js/src/builtin/streams/ReadableStream.cpp
+++ b/js/src/builtin/streams/ReadableStream.cpp
@@ -214,18 +214,18 @@ bool ReadableStream::constructor(JSConte
   JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
                             JSMSG_READABLESTREAM_UNDERLYINGSOURCE_TYPE_WRONG);
   return false;
 }
 
 /**
  * Streams spec, 3.2.5.1. get locked
  */
-static MOZ_MUST_USE bool ReadableStream_locked(JSContext* cx, unsigned argc,
-                                               JS::Value* vp) {
+[[nodiscard]] static bool ReadableStream_locked(JSContext* cx, unsigned argc,
+                                                JS::Value* vp) {
   CallArgs args = CallArgsFromVp(argc, vp);
 
   // Step 1: If ! IsReadableStream(this) is false, throw a TypeError exception.
   Rooted<ReadableStream*> unwrappedStream(
       cx, UnwrapAndTypeCheckThis<ReadableStream>(cx, args, "get locked"));
   if (!unwrappedStream) {
     return false;
   }
@@ -233,18 +233,18 @@ static MOZ_MUST_USE bool ReadableStream_
   // Step 2: Return ! IsReadableStreamLocked(this).
   args.rval().setBoolean(unwrappedStream->locked());
   return true;
 }
 
 /**
  * Streams spec, 3.2.5.2. cancel ( reason )
  */
-static MOZ_MUST_USE bool ReadableStream_cancel(JSContext* cx, unsigned argc,
-                                               JS::Value* vp) {
+[[nodiscard]] static bool ReadableStream_cancel(JSContext* cx, unsigned argc,
+                                                JS::Value* vp) {
   CallArgs args = CallArgsFromVp(argc, vp);
 
   // Step 1: If ! IsReadableStream(this) is false, return a promise rejected
   //         with a TypeError exception.
   Rooted<ReadableStream*> unwrappedStream(
       cx, UnwrapAndTypeCheckThis<ReadableStream>(cx, args, "cancel"));
   if (!unwrappedStream) {
     return ReturnPromiseRejectedWithPendingError(cx, args);
@@ -271,18 +271,18 @@ static MOZ_MUST_USE bool ReadableStream_
 // Streams spec, 3.2.5.3.
 //      getIterator({ preventCancel } = {})
 //
 // Not implemented.
 
 /**
  * Streams spec, 3.2.5.4. getReader({ mode } = {})
  */
-static MOZ_MUST_USE bool ReadableStream_getReader(JSContext* cx, unsigned argc,
-                                                  JS::Value* vp) {
+[[nodiscard]] static bool ReadableStream_getReader(JSContext* cx, unsigned argc,
+                                                   JS::Value* vp) {
   CallArgs args = CallArgsFromVp(argc, vp);
 
   // Implicit in the spec: Argument defaults and destructuring.
   Rooted<Value> optionsVal(cx, args.get(0));
   if (optionsVal.isUndefined()) {
     JSObject* emptyObj = NewBuiltinClassInstance<PlainObject>(cx);
     if (!emptyObj) {
       return false;
--- a/js/src/builtin/streams/ReadableStream.h
+++ b/js/src/builtin/streams/ReadableStream.h
@@ -110,30 +110,30 @@ class ReadableStream : public NativeObje
   void setStoredError(JS::Handle<JS::Value> value) {
     setFixedSlot(Slot_StoredError, value);
   }
 
   JS::ReadableStreamMode mode() const;
 
   bool locked() const;
 
-  static MOZ_MUST_USE ReadableStream* create(
+  [[nodiscard]] static ReadableStream* create(
       JSContext* cx, void* nsISupportsObject_alreadyAddreffed = nullptr,
       JS::Handle<JSObject*> proto = nullptr);
   static ReadableStream* createExternalSourceStream(
       JSContext* cx, JS::ReadableStreamUnderlyingSource* source,
       void* nsISupportsObject_alreadyAddreffed = nullptr,
       JS::Handle<JSObject*> proto = nullptr);
 
   static bool constructor(JSContext* cx, unsigned argc, Value* vp);
   static const ClassSpec classSpec_;
   static const JSClass class_;
   static const ClassSpec protoClassSpec_;
   static const JSClass protoClass_;
 };
 
-extern MOZ_MUST_USE bool SetUpExternalReadableByteStreamController(
+[[nodiscard]] extern bool SetUpExternalReadableByteStreamController(
     JSContext* cx, JS::Handle<ReadableStream*> stream,
     JS::ReadableStreamUnderlyingSource* source);
 
 }  // namespace js
 
 #endif  // builtin_streams_ReadableStream_h
--- a/js/src/builtin/streams/ReadableStreamController.h
+++ b/js/src/builtin/streams/ReadableStreamController.h
@@ -216,21 +216,21 @@ class ReadableByteStreamController : pub
 
   static bool constructor(JSContext* cx, unsigned argc, JS::Value* vp);
   static const ClassSpec classSpec_;
   static const JSClass class_;
   static const ClassSpec protoClassSpec_;
   static const JSClass protoClass_;
 };
 
-extern MOZ_MUST_USE bool CheckReadableStreamControllerCanCloseOrEnqueue(
+[[nodiscard]] extern bool CheckReadableStreamControllerCanCloseOrEnqueue(
     JSContext* cx, JS::Handle<ReadableStreamController*> unwrappedController,
     const char* action);
 
-extern MOZ_MUST_USE JSObject* ReadableStreamControllerCancelSteps(
+[[nodiscard]] extern JSObject* ReadableStreamControllerCancelSteps(
     JSContext* cx, JS::Handle<ReadableStreamController*> unwrappedController,
     JS::Handle<JS::Value> reason);
 
 extern PromiseObject* ReadableStreamDefaultControllerPullSteps(
     JSContext* cx,
     JS::Handle<ReadableStreamDefaultController*> unwrappedController);
 
 extern bool ReadableStreamControllerStartHandler(JSContext* cx, unsigned argc,
--- a/js/src/builtin/streams/ReadableStreamDefaultControllerOperations.h
+++ b/js/src/builtin/streams/ReadableStreamDefaultControllerOperations.h
@@ -18,56 +18,56 @@
 struct JS_PUBLIC_API JSContext;
 
 namespace js {
 
 class ReadableStream;
 class ReadableStreamController;
 class ReadableStreamDefaultController;
 
-extern MOZ_MUST_USE bool ReadableStreamDefaultControllerEnqueue(
+[[nodiscard]] extern bool ReadableStreamDefaultControllerEnqueue(
     JSContext* cx,
     JS::Handle<ReadableStreamDefaultController*> unwrappedController,
     JS::Handle<JS::Value> chunk);
 
-extern MOZ_MUST_USE bool ReadableStreamControllerError(
+[[nodiscard]] extern bool ReadableStreamControllerError(
     JSContext* cx, JS::Handle<ReadableStreamController*> unwrappedController,
     JS::Handle<JS::Value> e);
 
-extern MOZ_MUST_USE bool ReadableStreamDefaultControllerClose(
+[[nodiscard]] extern bool ReadableStreamDefaultControllerClose(
     JSContext* cx,
     JS::Handle<ReadableStreamDefaultController*> unwrappedController);
 
-extern MOZ_MUST_USE double ReadableStreamControllerGetDesiredSizeUnchecked(
+[[nodiscard]] extern double ReadableStreamControllerGetDesiredSizeUnchecked(
     ReadableStreamController* controller);
 
-extern MOZ_MUST_USE bool ReadableStreamControllerCallPullIfNeeded(
+[[nodiscard]] extern bool ReadableStreamControllerCallPullIfNeeded(
     JSContext* cx, JS::Handle<ReadableStreamController*> unwrappedController);
 
 extern void ReadableStreamControllerClearAlgorithms(
     JS::Handle<ReadableStreamController*> controller);
 
 /**
  * Characterizes the family of algorithms, (startAlgorithm, pullAlgorithm,
  * cancelAlgorithm), associated with a readable stream.
  *
  * See the comment on SetUpReadableStreamDefaultController().
  */
 enum class SourceAlgorithms {
   Script,
   Tee,
 };
 
-extern MOZ_MUST_USE bool SetUpReadableStreamDefaultController(
+[[nodiscard]] extern bool SetUpReadableStreamDefaultController(
     JSContext* cx, JS::Handle<ReadableStream*> stream,
     SourceAlgorithms sourceAlgorithms, JS::Handle<JS::Value> underlyingSource,
     JS::Handle<JS::Value> pullMethod, JS::Handle<JS::Value> cancelMethod,
     double highWaterMark, JS::Handle<JS::Value> size);
 
-extern MOZ_MUST_USE bool
+[[nodiscard]] extern bool
 SetUpReadableStreamDefaultControllerFromUnderlyingSource(
     JSContext* cx, JS::Handle<ReadableStream*> stream,
     JS::Handle<JS::Value> underlyingSource, double highWaterMark,
     JS::Handle<JS::Value> sizeAlgorithm);
 
 }  // namespace js
 
 #endif  // builtin_streams_ReadableStreamDefaultControllerOperations_h
--- a/js/src/builtin/streams/ReadableStreamDefaultReader.cpp
+++ b/js/src/builtin/streams/ReadableStreamDefaultReader.cpp
@@ -110,19 +110,19 @@ bool ReadableStreamDefaultReader::constr
 
   args.rval().setObject(*reader);
   return true;
 }
 
 /**
  * Streams spec, 3.6.4.1 get closed
  */
-static MOZ_MUST_USE bool ReadableStreamDefaultReader_closed(JSContext* cx,
-                                                            unsigned argc,
-                                                            Value* vp) {
+[[nodiscard]] static bool ReadableStreamDefaultReader_closed(JSContext* cx,
+                                                             unsigned argc,
+                                                             Value* vp) {
   CallArgs args = CallArgsFromVp(argc, vp);
 
   // Step 1: If ! IsReadableStreamDefaultReader(this) is false, return a promise
   //         rejected with a TypeError exception.
   Rooted<ReadableStreamDefaultReader*> unwrappedReader(
       cx, UnwrapAndTypeCheckThis<ReadableStreamDefaultReader>(cx, args,
                                                               "get closed"));
   if (!unwrappedReader) {
@@ -137,19 +137,19 @@ static MOZ_MUST_USE bool ReadableStreamD
 
   args.rval().setObject(*closedPromise);
   return true;
 }
 
 /**
  * Streams spec, 3.6.4.2. cancel ( reason )
  */
-static MOZ_MUST_USE bool ReadableStreamDefaultReader_cancel(JSContext* cx,
-                                                            unsigned argc,
-                                                            Value* vp) {
+[[nodiscard]] static bool ReadableStreamDefaultReader_cancel(JSContext* cx,
+                                                             unsigned argc,
+                                                             Value* vp) {
   CallArgs args = CallArgsFromVp(argc, vp);
 
   // Step 1: If ! IsReadableStreamDefaultReader(this) is false, return a promise
   //         rejected with a TypeError exception.
   Rooted<ReadableStreamDefaultReader*> unwrappedReader(
       cx,
       UnwrapAndTypeCheckThis<ReadableStreamDefaultReader>(cx, args, "cancel"));
   if (!unwrappedReader) {
@@ -172,19 +172,19 @@ static MOZ_MUST_USE bool ReadableStreamD
   }
   args.rval().setObject(*cancelPromise);
   return true;
 }
 
 /**
  * Streams spec, 3.6.4.3 read ( )
  */
-static MOZ_MUST_USE bool ReadableStreamDefaultReader_read(JSContext* cx,
-                                                          unsigned argc,
-                                                          Value* vp) {
+[[nodiscard]] static bool ReadableStreamDefaultReader_read(JSContext* cx,
+                                                           unsigned argc,
+                                                           Value* vp) {
   CallArgs args = CallArgsFromVp(argc, vp);
 
   // Step 1: If ! IsReadableStreamDefaultReader(this) is false, return a promise
   //         rejected with a TypeError exception.
   Rooted<ReadableStreamDefaultReader*> unwrappedReader(
       cx,
       UnwrapAndTypeCheckThis<ReadableStreamDefaultReader>(cx, args, "read"));
   if (!unwrappedReader) {
--- a/js/src/builtin/streams/ReadableStreamInternals.h
+++ b/js/src/builtin/streams/ReadableStreamInternals.h
@@ -20,38 +20,38 @@ struct JS_PUBLIC_API JSContext;
 class JS_PUBLIC_API JSObject;
 
 namespace js {
 
 class PlainObject;
 class PromiseObject;
 class ReadableStream;
 
-extern MOZ_MUST_USE PromiseObject* ReadableStreamAddReadOrReadIntoRequest(
+[[nodiscard]] extern PromiseObject* ReadableStreamAddReadOrReadIntoRequest(
     JSContext* cx, JS::Handle<ReadableStream*> unwrappedStream);
 
-extern MOZ_MUST_USE JSObject* ReadableStreamCancel(
+[[nodiscard]] extern JSObject* ReadableStreamCancel(
     JSContext* cx, JS::Handle<ReadableStream*> unwrappedStream,
     JS::Handle<JS::Value> reason);
 
-extern MOZ_MUST_USE bool ReadableStreamCloseInternal(
+[[nodiscard]] extern bool ReadableStreamCloseInternal(
     JSContext* cx, JS::Handle<ReadableStream*> unwrappedStream);
 
-extern MOZ_MUST_USE PlainObject* ReadableStreamCreateReadResult(
+[[nodiscard]] extern PlainObject* ReadableStreamCreateReadResult(
     JSContext* cx, JS::Handle<JS::Value> value, bool done,
     ForAuthorCodeBool forAuthorCode);
 
-extern MOZ_MUST_USE bool ReadableStreamErrorInternal(
+[[nodiscard]] extern bool ReadableStreamErrorInternal(
     JSContext* cx, JS::Handle<ReadableStream*> unwrappedStream,
     JS::Handle<JS::Value> e);
 
-extern MOZ_MUST_USE bool ReadableStreamFulfillReadOrReadIntoRequest(
+[[nodiscard]] extern bool ReadableStreamFulfillReadOrReadIntoRequest(
     JSContext* cx, JS::Handle<ReadableStream*> unwrappedStream,
     JS::Handle<JS::Value> chunk, bool done);
 
 extern uint32_t ReadableStreamGetNumReadRequests(ReadableStream* stream);
 
-extern MOZ_MUST_USE bool ReadableStreamHasDefaultReader(
+[[nodiscard]] extern bool ReadableStreamHasDefaultReader(
     JSContext* cx, JS::Handle<ReadableStream*> unwrappedStream, bool* result);
 
 }  // namespace js
 
 #endif  // builtin_streams_ReadableStreamInternals_h
--- a/js/src/builtin/streams/ReadableStreamOperations.cpp
+++ b/js/src/builtin/streams/ReadableStreamOperations.cpp
@@ -72,17 +72,17 @@ using JS::Value;
  * Streams spec, 3.4.3. CreateReadableStream (
  *                          startAlgorithm, pullAlgorithm, cancelAlgorithm
  *                          [, highWaterMark [, sizeAlgorithm ] ] )
  *
  * The start/pull/cancelAlgorithm arguments are represented instead as four
  * arguments: sourceAlgorithms, underlyingSource, pullMethod, cancelMethod.
  * See the comment on SetUpReadableStreamDefaultController.
  */
-static MOZ_MUST_USE ReadableStream* CreateReadableStream(
+[[nodiscard]] static ReadableStream* CreateReadableStream(
     JSContext* cx, SourceAlgorithms sourceAlgorithms,
     Handle<Value> underlyingSource,
     Handle<Value> pullMethod = UndefinedHandleValue,
     Handle<Value> cancelMethod = UndefinedHandleValue, double highWaterMark = 1,
     Handle<Value> sizeAlgorithm = UndefinedHandleValue,
     Handle<JSObject*> proto = nullptr) {
   cx->check(underlyingSource, sizeAlgorithm, proto);
   MOZ_ASSERT(sizeAlgorithm.isUndefined() || IsCallable(sizeAlgorithm));
--- a/js/src/builtin/streams/ReadableStreamOperations.h
+++ b/js/src/builtin/streams/ReadableStreamOperations.h
@@ -19,29 +19,29 @@ class JS_PUBLIC_API JSObject;
 namespace js {
 
 class PromiseObject;
 class ReadableStream;
 class ReadableStreamDefaultController;
 class TeeState;
 class WritableStream;
 
-extern MOZ_MUST_USE PromiseObject* ReadableStreamTee_Pull(
+[[nodiscard]] extern PromiseObject* ReadableStreamTee_Pull(
     JSContext* cx, JS::Handle<TeeState*> unwrappedTeeState);
 
-extern MOZ_MUST_USE JSObject* ReadableStreamTee_Cancel(
+[[nodiscard]] extern JSObject* ReadableStreamTee_Cancel(
     JSContext* cx, JS::Handle<TeeState*> unwrappedTeeState,
     JS::Handle<ReadableStreamDefaultController*> unwrappedBranch,
     JS::Handle<JS::Value> reason);
 
-extern MOZ_MUST_USE bool ReadableStreamTee(
+[[nodiscard]] extern bool ReadableStreamTee(
     JSContext* cx, JS::Handle<ReadableStream*> unwrappedStream,
     bool cloneForBranch2, JS::MutableHandle<ReadableStream*> branch1Stream,
     JS::MutableHandle<ReadableStream*> branch2Stream);
 
-extern MOZ_MUST_USE PromiseObject* ReadableStreamPipeTo(
+[[nodiscard]] extern PromiseObject* ReadableStreamPipeTo(
     JSContext* cx, JS::Handle<ReadableStream*> unwrappedSource,
     JS::Handle<WritableStream*> unwrappedDest, bool preventClose,
     bool preventAbort, bool preventCancel, JS::Handle<JSObject*> signal);
 
 }  // namespace js
 
 #endif  // builtin_streams_ReadableStreamOperations_h
--- a/js/src/builtin/streams/ReadableStreamReader-inl.h
+++ b/js/src/builtin/streams/ReadableStreamReader-inl.h
@@ -21,39 +21,39 @@
 
 #include "vm/Compartment-inl.h"  // js::UnwrapInternalSlot
 
 namespace js {
 
 /**
  * Returns the stream associated with the given reader.
  */
-inline MOZ_MUST_USE ReadableStream* UnwrapStreamFromReader(
+[[nodiscard]] inline ReadableStream* UnwrapStreamFromReader(
     JSContext* cx, JS::Handle<ReadableStreamReader*> reader) {
   MOZ_ASSERT(reader->hasStream());
   return UnwrapInternalSlot<ReadableStream>(cx, reader,
                                             ReadableStreamReader::Slot_Stream);
 }
 
 /**
  * Returns the reader associated with the given stream.
  *
  * Must only be called on ReadableStreams that already have a reader
  * associated with them.
  *
  * If the reader is a wrapper, it will be unwrapped, so the result might not be
  * an object from the currently active compartment.
  */
-inline MOZ_MUST_USE ReadableStreamReader* UnwrapReaderFromStream(
+[[nodiscard]] inline ReadableStreamReader* UnwrapReaderFromStream(
     JSContext* cx, JS::Handle<ReadableStream*> stream) {
   return UnwrapInternalSlot<ReadableStreamReader>(cx, stream,
                                                   ReadableStream::Slot_Reader);
 }
 
-inline MOZ_MUST_USE ReadableStreamReader* UnwrapReaderFromStreamNoThrow(
+[[nodiscard]] inline ReadableStreamReader* UnwrapReaderFromStreamNoThrow(
     ReadableStream* stream) {
   JSObject* readerObj =
       &stream->getFixedSlot(ReadableStream::Slot_Reader).toObject();
   if (IsProxy(readerObj)) {
     if (JS_IsDeadWrapper(readerObj)) {
       return nullptr;
     }
 
--- a/js/src/builtin/streams/ReadableStreamReader.h
+++ b/js/src/builtin/streams/ReadableStreamReader.h
@@ -112,45 +112,45 @@ class ReadableStreamDefaultReader : publ
  public:
   static bool constructor(JSContext* cx, unsigned argc, JS::Value* vp);
   static const ClassSpec classSpec_;
   static const JSClass class_;
   static const ClassSpec protoClassSpec_;
   static const JSClass protoClass_;
 };
 
-extern MOZ_MUST_USE ReadableStreamDefaultReader*
+[[nodiscard]] extern ReadableStreamDefaultReader*
 CreateReadableStreamDefaultReader(JSContext* cx,
                                   JS::Handle<ReadableStream*> unwrappedStream,
                                   ForAuthorCodeBool forAuthorCode,
                                   JS::Handle<JSObject*> proto = nullptr);
 
-extern MOZ_MUST_USE JSObject* ReadableStreamReaderGenericCancel(
+[[nodiscard]] extern JSObject* ReadableStreamReaderGenericCancel(
     JSContext* cx, JS::Handle<ReadableStreamReader*> unwrappedReader,
     JS::Handle<JS::Value> reason);
 
-extern MOZ_MUST_USE bool ReadableStreamReaderGenericInitialize(
+[[nodiscard]] extern bool ReadableStreamReaderGenericInitialize(
     JSContext* cx, JS::Handle<ReadableStreamReader*> reader,
     JS::Handle<ReadableStream*> unwrappedStream,
     ForAuthorCodeBool forAuthorCode);
 
-extern MOZ_MUST_USE bool ReadableStreamReaderGenericRelease(
+[[nodiscard]] extern bool ReadableStreamReaderGenericRelease(
     JSContext* cx, JS::Handle<ReadableStreamReader*> unwrappedReader);
 
-extern MOZ_MUST_USE PromiseObject* ReadableStreamDefaultReaderRead(
+[[nodiscard]] extern PromiseObject* ReadableStreamDefaultReaderRead(
     JSContext* cx, JS::Handle<ReadableStreamDefaultReader*> unwrappedReader);
 
 }  // namespace js
 
 template <>
 inline bool JSObject::is<js::ReadableStreamReader>() const {
   return is<js::ReadableStreamDefaultReader>();
 }
 
 namespace js {
 
-extern MOZ_MUST_USE JSObject* CreateReadableStreamBYOBReader(
+[[nodiscard]] extern JSObject* CreateReadableStreamBYOBReader(
     JSContext* cx, JS::Handle<ReadableStream*> unwrappedStream,
     ForAuthorCodeBool forAuthorCode, JS::Handle<JSObject*> proto = nullptr);
 
 }  // namespace js
 
 #endif  // builtin_streams_ReadableStreamReader_h
--- a/js/src/builtin/streams/StreamAPI.cpp
+++ b/js/src/builtin/streams/StreamAPI.cpp
@@ -135,17 +135,17 @@ JS_PUBLIC_API bool JS::IsReadableStreamR
   return obj->canUnwrapAs<ReadableStreamDefaultReader>();
 }
 
 JS_PUBLIC_API bool JS::IsReadableStreamDefaultReader(JSObject* obj) {
   return obj->canUnwrapAs<ReadableStreamDefaultReader>();
 }
 
 template <class T>
-static MOZ_MUST_USE T* APIUnwrapAndDowncast(JSContext* cx, JSObject* obj) {
+[[nodiscard]] static T* APIUnwrapAndDowncast(JSContext* cx, JSObject* obj) {
   cx->check(obj);
   return UnwrapAndDowncastObject<T>(cx, obj);
 }
 
 JS_PUBLIC_API bool JS::ReadableStreamIsReadable(JSContext* cx,
                                                 Handle<JSObject*> streamObj,
                                                 bool* result) {
   ReadableStream* unwrappedStream =
--- a/js/src/builtin/streams/WritableStream-inl.h
+++ b/js/src/builtin/streams/WritableStream-inl.h
@@ -30,17 +30,17 @@ namespace js {
  * Returns the writer associated with the given stream.
  *
  * Must only be called on WritableStreams that already have a writer
  * associated with them.
  *
  * If the writer is a wrapper, it will be unwrapped, so the result might not be
  * an object from the currently active compartment.
  */
-inline MOZ_MUST_USE WritableStreamDefaultWriter* UnwrapWriterFromStream(
+[[nodiscard]] inline WritableStreamDefaultWriter* UnwrapWriterFromStream(
     JSContext* cx, JS::Handle<WritableStream*> unwrappedStream) {
   MOZ_ASSERT(unwrappedStream->hasWriter());
   return UnwrapInternalSlot<WritableStreamDefaultWriter>(
       cx, unwrappedStream, WritableStream::Slot_Writer);
 }
 
 }  // namespace js
 
--- a/js/src/builtin/streams/WritableStream.h
+++ b/js/src/builtin/streams/WritableStream.h
@@ -403,17 +403,17 @@ class WritableStream : public NativeObje
     MOZ_ASSERT(hasPendingAbortRequest());
 
     // [[pendingAbortRequest]] is { [[promise]], [[reason]] } in the spec but
     // separate slots in our implementation, so both must be cleared.
     setFixedSlot(Slot_PendingAbortRequestPromise, JS::UndefinedValue());
     setFixedSlot(Slot_PendingAbortRequestReason, JS::UndefinedValue());
   }
 
-  static MOZ_MUST_USE WritableStream* create(
+  [[nodiscard]] static WritableStream* create(
       JSContext* cx, void* nsISupportsObject_alreadyAddreffed = nullptr,
       JS::Handle<JSObject*> proto = nullptr);
 
   static bool constructor(JSContext* cx, unsigned argc, JS::Value* vp);
 
   static const ClassSpec classSpec_;
   static const JSClass class_;
   static const ClassSpec protoClassSpec_;
--- a/js/src/builtin/streams/WritableStreamDefaultControllerOperations.cpp
+++ b/js/src/builtin/streams/WritableStreamDefaultControllerOperations.cpp
@@ -124,17 +124,17 @@ bool js::WritableStreamControllerErrorSt
     JSContext* cx,
     Handle<WritableStreamDefaultController*> unwrappedController) {
   // Step 1: Perform ! ResetQueue(this).
   return ResetQueue(cx, unwrappedController);
 }
 
 /*** 4.8. Writable stream default controller abstract operations ************/
 
-static MOZ_MUST_USE bool WritableStreamDefaultControllerAdvanceQueueIfNeeded(
+[[nodiscard]] static bool WritableStreamDefaultControllerAdvanceQueueIfNeeded(
     JSContext* cx,
     Handle<WritableStreamDefaultController*> unwrappedController);
 
 /**
  * Streams spec, 4.8.2. SetUpWritableStreamDefaultController, step 16:
  *      Upon fulfillment of startPromise, [...]
  */
 bool js::WritableStreamControllerStartHandler(JSContext* cx, unsigned argc,
@@ -590,17 +590,17 @@ bool js::WritableStreamDefaultController
   }
 
   // Step 6: Perform
   //         ! WritableStreamDefaultControllerAdvanceQueueIfNeeded(controller).
   return WritableStreamDefaultControllerAdvanceQueueIfNeeded(
       cx, unwrappedController);
 }
 
-static MOZ_MUST_USE bool WritableStreamDefaultControllerProcessIfNeeded(
+[[nodiscard]] static bool WritableStreamDefaultControllerProcessIfNeeded(
     JSContext* cx,
     Handle<WritableStreamDefaultController*> unwrappedController);
 
 /**
  * Streams spec, 4.8.9.
  *      WritableStreamDefaultControllerAdvanceQueueIfNeeded ( controller )
  */
 [[nodiscard]] bool WritableStreamDefaultControllerAdvanceQueueIfNeeded(
@@ -658,17 +658,17 @@ bool js::WritableStreamDefaultController
     }
   }
 
   return true;
 }
 
 // 4.8.11 step 5: Let sinkClosePromise be the result of performing
 //                controller.[[closeAlgorithm]].
-static MOZ_MUST_USE JSObject* PerformCloseAlgorithm(
+[[nodiscard]] static JSObject* PerformCloseAlgorithm(
     JSContext* cx,
     Handle<WritableStreamDefaultController*> unwrappedController) {
   // 4.8.3 step 5: Let closeAlgorithm be
   //               ? CreateAlgorithmFromUnderlyingMethod(underlyingSink,
   //                                                     "close", 0, « »).
 
   // Step 1: Assert: underlyingObject is not undefined.
   // Step 2: Assert: ! IsPropertyKey(methodName) is true (implicit).
@@ -705,17 +705,17 @@ static MOZ_MUST_USE JSObject* PerformClo
     return nullptr;
   }
 
   return PromiseCall(cx, closeMethod, underlyingSink);
 }
 
 // 4.8.12 step 3: Let sinkWritePromise be the result of performing
 //                controller.[[writeAlgorithm]], passing in chunk.
-static MOZ_MUST_USE JSObject* PerformWriteAlgorithm(
+[[nodiscard]] static JSObject* PerformWriteAlgorithm(
     JSContext* cx, Handle<WritableStreamDefaultController*> unwrappedController,
     Handle<Value> chunk) {
   cx->check(chunk);
 
   // 4.8.3 step 4: Let writeAlgorithm be
   //               ? CreateAlgorithmFromUnderlyingMethod(underlyingSink,
   //                                                     "write", 1,
   //                                                     « controller »).
@@ -764,18 +764,18 @@ static MOZ_MUST_USE JSObject* PerformWri
 
   return PromiseCall(cx, writeMethod, underlyingSink, chunk, controller);
 }
 
 /**
  * Streams spec, 4.8.11 step 7:
  * Upon fulfillment of sinkClosePromise,
  */
-static MOZ_MUST_USE bool WritableStreamCloseHandler(JSContext* cx,
-                                                    unsigned argc, Value* vp) {
+[[nodiscard]] static bool WritableStreamCloseHandler(JSContext* cx,
+                                                     unsigned argc, Value* vp) {
   CallArgs args = CallArgsFromVp(argc, vp);
 
   Rooted<WritableStream*> unwrappedStream(
       cx, TargetFromHandler<WritableStream>(args));
 
   // Step 7.a: Perform ! WritableStreamFinishInFlightClose(stream).
   if (!WritableStreamFinishInFlightClose(cx, unwrappedStream)) {
     return false;
@@ -784,19 +784,19 @@ static MOZ_MUST_USE bool WritableStreamC
   args.rval().setUndefined();
   return true;
 }
 
 /**
  * Streams spec, 4.8.11 step 8:
  * Upon rejection of sinkClosePromise with reason reason,
  */
-static MOZ_MUST_USE bool WritableStreamCloseFailedHandler(JSContext* cx,
-                                                          unsigned argc,
-                                                          Value* vp) {
+[[nodiscard]] static bool WritableStreamCloseFailedHandler(JSContext* cx,
+                                                           unsigned argc,
+                                                           Value* vp) {
   CallArgs args = CallArgsFromVp(argc, vp);
 
   Rooted<WritableStream*> unwrappedStream(
       cx, TargetFromHandler<WritableStream>(args));
 
   // Step 8.a: Perform
   //           ! WritableStreamFinishInFlightCloseWithError(stream, reason).
   if (!WritableStreamFinishInFlightCloseWithError(cx, unwrappedStream,
@@ -807,18 +807,18 @@ static MOZ_MUST_USE bool WritableStreamC
   args.rval().setUndefined();
   return true;
 }
 
 /**
  * Streams spec, 4.8.12 step 4:
  * Upon fulfillment of sinkWritePromise,
  */
-static MOZ_MUST_USE bool WritableStreamWriteHandler(JSContext* cx,
-                                                    unsigned argc, Value* vp) {
+[[nodiscard]] static bool WritableStreamWriteHandler(JSContext* cx,
+                                                     unsigned argc, Value* vp) {
   CallArgs args = CallArgsFromVp(argc, vp);
 
   Rooted<WritableStream*> unwrappedStream(
       cx, TargetFromHandler<WritableStream>(args));
 
   // Step 4.a: Perform ! WritableStreamFinishInFlightWrite(stream).
   if (!WritableStreamFinishInFlightWrite(cx, unwrappedStream)) {
     return false;
@@ -861,19 +861,19 @@ static MOZ_MUST_USE bool WritableStreamW
   args.rval().setUndefined();
   return true;
 }
 
 /**
  * Streams spec, 4.8.12 step 5:
  * Upon rejection of sinkWritePromise with reason,
  */
-static MOZ_MUST_USE bool WritableStreamWriteFailedHandler(JSContext* cx,
-                                                          unsigned argc,
-                                                          Value* vp) {
+[[nodiscard]] static bool WritableStreamWriteFailedHandler(JSContext* cx,
+                                                           unsigned argc,
+                                                           Value* vp) {
   CallArgs args = CallArgsFromVp(argc, vp);
 
   Rooted<WritableStream*> unwrappedStream(
       cx, TargetFromHandler<WritableStream>(args));
 
   // Step 5.a: If stream.[[state]] is "writable", perform
   //           ! WritableStreamDefaultControllerClearAlgorithms(controller).
   if (unwrappedStream->writable()) {
--- a/js/src/builtin/streams/WritableStreamDefaultControllerOperations.h
+++ b/js/src/builtin/streams/WritableStreamDefaultControllerOperations.h
@@ -22,87 +22,88 @@ namespace js {
 class WritableStream;
 class WritableStreamDefaultController;
 
 extern JSObject* WritableStreamControllerAbortSteps(
     JSContext* cx,
     JS::Handle<WritableStreamDefaultController*> unwrappedController,
     JS::Handle<JS::Value> reason);
 
-extern MOZ_MUST_USE bool WritableStreamControllerErrorSteps(
+[[nodiscard]] extern bool WritableStreamControllerErrorSteps(
     JSContext* cx,
     JS::Handle<WritableStreamDefaultController*> unwrappedController);
 
-extern MOZ_MUST_USE bool WritableStreamControllerStartHandler(JSContext* cx,
-                                                              unsigned argc,
-                                                              JS::Value* vp);
+[[nodiscard]] extern bool WritableStreamControllerStartHandler(JSContext* cx,
+                                                               unsigned argc,
+                                                               JS::Value* vp);
 
-extern MOZ_MUST_USE bool WritableStreamControllerStartFailedHandler(
+[[nodiscard]] extern bool WritableStreamControllerStartFailedHandler(
     JSContext* cx, unsigned argc, JS::Value* vp);
 
 /**
  * Characterizes the family of algorithms, (startAlgorithm, writeAlgorithm,
  * closeAlgorithm, abortAlgorithm), associated with a writable stream.
  *
  * See the comment on SetUpWritableStreamDefaultController().
  */
 enum class SinkAlgorithms {
   Script,
   Transform,
 };
 
-extern MOZ_MUST_USE bool SetUpWritableStreamDefaultController(
+[[nodiscard]] extern bool SetUpWritableStreamDefaultController(
     JSContext* cx, JS::Handle<WritableStream*> stream,
     SinkAlgorithms algorithms, JS::Handle<JS::Value> underlyingSink,
     JS::Handle<JS::Value> writeMethod, JS::Handle<JS::Value> closeMethod,
     JS::Handle<JS::Value> abortMethod, double highWaterMark,
     JS::Handle<JS::Value> size);
 
-extern MOZ_MUST_USE bool SetUpWritableStreamDefaultControllerFromUnderlyingSink(
+[[nodiscard]] extern bool
+SetUpWritableStreamDefaultControllerFromUnderlyingSink(
     JSContext* cx, JS::Handle<WritableStream*> stream,
     JS::Handle<JS::Value> underlyingSink, double highWaterMark,
     JS::Handle<JS::Value> sizeAlgorithm);
 
 extern void WritableStreamDefaultControllerClearAlgorithms(
     WritableStreamDefaultController* unwrappedController);
 
-extern MOZ_MUST_USE bool WritableStreamDefaultControllerClose(
+[[nodiscard]] extern bool WritableStreamDefaultControllerClose(
     JSContext* cx,
     JS::Handle<WritableStreamDefaultController*> unwrappedController);
 
-extern MOZ_MUST_USE bool WritableStreamDefaultControllerGetChunkSize(
+[[nodiscard]] extern bool WritableStreamDefaultControllerGetChunkSize(
     JSContext* cx,
     JS::Handle<WritableStreamDefaultController*> unwrappedController,
     JS::Handle<JS::Value> chunk, JS::MutableHandle<JS::Value> returnValue);
 
 extern double WritableStreamDefaultControllerGetDesiredSize(
     const WritableStreamDefaultController* controller);
 
-extern MOZ_MUST_USE bool WritableStreamDefaultControllerWrite(
+[[nodiscard]] extern bool WritableStreamDefaultControllerWrite(
     JSContext* cx,
     JS::Handle<WritableStreamDefaultController*> unwrappedController,
     JS::Handle<JS::Value> chunk, JS::Handle<JS::Value> chunkSize);
 
-extern MOZ_MUST_USE bool WritableStreamDefaultControllerErrorIfNeeded(
+[[nodiscard]] extern bool WritableStreamDefaultControllerErrorIfNeeded(
     JSContext* cx,
     JS::Handle<WritableStreamDefaultController*> unwrappedController,
     JS::Handle<JS::Value> error);
 
-extern MOZ_MUST_USE bool WritableStreamDefaultControllerProcessClose(
+[[nodiscard]] extern bool WritableStreamDefaultControllerProcessClose(
     JSContext* cx,
     JS::Handle<WritableStreamDefaultController*> unwrappedController);
 
-extern MOZ_MUST_USE bool WritableStreamDefaultControllerProcessWrite(
+[[nodiscard]] extern bool WritableStreamDefaultControllerProcessWrite(
     JSContext* cx,
     JS::Handle<WritableStreamDefaultController*> unwrappedController,
     JS::Handle<JS::Value> chunk);
 
 extern bool WritableStreamDefaultControllerGetBackpressure(
     const WritableStreamDefaultController* unwrappedController);
 
-extern MOZ_MUST_USE bool WritableStreamDefaultControllerError(
+[[nodiscard]] extern bool WritableStreamDefaultControllerError(
     JSContext* cx,
     JS::Handle<WritableStreamDefaultController*> unwrappedController,
     JS::Handle<JS::Value> error);
 
 }  // namespace js
 
 #endif  // builtin_streams_WritableStreamDefaultControllerOperations_h
--- a/js/src/builtin/streams/WritableStreamDefaultWriter-inl.h
+++ b/js/src/builtin/streams/WritableStreamDefaultWriter-inl.h
@@ -23,17 +23,17 @@
 
 struct JS_PUBLIC_API JSContext;
 
 namespace js {
 
 /**
  * Returns the stream associated with the given reader.
  */
-inline MOZ_MUST_USE WritableStream* UnwrapStreamFromWriter(
+[[nodiscard]] inline WritableStream* UnwrapStreamFromWriter(
     JSContext* cx, JS::Handle<WritableStreamDefaultWriter*> unwrappedWriter) {
   MOZ_ASSERT(unwrappedWriter->hasStream());
   return UnwrapInternalSlot<WritableStream>(
       cx, unwrappedWriter, WritableStreamDefaultWriter::Slot_Stream);
 }
 
 }  // namespace js
 
--- a/js/src/builtin/streams/WritableStreamDefaultWriter.cpp
+++ b/js/src/builtin/streams/WritableStreamDefaultWriter.cpp
@@ -253,19 +253,19 @@ bool WritableStreamDefaultWriter::constr
 
   args.rval().setObject(*writer);
   return true;
 }
 
 /**
  * Streams spec, 4.5.4.1. get closed
  */
-static MOZ_MUST_USE bool WritableStreamDefaultWriter_closed(JSContext* cx,
-                                                            unsigned argc,
-                                                            Value* vp) {
+[[nodiscard]] static bool WritableStreamDefaultWriter_closed(JSContext* cx,
+                                                             unsigned argc,
+                                                             Value* vp) {
   CallArgs args = CallArgsFromVp(argc, vp);
 
   // Step 1: If ! IsWritableStreamDefaultWriter(this) is false, return a promise
   //         rejected with a TypeError exception.
   Rooted<WritableStreamDefaultWriter*> unwrappedWriter(
       cx, UnwrapAndTypeCheckThis<WritableStreamDefaultWriter>(cx, args,
                                                               "get closed"));
   if (!unwrappedWriter) {
@@ -280,19 +280,19 @@ static MOZ_MUST_USE bool WritableStreamD
 
   args.rval().setObject(*closedPromise);
   return true;
 }
 
 /**
  * Streams spec, 4.5.4.2. get desiredSize
  */
-static MOZ_MUST_USE bool WritableStreamDefaultWriter_desiredSize(JSContext* cx,
-                                                                 unsigned argc,
-                                                                 Value* vp) {
+[[nodiscard]] static bool WritableStreamDefaultWriter_desiredSize(JSContext* cx,
+                                                                  unsigned argc,
+                                                                  Value* vp) {
   CallArgs args = CallArgsFromVp(argc, vp);
 
   // Step 1: If ! IsWritableStreamDefaultWriter(this) is false, throw a
   //         TypeError exception.
   Rooted<WritableStreamDefaultWriter*> unwrappedWriter(
       cx, UnwrapAndTypeCheckThis<WritableStreamDefaultWriter>(
               cx, args, "get desiredSize"));
   if (!unwrappedWriter) {
@@ -317,19 +317,19 @@ static MOZ_MUST_USE bool WritableStreamD
   MOZ_ASSERT(args.rval().isNull() || args.rval().isNumber(),
              "expected a type that'll never require wrapping");
   return true;
 }
 
 /**
  * Streams spec, 4.5.4.3. get ready
  */
-static MOZ_MUST_USE bool WritableStreamDefaultWriter_ready(JSContext* cx,
-                                                           unsigned argc,
-                                                           Value* vp) {
+[[nodiscard]] static bool WritableStreamDefaultWriter_ready(JSContext* cx,
+                                                            unsigned argc,
+                                                            Value* vp) {
   CallArgs args = CallArgsFromVp(argc, vp);
 
   // Step 1: If ! IsWritableStreamDefaultWriter(this) is false, return a promise
   //         rejected with a TypeError exception.
   Rooted<WritableStreamDefaultWriter*> unwrappedWriter(
       cx, UnwrapAndTypeCheckThis<WritableStreamDefaultWriter>(cx, args,
                                                               "get ready"));
   if (!unwrappedWriter) {
@@ -344,19 +344,19 @@ static MOZ_MUST_USE bool WritableStreamD
 
   args.rval().setObject(*readyPromise);
   return true;
 }
 
 /**
  * Streams spec, 4.5.4.4. abort(reason)
  */
-static MOZ_MUST_USE bool WritableStreamDefaultWriter_abort(JSContext* cx,
-                                                           unsigned argc,
-                                                           Value* vp) {
+[[nodiscard]] static bool WritableStreamDefaultWriter_abort(JSContext* cx,
+                                                            unsigned argc,
+                                                            Value* vp) {
   CallArgs args = CallArgsFromVp(argc, vp);
 
   // Step 1: If ! IsWritableStreamDefaultWriter(this) is false, return a promise
   //         rejected with a TypeError exception.
   Rooted<WritableStreamDefaultWriter*> unwrappedWriter(
       cx,
       UnwrapAndTypeCheckThis<WritableStreamDefaultWriter>(cx, args, "abort"));
   if (!unwrappedWriter) {
@@ -381,19 +381,19 @@ static MOZ_MUST_USE bool WritableStreamD
 
   args.rval().setObject(*promise);
   return true;
 }
 
 /**
  * Streams spec, 4.5.4.5. close()
  */
-static MOZ_MUST_USE bool WritableStreamDefaultWriter_close(JSContext* cx,
-                                                           unsigned argc,
-                                                           Value* vp) {
+[[nodiscard]] static bool WritableStreamDefaultWriter_close(JSContext* cx,
+                                                            unsigned argc,
+                                                            Value* vp) {
   CallArgs args = CallArgsFromVp(argc, vp);
 
   // Step 1: If ! IsWritableStreamDefaultWriter(this) is false, return a promise
   //         rejected with a TypeError exception.
   Rooted<WritableStreamDefaultWriter*> unwrappedWriter(
       cx,
       UnwrapAndTypeCheckThis<WritableStreamDefaultWriter>(cx, args, "close"));
   if (!unwrappedWriter) {
@@ -431,19 +431,19 @@ static MOZ_MUST_USE bool WritableStreamD
 
   args.rval().setObject(*promise);
   return true;
 }
 
 /**
  * Streams spec, 4.5.4.6. releaseLock()
  */
-static MOZ_MUST_USE bool WritableStreamDefaultWriter_releaseLock(JSContext* cx,
-                                                                 unsigned argc,
-                                                                 Value* vp) {
+[[nodiscard]] static bool WritableStreamDefaultWriter_releaseLock(JSContext* cx,
+                                                                  unsigned argc,
+                                                                  Value* vp) {
   CallArgs args = CallArgsFromVp(argc, vp);
 
   // Step 1: If ! IsWritableStreamDefaultWriter(this) is false, return a promise
   //         rejected with a TypeError exception.
   Rooted<WritableStreamDefaultWriter*> unwrappedWriter(
       cx,
       UnwrapAndTypeCheckThis<WritableStreamDefaultWriter>(cx, args, "close"));
   if (!unwrappedWriter) {
@@ -476,19 +476,19 @@ static MOZ_MUST_USE bool WritableStreamD
 
   args.rval().setUndefined();
   return true;
 }
 
 /**
  * Streams spec, 4.5.4.7. write(chunk)
  */
-static MOZ_MUST_USE bool WritableStreamDefaultWriter_write(JSContext* cx,
-                                                           unsigned argc,
-                                                           Value* vp) {
+[[nodiscard]] static bool WritableStreamDefaultWriter_write(JSContext* cx,
+                                                            unsigned argc,
+                                                            Value* vp) {
   CallArgs args = CallArgsFromVp(argc, vp);
 
   // Step 1: If ! IsWritableStreamDefaultWriter(this) is false, return a promise
   //         rejected with a TypeError exception.
   Rooted<WritableStreamDefaultWriter*> unwrappedWriter(
       cx,
       UnwrapAndTypeCheckThis<WritableStreamDefaultWriter>(cx, args, "write"));
   if (!unwrappedWriter) {
--- a/js/src/builtin/streams/WritableStreamDefaultWriter.h
+++ b/js/src/builtin/streams/WritableStreamDefaultWriter.h
@@ -98,16 +98,16 @@ class WritableStreamDefaultWriter : publ
 
   static bool constructor(JSContext* cx, unsigned argc, JS::Value* vp);
   static const ClassSpec classSpec_;
   static const JSClass class_;
   static const ClassSpec protoClassSpec_;
   static const JSClass protoClass_;
 };
 
-extern MOZ_MUST_USE WritableStreamDefaultWriter*
+[[nodiscard]] extern WritableStreamDefaultWriter*
 CreateWritableStreamDefaultWriter(JSContext* cx,
                                   JS::Handle<WritableStream*> unwrappedStream,
                                   JS::Handle<JSObject*> proto = nullptr);
 
 }  // namespace js
 
 #endif  // builtin_streams_WritableStreamDefaultWriter_h
--- a/js/src/builtin/streams/WritableStreamOperations.h
+++ b/js/src/builtin/streams/WritableStreamOperations.h
@@ -24,55 +24,55 @@ class WritableStream;
 
 extern JSObject* WritableStreamAbort(
     JSContext* cx, JS::Handle<WritableStream*> unwrappedStream,
     JS::Handle<JS::Value> reason);
 
 extern JSObject* WritableStreamClose(
     JSContext* cx, JS::Handle<WritableStream*> unwrappedStream);
 
-extern MOZ_MUST_USE PromiseObject* WritableStreamAddWriteRequest(
+[[nodiscard]] extern PromiseObject* WritableStreamAddWriteRequest(
     JSContext* cx, JS::Handle<WritableStream*> unwrappedStream);
 
-extern MOZ_MUST_USE bool WritableStreamDealWithRejection(
+[[nodiscard]] extern bool WritableStreamDealWithRejection(
     JSContext* cx, JS::Handle<WritableStream*> unwrappedStream,
     JS::Handle<JS::Value> error);
 
-extern MOZ_MUST_USE bool WritableStreamStartErroring(
+[[nodiscard]] extern bool WritableStreamStartErroring(
     JSContext* cx, JS::Handle<WritableStream*> unwrappedStream,
     JS::Handle<JS::Value> reason);
 
-extern MOZ_MUST_USE bool WritableStreamFinishErroring(
+[[nodiscard]] extern bool WritableStreamFinishErroring(
     JSContext* cx, JS::Handle<WritableStream*> unwrappedStream);
 
-extern MOZ_MUST_USE bool WritableStreamFinishInFlightWrite(
+[[nodiscard]] extern bool WritableStreamFinishInFlightWrite(
     JSContext* cx, JS::Handle<WritableStream*> unwrappedStream);
 
-extern MOZ_MUST_USE bool WritableStreamFinishInFlightWriteWithError(
+[[nodiscard]] extern bool WritableStreamFinishInFlightWriteWithError(
     JSContext* cx, JS::Handle<WritableStream*> unwrappedStream,
     JS::Handle<JS::Value> error);
 
-extern MOZ_MUST_USE bool WritableStreamFinishInFlightClose(
+[[nodiscard]] extern bool WritableStreamFinishInFlightClose(
     JSContext* cx, JS::Handle<WritableStream*> unwrappedStream);
 
-extern MOZ_MUST_USE bool WritableStreamFinishInFlightCloseWithError(
+[[nodiscard]] extern bool WritableStreamFinishInFlightCloseWithError(
     JSContext* cx, JS::Handle<WritableStream*> unwrappedStream,
     JS::Handle<JS::Value> error);
 
 extern bool WritableStreamCloseQueuedOrInFlight(
     const WritableStream* unwrappedStream);
 
 extern void WritableStreamMarkCloseRequestInFlight(
     WritableStream* unwrappedStream);
 
 extern void WritableStreamMarkFirstWriteRequestInFlight(
     WritableStream* unwrappedStream);
 
-extern MOZ_MUST_USE bool WritableStreamRejectCloseAndClosedPromiseIfNeeded(
+[[nodiscard]] extern bool WritableStreamRejectCloseAndClosedPromiseIfNeeded(
     JSContext* cx, JS::Handle<WritableStream*> unwrappedStream);
 
-extern MOZ_MUST_USE bool WritableStreamUpdateBackpressure(
+[[nodiscard]] extern bool WritableStreamUpdateBackpressure(
     JSContext* cx, JS::Handle<WritableStream*> unwrappedStream,
     bool backpressure);
 
 }  // namespace js
 
 #endif  // builtin_streams_WritableStreamOperations_h
--- a/js/src/builtin/streams/WritableStreamWriterOperations.h
+++ b/js/src/builtin/streams/WritableStreamWriterOperations.h
@@ -27,29 +27,30 @@ extern JSObject* WritableStreamDefaultWr
     JS::Handle<JS::Value> reason);
 
 extern PromiseObject* WritableStreamDefaultWriterClose(
     JSContext* cx, JS::Handle<WritableStreamDefaultWriter*> unwrappedWriter);
 
 extern PromiseObject* WritableStreamDefaultWriterCloseWithErrorPropagation(
     JSContext* cx, JS::Handle<WritableStreamDefaultWriter*> unwrappedWriter);
 
-extern MOZ_MUST_USE bool WritableStreamDefaultWriterEnsureClosedPromiseRejected(
+[[nodiscard]] extern bool
+WritableStreamDefaultWriterEnsureClosedPromiseRejected(
     JSContext* cx, JS::Handle<WritableStreamDefaultWriter*> unwrappedWriter,
     JS::Handle<JS::Value> error);
 
-extern MOZ_MUST_USE bool WritableStreamDefaultWriterEnsureReadyPromiseRejected(
+[[nodiscard]] extern bool WritableStreamDefaultWriterEnsureReadyPromiseRejected(
     JSContext* cx, JS::Handle<WritableStreamDefaultWriter*> unwrappedWriter,
     JS::Handle<JS::Value> error);
 
-extern MOZ_MUST_USE bool WritableStreamDefaultWriterGetDesiredSize(
+[[nodiscard]] extern bool WritableStreamDefaultWriterGetDesiredSize(
     JSContext* cx, JS::Handle<WritableStreamDefaultWriter*> unwrappedWriter,
     JS::MutableHandle<JS::Value> size);
 
-extern MOZ_MUST_USE bool WritableStreamDefaultWriterRelease(
+[[nodiscard]] extern bool WritableStreamDefaultWriterRelease(
     JSContext* cx, JS::Handle<WritableStreamDefaultWriter*> unwrappedWriter);
 
 extern PromiseObject* WritableStreamDefaultWriterWrite(
     JSContext* cx, JS::Handle<WritableStreamDefaultWriter*> unwrappedWriter,
     JS::Handle<JS::Value> chunk);
 
 }  // namespace js
 
--- a/js/src/ctypes/CTypes.cpp
+++ b/js/src/ctypes/CTypes.cpp
@@ -4106,19 +4106,19 @@ static void BuildTypeSource(JSContext* c
 // the same CType and containing the same binary value. This assumes that any
 // StructType 't' is bound to an in-scope variable of name 't.name'. (This means
 // the type comparison function CType::TypesEqual will return true when
 // comparing the types, since struct equality is determined by strict JSObject
 // pointer equality.) Further, if 'isImplicit' is true, ensure that the
 // resulting string can ImplicitConvert successfully if passed to another data
 // constructor. (This is important when called recursively, since fields of
 // structs and arrays are converted with ImplicitConvert.)
-static MOZ_MUST_USE bool BuildDataSource(JSContext* cx, HandleObject typeObj,
-                                         void* data, bool isImplicit,
-                                         AutoString& result) {
+[[nodiscard]] static bool BuildDataSource(JSContext* cx, HandleObject typeObj,
+                                          void* data, bool isImplicit,
+                                          AutoString& result) {
   TypeCode type = CType::GetTypeCode(typeObj);
   switch (type) {
     case TYPE_bool:
       if (*static_cast<bool*>(data)) {
         AppendString(cx, result, "true");
       } else {
         AppendString(cx, result, "false");
       }
--- a/js/src/debugger/DebugAPI.h
+++ b/js/src/debugger/DebugAPI.h
@@ -108,17 +108,17 @@ class DebugAPI {
 
   // The garbage collector calls this after everything has been marked, but
   // before anything has been finalized. We use this to clear Debugger /
   // debuggee edges at a point where the parties concerned are all still
   // initialized.
   static void sweepAll(JSFreeOp* fop);
 
   // Add sweep group edges due to the presence of any debuggers.
-  static MOZ_MUST_USE bool findSweepGroupEdges(JSRuntime* rt);
+  [[nodiscard]] static bool findSweepGroupEdges(JSRuntime* rt);
 
   // Destroy the debugging information associated with a script.
   static void destroyDebugScript(JSFreeOp* fop, JSScript* script);
 
   // Validate the debugging information in a script after a moving GC>
 #ifdef JSGC_HASH_TABLE_CHECKS
   static void checkDebugScriptAfterMovingGC(DebugScript* ds);
 #endif
@@ -134,35 +134,35 @@ class DebugAPI {
   static inline bool stepModeEnabled(JSScript* script);
   static inline bool hasBreakpointsAt(JSScript* script, jsbytecode* pc);
   static inline bool hasAnyBreakpointsOrStepMode(JSScript* script);
 
   /*** Methods for interacting with the JITs. *********************************/
 
   // Update Debugger frames when an interpreter frame is replaced with a
   // baseline frame.
-  static MOZ_MUST_USE bool handleBaselineOsr(JSContext* cx,
-                                             InterpreterFrame* from,
-                                             jit::BaselineFrame* to);
+  [[nodiscard]] static bool handleBaselineOsr(JSContext* cx,
+                                              InterpreterFrame* from,
+                                              jit::BaselineFrame* to);
 
   // Update Debugger frames when an Ion frame bails out and is replaced with a
   // baseline frame.
-  static MOZ_MUST_USE bool handleIonBailout(JSContext* cx,
-                                            jit::RematerializedFrame* from,
-                                            jit::BaselineFrame* to);
+  [[nodiscard]] static bool handleIonBailout(JSContext* cx,
+                                             jit::RematerializedFrame* from,
+                                             jit::BaselineFrame* to);
 
   // Detach any Debugger frames from an Ion frame after an error occurred while
   // it bailed out.
   static void handleUnrecoverableIonBailoutError(
       JSContext* cx, jit::RematerializedFrame* frame);
 
   // When doing on-stack-replacement of a debuggee interpreter frame with a
   // baseline frame, ensure that the resulting frame can be observed by the
   // debugger.
-  static MOZ_MUST_USE bool ensureExecutionObservabilityOfOsrFrame(
+  [[nodiscard]] static bool ensureExecutionObservabilityOfOsrFrame(
       JSContext* cx, AbstractFramePtr osrSourceFrame);
 
   // Describes a set of scripts or frames whose execution observability can
   // change due to debugger activity.
   class ExecutionObservableSet {
    public:
     using ZoneRange = HashSet<Zone*>::Range;
 
@@ -189,83 +189,83 @@ class DebugAPI {
   static inline void onNewWasmInstance(
       JSContext* cx, Handle<WasmInstanceObject*> wasmInstance);
 
   /*
    * Announce to the debugger that the context has entered a new JavaScript
    * frame, |frame|. Call whatever hooks have been registered to observe new
    * frames.
    */
-  static inline MOZ_MUST_USE bool onEnterFrame(JSContext* cx,
-                                               AbstractFramePtr frame);
+  [[nodiscard]] static inline bool onEnterFrame(JSContext* cx,
+                                                AbstractFramePtr frame);
 
   /*
    * Like onEnterFrame, but for resuming execution of a generator or async
    * function. `frame` is a new baseline or interpreter frame, but abstractly
    * it can be identified with a particular generator frame that was
    * suspended earlier.
    *
    * There is no separate user-visible Debugger.onResumeFrame hook; this
    * fires .onEnterFrame (again, since we're re-entering the frame).
    *
    * Unfortunately, the interpreter and the baseline JIT arrange for this to
    * be called in different ways. The interpreter calls it from JSOp::Resume,
    * immediately after pushing the resumed frame; the JIT calls it from
    * JSOp::AfterYield, just after the generator resumes. The difference
    * should not be user-visible.
    */
-  static inline MOZ_MUST_USE bool onResumeFrame(JSContext* cx,
-                                                AbstractFramePtr frame);
+  [[nodiscard]] static inline bool onResumeFrame(JSContext* cx,
+                                                 AbstractFramePtr frame);
 
   static inline NativeResumeMode onNativeCall(JSContext* cx,
                                               const CallArgs& args,
                                               CallReason reason);
 
   /*
    * Announce to the debugger a |debugger;| statement on has been
    * encountered on the youngest JS frame on |cx|. Call whatever hooks have
    * been registered to observe this.
    *
    * Note that this method is called for all |debugger;| statements,
    * regardless of the frame's debuggee-ness.
    */
-  static inline MOZ_MUST_USE bool onDebuggerStatement(JSContext* cx,
-                                                      AbstractFramePtr frame);
+  [[nodiscard]] static inline bool onDebuggerStatement(JSContext* cx,
+                                                       AbstractFramePtr frame);
 
   /*
    * Announce to the debugger that an exception has been thrown and propagated
    * to |frame|. Call whatever hooks have been registered to observe this.
    */
-  static inline MOZ_MUST_USE bool onExceptionUnwind(JSContext* cx,
-                                                    AbstractFramePtr frame);
+  [[nodiscard]] static inline bool onExceptionUnwind(JSContext* cx,
+                                                     AbstractFramePtr frame);
 
   /*
    * Announce to the debugger that the thread has exited a JavaScript frame,
    * |frame|. If |ok| is true, the frame is returning normally; if |ok| is
    * false, the frame is throwing an exception or terminating.
    *
    * Change cx's current exception and |frame|'s return value to reflect the
    * changes in behavior the hooks request, if any. Return the new error/success
    * value.
    *
    * This function may be called twice for the same outgoing frame; only the
    * first call has any effect. (Permitting double calls simplifies some
    * cases where an onPop handler's resumption value changes a return to a
    * throw, or vice versa: we can redirect to a complete copy of the
    * alternative path, containing its own call to onLeaveFrame.)
    */
-  static inline MOZ_MUST_USE bool onLeaveFrame(JSContext* cx,
-                                               AbstractFramePtr frame,
-                                               jsbytecode* pc, bool ok);
+  [[nodiscard]] static inline bool onLeaveFrame(JSContext* cx,
+                                                AbstractFramePtr frame,
+                                                jsbytecode* pc, bool ok);
 
   // Call any breakpoint handlers for the current scripted location.
-  static MOZ_MUST_USE bool onTrap(JSContext* cx);
+  [[nodiscard]] static bool onTrap(JSContext* cx);
 
   // Call any stepping handlers for the current scripted location.
-  static MOZ_MUST_USE bool onSingleStep(JSContext* cx);
+  [[nodiscard]] static bool onSingleStep(JSContext* cx);
 
   // Notify any Debugger instances observing this promise's global that a new
   // promise was allocated.
   static inline void onNewPromise(JSContext* cx,
                                   Handle<PromiseObject*> promise);
 
   // Notify any Debugger instances observing this promise's global that the
   // promise has settled (ie, it has either been fulfilled or rejected). Note
@@ -309,35 +309,35 @@ class DebugAPI {
   static bool hasExceptionUnwindHook(GlobalObject* global);
 
   // Whether any debugger is observing debugger statements in a realm.
   static bool hasDebuggerStatementHook(GlobalObject* global);
 
   /*** Assorted methods for interacting with the runtime. *********************/
 
   // Checks if the current compartment is allowed to execute code.
-  static inline MOZ_MUST_USE bool checkNoExecute(JSContext* cx,
-                                                 HandleScript script);
+  [[nodiscard]] static inline bool checkNoExecute(JSContext* cx,
+                                                  HandleScript script);
 
   /*
    * Announce to the debugger that a generator object has been created,
    * via JSOp::Generator.
    *
    * This does not fire user hooks, but it's needed for debugger bookkeeping.
    */
-  static inline MOZ_MUST_USE bool onNewGenerator(
+  [[nodiscard]] static inline bool onNewGenerator(
       JSContext* cx, AbstractFramePtr frame,
       Handle<AbstractGeneratorObject*> genObj);
 
   // If necessary, record an object that was just allocated for any observing
   // debuggers.
-  static inline MOZ_MUST_USE bool onLogAllocationSite(JSContext* cx,
-                                                      JSObject* obj,
-                                                      HandleSavedFrame frame,
-                                                      mozilla::TimeStamp when);
+  [[nodiscard]] static inline bool onLogAllocationSite(JSContext* cx,
+                                                       JSObject* obj,
+                                                       HandleSavedFrame frame,
+                                                       mozilla::TimeStamp when);
 
   // Announce to the debugger that a global object is being collected by the
   // specified major GC.
   static inline void notifyParticipatesInGC(GlobalObject* global,
                                             uint64_t majorGCNumber);
 
   /*
    * Get any instrumentation ID which has been associated with a script using
@@ -349,38 +349,38 @@ class DebugAPI {
 
  private:
   static bool stepModeEnabledSlow(JSScript* script);
   static bool hasBreakpointsAtSlow(JSScript* script, jsbytecode* pc);
   static void slowPathOnNewGlobalObject(JSContext* cx,
                                         Handle<GlobalObject*> global);
   static void slowPathNotifyParticipatesInGC(uint64_t majorGCNumber,
                                              JS::Realm::DebuggerVector& dbgs);
-  static MOZ_MUST_USE bool slowPathOnLogAllocationSite(
+  [[nodiscard]] static bool slowPathOnLogAllocationSite(
       JSContext* cx, HandleObject obj, HandleSavedFrame frame,
       mozilla::TimeStamp when, JS::Realm::DebuggerVector& dbgs);
-  static MOZ_MUST_USE bool slowPathOnLeaveFrame(JSContext* cx,
-                                                AbstractFramePtr frame,
-                                                jsbytecode* pc, bool ok);
-  static MOZ_MUST_USE bool slowPathOnNewGenerator(
+  [[nodiscard]] static bool slowPathOnLeaveFrame(JSContext* cx,
+                                                 AbstractFramePtr frame,
+                                                 jsbytecode* pc, bool ok);
+  [[nodiscard]] static bool slowPathOnNewGenerator(
       JSContext* cx, AbstractFramePtr frame,
       Handle<AbstractGeneratorObject*> genObj);
-  static MOZ_MUST_USE bool slowPathCheckNoExecute(JSContext* cx,
-                                                  HandleScript script);
-  static MOZ_MUST_USE bool slowPathOnEnterFrame(JSContext* cx,
-                                                AbstractFramePtr frame);
-  static MOZ_MUST_USE bool slowPathOnResumeFrame(JSContext* cx,
+  [[nodiscard]] static bool slowPathCheckNoExecute(JSContext* cx,
+                                                   HandleScript script);
+  [[nodiscard]] static bool slowPathOnEnterFrame(JSContext* cx,
                                                  AbstractFramePtr frame);
+  [[nodiscard]] static bool slowPathOnResumeFrame(JSContext* cx,
+                                                  AbstractFramePtr frame);
   static NativeResumeMode slowPathOnNativeCall(JSContext* cx,
                                                const CallArgs& args,
                                                CallReason reason);
-  static MOZ_MUST_USE bool slowPathOnDebuggerStatement(JSContext* cx,
-                                                       AbstractFramePtr frame);
-  static MOZ_MUST_USE bool slowPathOnExceptionUnwind(JSContext* cx,
-                                                     AbstractFramePtr frame);
+  [[nodiscard]] static bool slowPathOnDebuggerStatement(JSContext* cx,
+                                                        AbstractFramePtr frame);
+  [[nodiscard]] static bool slowPathOnExceptionUnwind(JSContext* cx,
+                                                      AbstractFramePtr frame);
   static void slowPathOnNewWasmInstance(
       JSContext* cx, Handle<WasmInstanceObject*> wasmInstance);
   static void slowPathOnNewPromise(JSContext* cx,
                                    Handle<PromiseObject*> promise);
   static void slowPathOnPromiseSettled(JSContext* cx,
                                        Handle<PromiseObject*> promise);
   static bool inFrameMaps(AbstractFramePtr frame);
   static void slowPathTraceGeneratorFrame(JSTracer* tracer,
--- a/js/src/debugger/DebugScript.h
+++ b/js/src/debugger/DebugScript.h
@@ -97,26 +97,26 @@ class DebugScript {
 #endif
 
   /*
    * Increment or decrement the single-step count. If the count is non-zero
    * then the script is in single-step mode.
    *
    * Only incrementing is fallible, as it could allocate a DebugScript.
    */
-  static MOZ_MUST_USE bool incrementStepperCount(JSContext* cx,
-                                                 JSScript* script);
+  [[nodiscard]] static bool incrementStepperCount(JSContext* cx,
+                                                  JSScript* script);
   static void decrementStepperCount(JSFreeOp* fop, JSScript* script);
 
   /*
    * Increment or decrement the generator observer count. If the count is
    * non-zero then the script reports resumptions to the debugger.
    *
    * Only incrementing is fallible, as it could allocate a DebugScript.
    */
-  static MOZ_MUST_USE bool incrementGeneratorObserverCount(JSContext* cx,
-                                                           JSScript* script);
+  [[nodiscard]] static bool incrementGeneratorObserverCount(JSContext* cx,
+                                                            JSScript* script);
   static void decrementGeneratorObserverCount(JSFreeOp* fop, JSScript* script);
 };
 
 } /* namespace js */
 
 #endif /* dbg_DebugScript_h */
--- a/js/src/debugger/Debugger.cpp
+++ b/js/src/debugger/Debugger.cpp
@@ -259,26 +259,26 @@ static void PropagateForcedReturn(JSCont
   // exception, but with a special flag. When the error is handled by the
   // interpreter or JIT, the special flag and the error state will be cleared
   // and execution will continue from the end of the frame.
   MOZ_ASSERT(!cx->isExceptionPending());
   cx->setPropagatingForcedReturn();
   frame.setReturnValue(rval);
 }
 
-static MOZ_MUST_USE bool AdjustGeneratorResumptionValue(JSContext* cx,
-                                                        AbstractFramePtr frame,
-                                                        ResumeMode& resumeMode,
-                                                        MutableHandleValue vp);
-
-static MOZ_MUST_USE bool ApplyFrameResumeMode(JSContext* cx,
-                                              AbstractFramePtr frame,
-                                              ResumeMode resumeMode,
-                                              HandleValue rv,
-                                              HandleSavedFrame exnStack) {
+[[nodiscard]] static bool AdjustGeneratorResumptionValue(JSContext* cx,
+                                                         AbstractFramePtr frame,
+                                                         ResumeMode& resumeMode,
+                                                         MutableHandleValue vp);
+
+[[nodiscard]] static bool ApplyFrameResumeMode(JSContext* cx,
+                                               AbstractFramePtr frame,
+                                               ResumeMode resumeMode,
+                                               HandleValue rv,
+                                               HandleSavedFrame exnStack) {
   RootedValue rval(cx, rv);
 
   // The value passed in here is unwrapped and has no guarantees about what
   // compartment it may be associated with, so we explicitly wrap it into the
   // debuggee compartment.
   if (!cx->compartment()->wrap(cx, &rval)) {
     return false;
   }
@@ -1705,20 +1705,19 @@ static bool CheckResumptionValue(JSConte
 }
 
 // Last-minute sanity adjustments to resumption.
 //
 // This is called last, as we leave the debugger. It must happen outside the
 // control of the uncaughtExceptionHook, because this code assumes we won't
 // change our minds and continue execution--we must not close the generator
 // object unless we're really going to force-return.
-static MOZ_MUST_USE bool AdjustGeneratorResumptionValue(JSContext* cx,
-                                                        AbstractFramePtr frame,
-                                                        ResumeMode& resumeMode,
-                                                        MutableHandleValue vp) {
+[[nodiscard]] static bool AdjustGeneratorResumptionValue(
+    JSContext* cx, AbstractFramePtr frame, ResumeMode& resumeMode,
+    MutableHandleValue vp) {
   if (resumeMode != ResumeMode::Return && resumeMode != ResumeMode::Throw) {
     return true;
   }
   if (!frame || !frame.isFunctionFrame()) {
     return true;
   }
 
   // Treat `{return: <value>}` like a `return` statement. Simulate what the
--- a/js/src/debugger/Debugger.h
+++ b/js/src/debugger/Debugger.h
@@ -3,17 +3,17 @@
  * 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 debugger_Debugger_h
 #define debugger_Debugger_h
 
 #include "mozilla/Assertions.h"        // for MOZ_ASSERT_HELPER1
-#include "mozilla/Attributes.h"        // for MOZ_MUST_USE, MOZ_RAII
+#include "mozilla/Attributes.h"        // [[nodiscard]] for, MOZ_RAII
 #include "mozilla/DoublyLinkedList.h"  // for DoublyLinkedListElement
 #include "mozilla/HashTable.h"         // for HashSet, DefaultHasher (ptr only)
 #include "mozilla/LinkedList.h"        // for LinkedList (ptr only)
 #include "mozilla/Maybe.h"             // for Maybe, Nothing
 #include "mozilla/Range.h"             // for Range
 #include "mozilla/Result.h"            // for Result
 #include "mozilla/TimeStamp.h"         // for TimeStamp
 #include "mozilla/Variant.h"           // for Variant
@@ -657,17 +657,17 @@ class Debugger : private mozilla::Linked
    */
   static bool cannotTrackAllocations(const GlobalObject& global);
 
   /*
    * Add allocations tracking for objects allocated within the given
    * debuggee's compartment. The given debuggee global must be observed by at
    * least one Debugger that is tracking allocations.
    */
-  static MOZ_MUST_USE bool addAllocationsTracking(
+  [[nodiscard]] static bool addAllocationsTracking(
       JSContext* cx, Handle<GlobalObject*> debuggee);
 
   /*
    * Remove allocations tracking for objects allocated within the given
    * global's compartment. This is a no-op if there are still Debuggers
    * observing this global and who are tracking allocations.
    */
   static void removeAllocationsTracking(GlobalObject& global);
@@ -861,27 +861,27 @@ class Debugger : private mozilla::Linked
 
   void traceForMovingGC(JSTracer* trc);
   void traceCrossCompartmentEdges(JSTracer* tracer);
 
  private:
   template <typename F>
   void forEachWeakMap(const F& f);
 
-  static MOZ_MUST_USE bool getHookImpl(JSContext* cx, const CallArgs& args,
-                                       Debugger& dbg, Hook which);
-  static MOZ_MUST_USE bool setHookImpl(JSContext* cx, const CallArgs& args,
-                                       Debugger& dbg, Hook which);
+  [[nodiscard]] static bool getHookImpl(JSContext* cx, const CallArgs& args,
+                                        Debugger& dbg, Hook which);
+  [[nodiscard]] static bool setHookImpl(JSContext* cx, const CallArgs& args,
+                                        Debugger& dbg, Hook which);
 
-  static MOZ_MUST_USE bool getGarbageCollectionHook(JSContext* cx,
-                                                    const CallArgs& args,
-                                                    Debugger& dbg);
-  static MOZ_MUST_USE bool setGarbageCollectionHook(JSContext* cx,
-                                                    const CallArgs& args,
-                                                    Debugger& dbg);
+  [[nodiscard]] static bool getGarbageCollectionHook(JSContext* cx,
+                                                     const CallArgs& args,
+                                                     Debugger& dbg);
+  [[nodiscard]] static bool setGarbageCollectionHook(JSContext* cx,
+                                                     const CallArgs& args,
+                                                     Debugger& dbg);
 
   static bool isCompilableUnit(JSContext* cx, unsigned argc, Value* vp);
   static bool recordReplayProcessKind(JSContext* cx, unsigned argc, Value* vp);
   static bool construct(JSContext* cx, unsigned argc, Value* vp);
 
   struct CallData;
 
   static const JSPropertySpec properties[];
@@ -935,22 +935,22 @@ class Debugger : private mozilla::Linked
                                                      FrameFn fn);
 
   /*
    * Return a vector containing all Debugger.Frame instances referring to
    * |frame|. |global| is |frame|'s global object; if nullptr or omitted, we
    * compute it ourselves from |frame|.
    */
   using DebuggerFrameVector = GCVector<DebuggerFrame*>;
-  static MOZ_MUST_USE bool getDebuggerFrames(
+  [[nodiscard]] static bool getDebuggerFrames(
       AbstractFramePtr frame, MutableHandle<DebuggerFrameVector> frames);
 
  public:
   // Public for DebuggerScript::setBreakpoint.
-  static MOZ_MUST_USE bool ensureExecutionObservabilityOfScript(
+  [[nodiscard]] static bool ensureExecutionObservabilityOfScript(
       JSContext* cx, JSScript* script);
 
   // Whether the Debugger instance needs to observe all non-AOT JS
   // execution of its debugees.
   IsObserving observesAllExecution() const;
 
   // Whether the Debugger instance needs to observe AOT-compiled asm.js
   // execution of its debuggees.
@@ -959,19 +959,19 @@ class Debugger : private mozilla::Linked
   // Whether the Debugger instance needs to observe coverage of any JavaScript
   // execution.
   IsObserving observesCoverage() const;
 
   // Whether the Debugger instance needs to observe native call invocations.
   IsObserving observesNativeCalls() const;
 
  private:
-  static MOZ_MUST_USE bool ensureExecutionObservabilityOfFrame(
+  [[nodiscard]] static bool ensureExecutionObservabilityOfFrame(
       JSContext* cx, AbstractFramePtr frame);
-  static MOZ_MUST_USE bool ensureExecutionObservabilityOfRealm(
+  [[nodiscard]] static bool ensureExecutionObservabilityOfRealm(
       JSContext* cx, JS::Realm* realm);
 
   static bool hookObservesAllExecution(Hook which);
 
   [[nodiscard]] bool updateObservesAllExecutionOnDebuggees(
       JSContext* cx, IsObserving observing);
   [[nodiscard]] bool updateObservesCoverageOnDebuggees(JSContext* cx,
                                                        IsObserving observing);
@@ -985,17 +985,17 @@ class Debugger : private mozilla::Linked
                                   Handle<PromiseObject*> promise);
 
   template <typename HookIsEnabledFun /* bool (Debugger*) */,
             typename FireHookFun /* void (Debugger*) */>
   static void dispatchQuietHook(JSContext* cx, HookIsEnabledFun hookIsEnabled,
                                 FireHookFun fireHook);
   template <
       typename HookIsEnabledFun /* bool (Debugger*) */, typename FireHookFun /* bool (Debugger*, ResumeMode&, MutableHandleValue) */>
-  static MOZ_MUST_USE bool dispatchResumptionHook(
+  [[nodiscard]] static bool dispatchResumptionHook(
       JSContext* cx, AbstractFramePtr frame, HookIsEnabledFun hookIsEnabled,
       FireHookFun fireHook);
 
   template <typename RunImpl /* bool () */>
   [[nodiscard]] bool enterDebuggerHook(JSContext* cx, RunImpl runImpl) {
     if (!isHookCallAllowed(cx)) {
       return true;
     }
@@ -1083,20 +1083,20 @@ class Debugger : private mozilla::Linked
    * Receive a "garbage collection" event from the engine. A GC cycle with the
    * given data was recently completed.
    */
   [[nodiscard]] bool fireOnGarbageCollectionHook(
       JSContext* cx, const JS::dbg::GarbageCollectionEvent::Ptr& gcData);
 
   inline Breakpoint* firstBreakpoint() const;
 
-  static MOZ_MUST_USE bool replaceFrameGuts(JSContext* cx,
-                                            AbstractFramePtr from,
-                                            AbstractFramePtr to,
-                                            ScriptFrameIter& iter);
+  [[nodiscard]] static bool replaceFrameGuts(JSContext* cx,
+                                             AbstractFramePtr from,
+                                             AbstractFramePtr to,
+                                             ScriptFrameIter& iter);
 
  public:
   Debugger(JSContext* cx, NativeObject* dbg);
   ~Debugger();
 
   inline const js::HeapPtrNativeObject& toJSObject() const;
   inline js::HeapPtrNativeObject& toJSObjectRef();
   static inline Debugger* fromJSObject(const JSObject* obj);
--- a/js/src/debugger/Environment.h
+++ b/js/src/debugger/Environment.h
@@ -3,17 +3,17 @@
  * 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 debugger_Environment_h
 #define debugger_Environment_h
 
 #include "mozilla/Assertions.h"  // for AssertionConditionType, MOZ_ASSERT
-#include "mozilla/Attributes.h"  // for MOZ_MUST_USE
+#include "mozilla/Attributes.h"  // [[nodiscard]] for
 #include "mozilla/Maybe.h"       // for Maybe
 
 #include "jstypes.h"            // for JS_PUBLIC_API
 #include "NamespaceImports.h"   // for Value, HandleId, HandleObject
 #include "debugger/Debugger.h"  // for Env
 #include "gc/Rooting.h"         // for HandleDebuggerEnvironment
 #include "js/PropertySpec.h"    // for JSFunctionSpec, JSPropertySpec
 #include "js/RootingAPI.h"      // for Handle, MutableHandle
@@ -52,29 +52,29 @@ class DebuggerEnvironment : public Nativ
                                MutableHandleDebuggerEnvironment result) const;
   [[nodiscard]] bool getObject(JSContext* cx,
                                MutableHandleDebuggerObject result) const;
   [[nodiscard]] bool getCalleeScript(JSContext* cx,
                                      MutableHandleDebuggerScript result) const;
   bool isDebuggee() const;
   bool isOptimized() const;
 
-  static MOZ_MUST_USE bool getNames(JSContext* cx,
-                                    HandleDebuggerEnvironment environment,
-                                    MutableHandle<IdVector> result);
-  static MOZ_MUST_USE bool find(JSContext* cx,
-                                HandleDebuggerEnvironment environment,
-                                HandleId id,
-                                MutableHandleDebuggerEnvironment result);
-  static MOZ_MUST_USE bool getVariable(JSContext* cx,
-                                       HandleDebuggerEnvironment environment,
-                                       HandleId id, MutableHandleValue result);
-  static MOZ_MUST_USE bool setVariable(JSContext* cx,
-                                       HandleDebuggerEnvironment environment,
-                                       HandleId id, HandleValue value);
+  [[nodiscard]] static bool getNames(JSContext* cx,
+                                     HandleDebuggerEnvironment environment,
+                                     MutableHandle<IdVector> result);
+  [[nodiscard]] static bool find(JSContext* cx,
+                                 HandleDebuggerEnvironment environment,
+                                 HandleId id,
+                                 MutableHandleDebuggerEnvironment result);
+  [[nodiscard]] static bool getVariable(JSContext* cx,
+                                        HandleDebuggerEnvironment environment,
+                                        HandleId id, MutableHandleValue result);
+  [[nodiscard]] static bool setVariable(JSContext* cx,
+                                        HandleDebuggerEnvironment environment,
+                                        HandleId id, HandleValue value);
 
   bool isInstance() const;
   Debugger* owner() const;
 
   Env* referent() const {
     Env* env = static_cast<Env*>(getPrivate());
     MOZ_ASSERT(env);
     return env;
@@ -83,16 +83,16 @@ class DebuggerEnvironment : public Nativ
  private:
   static const JSClassOps classOps_;
 
   static const JSPropertySpec properties_[];
   static const JSFunctionSpec methods_[];
 
   bool requireDebuggee(JSContext* cx) const;
 
-  static MOZ_MUST_USE bool construct(JSContext* cx, unsigned argc, Value* vp);
+  [[nodiscard]] static bool construct(JSContext* cx, unsigned argc, Value* vp);
 
   struct CallData;
 };
 
 } /* namespace js */
 
 #endif /* debugger_Environment_h */
--- a/js/src/debugger/Frame.h
+++ b/js/src/debugger/Frame.h
@@ -2,17 +2,17 @@
  * vim: set ts=8 sts=2 et sw=2 tw=80:
  * 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 debugger_Frame_h
 #define debugger_Frame_h
 
-#include "mozilla/Attributes.h"  // for MOZ_MUST_USE
+#include "mozilla/Attributes.h"  // [[nodiscard]] for
 #include "mozilla/Maybe.h"       // for Maybe
 #include "mozilla/Range.h"       // for Range
 #include "mozilla/Result.h"      // for Result
 
 #include <stddef.h>  // for size_t
 
 #include "jsapi.h"  // for JSContext, CallArgs
 
@@ -146,52 +146,52 @@ class DebuggerFrame : public NativeObjec
 
   static NativeObject* initClass(JSContext* cx, Handle<GlobalObject*> global,
                                  HandleObject dbgCtor);
   static DebuggerFrame* create(JSContext* cx, HandleObject proto,
                                HandleNativeObject debugger,
                                const FrameIter* maybeIter,
                                Handle<AbstractGeneratorObject*> maybeGenerator);
 
-  static MOZ_MUST_USE bool getArguments(JSContext* cx,
-                                        HandleDebuggerFrame frame,
-                                        MutableHandleDebuggerArguments result);
-  static MOZ_MUST_USE bool getCallee(JSContext* cx, HandleDebuggerFrame frame,
-                                     MutableHandleDebuggerObject result);
-  static MOZ_MUST_USE bool getIsConstructing(JSContext* cx,
-                                             HandleDebuggerFrame frame,
-                                             bool& result);
-  static MOZ_MUST_USE bool getEnvironment(
+  [[nodiscard]] static bool getArguments(JSContext* cx,
+                                         HandleDebuggerFrame frame,
+                                         MutableHandleDebuggerArguments result);
+  [[nodiscard]] static bool getCallee(JSContext* cx, HandleDebuggerFrame frame,
+                                      MutableHandleDebuggerObject result);
+  [[nodiscard]] static bool getIsConstructing(JSContext* cx,
+                                              HandleDebuggerFrame frame,
+                                              bool& result);
+  [[nodiscard]] static bool getEnvironment(
       JSContext* cx, HandleDebuggerFrame frame,
       MutableHandleDebuggerEnvironment result);
-  static MOZ_MUST_USE bool getOffset(JSContext* cx, HandleDebuggerFrame frame,
-                                     size_t& result);
-  static MOZ_MUST_USE bool getOlder(JSContext* cx, HandleDebuggerFrame frame,
-                                    MutableHandleDebuggerFrame result);
-  static MOZ_MUST_USE bool getAsyncPromise(JSContext* cx,
-                                           HandleDebuggerFrame frame,
-                                           MutableHandleDebuggerObject result);
-  static MOZ_MUST_USE bool getOlderSavedFrame(JSContext* cx,
-                                              HandleDebuggerFrame frame,
-                                              MutableHandleSavedFrame result);
-  static MOZ_MUST_USE bool getThis(JSContext* cx, HandleDebuggerFrame frame,
-                                   MutableHandleValue result);
+  [[nodiscard]] static bool getOffset(JSContext* cx, HandleDebuggerFrame frame,
+                                      size_t& result);
+  [[nodiscard]] static bool getOlder(JSContext* cx, HandleDebuggerFrame frame,
+                                     MutableHandleDebuggerFrame result);
+  [[nodiscard]] static bool getAsyncPromise(JSContext* cx,
+                                            HandleDebuggerFrame frame,
+                                            MutableHandleDebuggerObject result);
+  [[nodiscard]] static bool getOlderSavedFrame(JSContext* cx,
+                                               HandleDebuggerFrame frame,
+                                               MutableHandleSavedFrame result);
+  [[nodiscard]] static bool getThis(JSContext* cx, HandleDebuggerFrame frame,
+                                    MutableHandleValue result);
   static DebuggerFrameType getType(HandleDebuggerFrame frame);
   static DebuggerFrameImplementation getImplementation(
       HandleDebuggerFrame frame);
-  static MOZ_MUST_USE bool setOnStepHandler(JSContext* cx,
-                                            HandleDebuggerFrame frame,
-                                            OnStepHandler* handler);
+  [[nodiscard]] static bool setOnStepHandler(JSContext* cx,
+                                             HandleDebuggerFrame frame,
+                                             OnStepHandler* handler);
 
-  static MOZ_MUST_USE JS::Result<Completion> eval(
+  [[nodiscard]] static JS::Result<Completion> eval(
       JSContext* cx, HandleDebuggerFrame frame,
       mozilla::Range<const char16_t> chars, HandleObject bindings,
       const EvalOptions& options);
 
-  static MOZ_MUST_USE DebuggerFrame* check(JSContext* cx, HandleValue thisv);
+  [[nodiscard]] static DebuggerFrame* check(JSContext* cx, HandleValue thisv);
 
   bool isOnStack() const;
 
   // Like isOnStack, but works even in the midst of a relocating GC.
   bool isOnStackMaybeForwarded() const;
 
   bool isSuspended() const;
 
@@ -261,20 +261,20 @@ class DebuggerFrame : public NativeObjec
   static const JSClassOps classOps_;
 
   static const JSPropertySpec properties_[];
   static const JSFunctionSpec methods_[];
 
   static void finalize(JSFreeOp* fop, JSObject* obj);
 
   static AbstractFramePtr getReferent(HandleDebuggerFrame frame);
-  static MOZ_MUST_USE bool requireScriptReferent(JSContext* cx,
-                                                 HandleDebuggerFrame frame);
+  [[nodiscard]] static bool requireScriptReferent(JSContext* cx,
+                                                  HandleDebuggerFrame frame);
 
-  static MOZ_MUST_USE bool construct(JSContext* cx, unsigned argc, Value* vp);
+  [[nodiscard]] static bool construct(JSContext* cx, unsigned argc, Value* vp);
 
   struct CallData;
 
   [[nodiscard]] bool incrementStepperCounter(JSContext* cx,
                                              AbstractFramePtr referent);
   [[nodiscard]] bool incrementStepperCounter(JSContext* cx, JSScript* script);
   void decrementStepperCounter(JSFreeOp* fop, JSScript* script);
   void decrementStepperCounter(JSFreeOp* fop, AbstractFramePtr referent);
--- a/js/src/debugger/Object.h
+++ b/js/src/debugger/Object.h
@@ -3,17 +3,17 @@
  * 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 debugger_Object_h
 #define debugger_Object_h
 
 #include "mozilla/Assertions.h"  // for AssertionConditionType, MOZ_ASSERT
-#include "mozilla/Attributes.h"  // for MOZ_MUST_USE
+#include "mozilla/Attributes.h"  // [[nodiscard]] for
 #include "mozilla/Maybe.h"       // for Maybe
 #include "mozilla/Range.h"       // for Range
 #include "mozilla/Result.h"      // for Result
 
 #include "jsapi.h"             // for JSContext
 #include "jstypes.h"           // for JS_PUBLIC_API
 #include "NamespaceImports.h"  // for Value, MutableHandleValue, HandleId
 
@@ -41,121 +41,121 @@ class DebuggerObject : public NativeObje
                                  HandleObject debugCtor);
   static DebuggerObject* create(JSContext* cx, HandleObject proto,
                                 HandleObject referent,
                                 HandleNativeObject debugger);
 
   void trace(JSTracer* trc);
 
   // Properties
-  static MOZ_MUST_USE bool getClassName(JSContext* cx,
-                                        HandleDebuggerObject object,
-                                        MutableHandleString result);
-  static MOZ_MUST_USE bool getBoundTargetFunction(
+  [[nodiscard]] static bool getClassName(JSContext* cx,
+                                         HandleDebuggerObject object,
+                                         MutableHandleString result);
+  [[nodiscard]] static bool getBoundTargetFunction(
       JSContext* cx, HandleDebuggerObject object,
       MutableHandleDebuggerObject result);
-  static MOZ_MUST_USE bool getBoundThis(JSContext* cx,
-                                        HandleDebuggerObject object,
-                                        MutableHandleValue result);
-  static MOZ_MUST_USE bool getBoundArguments(JSContext* cx,
-                                             HandleDebuggerObject object,
-                                             MutableHandle<ValueVector> result);
-  static MOZ_MUST_USE bool getAllocationSite(JSContext* cx,
-                                             HandleDebuggerObject object,
-                                             MutableHandleObject result);
-  static MOZ_MUST_USE bool getErrorMessageName(JSContext* cx,
-                                               HandleDebuggerObject object,
-                                               MutableHandleString result);
-  static MOZ_MUST_USE bool getErrorNotes(JSContext* cx,
+  [[nodiscard]] static bool getBoundThis(JSContext* cx,
                                          HandleDebuggerObject object,
                                          MutableHandleValue result);
-  static MOZ_MUST_USE bool getErrorLineNumber(JSContext* cx,
+  [[nodiscard]] static bool getBoundArguments(
+      JSContext* cx, HandleDebuggerObject object,
+      MutableHandle<ValueVector> result);
+  [[nodiscard]] static bool getAllocationSite(JSContext* cx,
                                               HandleDebuggerObject object,
-                                              MutableHandleValue result);
-  static MOZ_MUST_USE bool getErrorColumnNumber(JSContext* cx,
+                                              MutableHandleObject result);
+  [[nodiscard]] static bool getErrorMessageName(JSContext* cx,
                                                 HandleDebuggerObject object,
-                                                MutableHandleValue result);
-  static MOZ_MUST_USE bool getScriptedProxyTarget(
+                                                MutableHandleString result);
+  [[nodiscard]] static bool getErrorNotes(JSContext* cx,
+                                          HandleDebuggerObject object,
+                                          MutableHandleValue result);
+  [[nodiscard]] static bool getErrorLineNumber(JSContext* cx,
+                                               HandleDebuggerObject object,
+                                               MutableHandleValue result);
+  [[nodiscard]] static bool getErrorColumnNumber(JSContext* cx,
+                                                 HandleDebuggerObject object,
+                                                 MutableHandleValue result);
+  [[nodiscard]] static bool getScriptedProxyTarget(
       JSContext* cx, HandleDebuggerObject object,
       MutableHandleDebuggerObject result);
-  static MOZ_MUST_USE bool getScriptedProxyHandler(
+  [[nodiscard]] static bool getScriptedProxyHandler(
       JSContext* cx, HandleDebuggerObject object,
       MutableHandleDebuggerObject result);
-  static MOZ_MUST_USE bool getPromiseValue(JSContext* cx,
-                                           HandleDebuggerObject object,
-                                           MutableHandleValue result);
-  static MOZ_MUST_USE bool getPromiseReason(JSContext* cx,
+  [[nodiscard]] static bool getPromiseValue(JSContext* cx,
                                             HandleDebuggerObject object,
                                             MutableHandleValue result);
+  [[nodiscard]] static bool getPromiseReason(JSContext* cx,
+                                             HandleDebuggerObject object,
+                                             MutableHandleValue result);
 
   // Methods
-  static MOZ_MUST_USE bool isExtensible(JSContext* cx,
-                                        HandleDebuggerObject object,
-                                        bool& result);
-  static MOZ_MUST_USE bool isSealed(JSContext* cx, HandleDebuggerObject object,
-                                    bool& result);
-  static MOZ_MUST_USE bool isFrozen(JSContext* cx, HandleDebuggerObject object,
-                                    bool& result);
-  static MOZ_MUST_USE JS::Result<Completion> getProperty(
+  [[nodiscard]] static bool isExtensible(JSContext* cx,
+                                         HandleDebuggerObject object,
+                                         bool& result);
+  [[nodiscard]] static bool isSealed(JSContext* cx, HandleDebuggerObject object,
+                                     bool& result);
+  [[nodiscard]] static bool isFrozen(JSContext* cx, HandleDebuggerObject object,
+                                     bool& result);
+  [[nodiscard]] static JS::Result<Completion> getProperty(
       JSContext* cx, HandleDebuggerObject object, HandleId id,
       HandleValue receiver);
-  static MOZ_MUST_USE JS::Result<Completion> setProperty(
+  [[nodiscard]] static JS::Result<Completion> setProperty(
       JSContext* cx, HandleDebuggerObject object, HandleId id,
       HandleValue value, HandleValue receiver);
-  static MOZ_MUST_USE bool getPrototypeOf(JSContext* cx,
-                                          HandleDebuggerObject object,
-                                          MutableHandleDebuggerObject result);
-  static MOZ_MUST_USE bool getOwnPropertyNames(JSContext* cx,
-                                               HandleDebuggerObject object,
-                                               MutableHandle<IdVector> result);
-  static MOZ_MUST_USE bool getOwnPropertySymbols(
+  [[nodiscard]] static bool getPrototypeOf(JSContext* cx,
+                                           HandleDebuggerObject object,
+                                           MutableHandleDebuggerObject result);
+  [[nodiscard]] static bool getOwnPropertyNames(JSContext* cx,
+                                                HandleDebuggerObject object,
+                                                MutableHandle<IdVector> result);
+  [[nodiscard]] static bool getOwnPropertySymbols(
       JSContext* cx, HandleDebuggerObject object,
       MutableHandle<IdVector> result);
-  static MOZ_MUST_USE bool getOwnPropertyDescriptor(
+  [[nodiscard]] static bool getOwnPropertyDescriptor(
       JSContext* cx, HandleDebuggerObject object, HandleId id,
       MutableHandle<PropertyDescriptor> desc);
-  static MOZ_MUST_USE bool preventExtensions(JSContext* cx,
-                                             HandleDebuggerObject object);
-  static MOZ_MUST_USE bool seal(JSContext* cx, HandleDebuggerObject object);
-  static MOZ_MUST_USE bool freeze(JSContext* cx, HandleDebuggerObject object);
-  static MOZ_MUST_USE bool defineProperty(JSContext* cx,
-                                          HandleDebuggerObject object,
-                                          HandleId id,
-                                          Handle<PropertyDescriptor> desc);
-  static MOZ_MUST_USE bool defineProperties(
+  [[nodiscard]] static bool preventExtensions(JSContext* cx,
+                                              HandleDebuggerObject object);
+  [[nodiscard]] static bool seal(JSContext* cx, HandleDebuggerObject object);
+  [[nodiscard]] static bool freeze(JSContext* cx, HandleDebuggerObject object);
+  [[nodiscard]] static bool defineProperty(JSContext* cx,
+                                           HandleDebuggerObject object,
+                                           HandleId id,
+                                           Handle<PropertyDescriptor> desc);
+  [[nodiscard]] static bool defineProperties(
       JSContext* cx, HandleDebuggerObject object, Handle<IdVector> ids,
       Handle<PropertyDescriptorVector> descs);
-  static MOZ_MUST_USE bool deleteProperty(JSContext* cx,
-                                          HandleDebuggerObject object,
-                                          HandleId id, ObjectOpResult& result);
-  static MOZ_MUST_USE mozilla::Maybe<Completion> call(
+  [[nodiscard]] static bool deleteProperty(JSContext* cx,
+                                           HandleDebuggerObject object,
+                                           HandleId id, ObjectOpResult& result);
+  [[nodiscard]] static mozilla::Maybe<Completion> call(
       JSContext* cx, HandleDebuggerObject object, HandleValue thisv,
       Handle<ValueVector> args);
-  static MOZ_MUST_USE bool forceLexicalInitializationByName(
+  [[nodiscard]] static bool forceLexicalInitializationByName(
       JSContext* cx, HandleDebuggerObject object, HandleId id, bool& result);
-  static MOZ_MUST_USE JS::Result<Completion> executeInGlobal(
+  [[nodiscard]] static JS::Result<Completion> executeInGlobal(
       JSContext* cx, HandleDebuggerObject object,
       mozilla::Range<const char16_t> chars, HandleObject bindings,
       const EvalOptions& options);
-  static MOZ_MUST_USE bool makeDebuggeeValue(JSContext* cx,
-                                             HandleDebuggerObject object,
-                                             HandleValue value,
-                                             MutableHandleValue result);
-  static MOZ_MUST_USE bool makeDebuggeeNativeFunction(
+  [[nodiscard]] static bool makeDebuggeeValue(JSContext* cx,
+                                              HandleDebuggerObject object,
+                                              HandleValue value,
+                                              MutableHandleValue result);
+  [[nodiscard]] static bool makeDebuggeeNativeFunction(
       JSContext* cx, HandleDebuggerObject object, HandleValue value,
       MutableHandleValue result);
-  static MOZ_MUST_USE bool isSameNative(JSContext* cx,
-                                        HandleDebuggerObject object,
-                                        HandleValue value,
-                                        MutableHandleValue result);
-  static MOZ_MUST_USE bool unsafeDereference(JSContext* cx,
-                                             HandleDebuggerObject object,
-                                             MutableHandleObject result);
-  static MOZ_MUST_USE bool unwrap(JSContext* cx, HandleDebuggerObject object,
-                                  MutableHandleDebuggerObject result);
+  [[nodiscard]] static bool isSameNative(JSContext* cx,
+                                         HandleDebuggerObject object,
+                                         HandleValue value,
+                                         MutableHandleValue result);
+  [[nodiscard]] static bool unsafeDereference(JSContext* cx,
+                                              HandleDebuggerObject object,
+                                              MutableHandleObject result);
+  [[nodiscard]] static bool unwrap(JSContext* cx, HandleDebuggerObject object,
+                                   MutableHandleDebuggerObject result);
 
   // Infallible properties
   bool isCallable() const;
   bool isFunction() const;
   bool isDebuggeeFunction() const;
   bool isBoundFunction() const;
   bool isArrowFunction() const;
   bool isAsyncFunction() const;
@@ -188,25 +188,25 @@ class DebuggerObject : public NativeObje
   static const JSClassOps classOps_;
 
   static const JSPropertySpec properties_[];
   static const JSPropertySpec promiseProperties_[];
   static const JSFunctionSpec methods_[];
 
   PromiseObject* promise() const;
 
-  static MOZ_MUST_USE bool requireGlobal(JSContext* cx,
-                                         HandleDebuggerObject object);
-  static MOZ_MUST_USE bool requirePromise(JSContext* cx,
+  [[nodiscard]] static bool requireGlobal(JSContext* cx,
                                           HandleDebuggerObject object);
-  static MOZ_MUST_USE bool construct(JSContext* cx, unsigned argc, Value* vp);
+  [[nodiscard]] static bool requirePromise(JSContext* cx,
+                                           HandleDebuggerObject object);
+  [[nodiscard]] static bool construct(JSContext* cx, unsigned argc, Value* vp);
 
   struct CallData;
   struct PromiseReactionRecordBuilder;
 
-  static MOZ_MUST_USE bool getErrorReport(JSContext* cx,
-                                          HandleObject maybeError,
-                                          JSErrorReport*& report);
+  [[nodiscard]] static bool getErrorReport(JSContext* cx,
+                                           HandleObject maybeError,
+                                           JSErrorReport*& report);
 };
 
 } /* namespace js */
 
 #endif /* debugger_Object_h */
--- a/js/src/ds/InlineTable.h
+++ b/js/src/ds/InlineTable.h
@@ -104,18 +104,17 @@ class InlineTable : private AllocPolicy 
     }
 
     inlNext_ = InlineEntries + 1;
     MOZ_ASSERT(table_.count() == inlCount_);
     MOZ_ASSERT(usingTable());
     return true;
   }
 
-  MOZ_NEVER_INLINE
-  MOZ_MUST_USE bool switchAndAdd(const InlineEntry& entry) {
+  [[nodiscard]] MOZ_NEVER_INLINE bool switchAndAdd(const InlineEntry& entry) {
     if (!switchToTable()) {
       return false;
     }
 
     return entry.putNew(table_);
   }
 
  public:
@@ -283,18 +282,18 @@ class InlineTable : private AllocPolicy 
 
     // The add pointer that's returned here may indicate the limit entry of
     // the linear space, in which case the |add| operation will initialize
     // the table if necessary and add the entry there.
     return AddPtr(inlineEnd(), false);
   }
 
   template <typename KeyInput, typename... Args>
-  MOZ_ALWAYS_INLINE MOZ_MUST_USE bool add(AddPtr& p, KeyInput&& key,
-                                          Args&&... args) {
+  [[nodiscard]] MOZ_ALWAYS_INLINE bool add(AddPtr& p, KeyInput&& key,
+                                           Args&&... args) {
     MOZ_ASSERT(!p);
     MOZ_ASSERT(keyNonZero(key));
 
     if (p.isInlinePtr_) {
       InlineEntry* addPtr = p.inlAddPtr_;
       MOZ_ASSERT(addPtr == inlineEnd());
 
       // Switching to table mode before we add this pointer.
@@ -515,18 +514,18 @@ class InlineMap {
   bool has(const Lookup& l) const {
     return const_cast<InlineMap*>(this)->lookup(l).found();
   }
 
   MOZ_ALWAYS_INLINE
   AddPtr lookupForAdd(const Lookup& l) { return impl_.lookupForAdd(l); }
 
   template <typename KeyInput, typename ValueInput>
-  MOZ_ALWAYS_INLINE MOZ_MUST_USE bool add(AddPtr& p, KeyInput&& key,
-                                          ValueInput&& value) {
+  [[nodiscard]] MOZ_ALWAYS_INLINE bool add(AddPtr& p, KeyInput&& key,
+                                           ValueInput&& value) {
     return impl_.add(p, std::forward<KeyInput>(key),
                      std::forward<ValueInput>(value));
   }
 
   template <typename KeyInput, typename ValueInput>
   [[nodiscard]] bool put(KeyInput&& key, ValueInput&& value) {
     AddPtr p = lookupForAdd(key);
     if (p) {
@@ -620,17 +619,17 @@ class InlineSet {
   bool has(const Lookup& l) const {
     return const_cast<InlineSet*>(this)->lookup(l).found();
   }
 
   MOZ_ALWAYS_INLINE
   AddPtr lookupForAdd(const Lookup& l) { return impl_.lookupForAdd(l); }
 
   template <typename TInput>
-  MOZ_ALWAYS_INLINE MOZ_MUST_USE bool add(AddPtr& p, TInput&& key) {
+  [[nodiscard]] MOZ_ALWAYS_INLINE bool add(AddPtr& p, TInput&& key) {
     return impl_.add(p, std::forward<TInput>(key));
   }
 
   template <typename TInput>
   [[nodiscard]] bool put(TInput&& key) {
     AddPtr p = lookupForAdd(key);
     return p ? true : add(p, std::forward<TInput>(key));
   }
--- a/js/src/ds/LifoAlloc.h
+++ b/js/src/ds/LifoAlloc.h
@@ -403,18 +403,18 @@ class BumpChunk : public SingleLinkedLis
   void release(Mark m) {
     MOZ_RELEASE_ASSERT(contains(m));
     setBump(m.bump_);
   }
 
   // Given an amount, compute the total size of a chunk for it: reserved
   // space before |begin()|, space for |amount| bytes, and red-zone space
   // after those bytes that will ultimately end at |capacity_|.
-  static inline MOZ_MUST_USE bool allocSizeWithRedZone(size_t amount,
-                                                       size_t* size);
+  [[nodiscard]] static inline bool allocSizeWithRedZone(size_t amount,
+                                                        size_t* size);
 
   // Given a bump chunk pointer, find the next base/end pointers. This is
   // useful for having consistent allocations, and iterating over known size
   // allocations.
   static uint8_t* nextAllocBase(uint8_t* e) { return detail::AlignPtr(e); }
   static uint8_t* nextAllocEnd(uint8_t* b, size_t n) {
     return b + n + RedZoneSize;
   }
@@ -466,17 +466,17 @@ class BumpChunk : public SingleLinkedLis
 };
 
 // Space reserved for the BumpChunk internal data, and the alignment of the
 // first allocation content. This can be used to ensure there is enough space
 // for the next allocation (see LifoAlloc::newChunkWithCapacity).
 static constexpr size_t BumpChunkReservedSpace =
     AlignBytes(sizeof(BumpChunk), LIFO_ALLOC_ALIGN);
 
-/* static */ inline MOZ_MUST_USE bool BumpChunk::allocSizeWithRedZone(
+[[nodiscard]] /* static */ inline bool BumpChunk::allocSizeWithRedZone(
     size_t amount, size_t* size) {
   constexpr size_t SpaceBefore = BumpChunkReservedSpace;
   static_assert((SpaceBefore % LIFO_ALLOC_ALIGN) == 0,
                 "reserved space presumed already aligned");
 
   constexpr size_t SpaceAfter = RedZoneSize;  // may be zero
 
   constexpr size_t SpaceBeforeAndAfter = SpaceBefore + SpaceAfter;
@@ -693,18 +693,17 @@ class LifoAlloc {
     }
     oomUnsafe.crash("LifoAlloc::allocInfallible");
     return nullptr;
   }
 
   // Ensures that enough space exists to satisfy N bytes worth of
   // allocation requests, not necessarily contiguous. Note that this does
   // not guarantee a successful single allocation of N bytes.
-  MOZ_ALWAYS_INLINE
-  MOZ_MUST_USE bool ensureUnusedApproximate(size_t n) {
+  [[nodiscard]] MOZ_ALWAYS_INLINE bool ensureUnusedApproximate(size_t n) {
     AutoFallibleScope fallibleAllocator(this);
     size_t total = 0;
     if (!chunks_.empty()) {
       total += chunks_.last()->unused();
       if (total >= n) {
         return true;
       }
     }
--- a/js/src/ds/PageProtectingVector.h
+++ b/js/src/ds/PageProtectingVector.h
@@ -258,17 +258,17 @@ class PageProtectingVector final {
     if (MOZ_UNLIKELY(next == curr)) {
       return;
     }
     void* addr = reinterpret_cast<T*>(curr << pageShift);
     size_t size = (next - curr) << pageShift;
     gc::MakePagesReadOnly(addr, size);
   }
 
-  MOZ_ALWAYS_INLINE MOZ_MUST_USE bool reserveNewBuffer(size_t size) {
+  [[nodiscard]] MOZ_ALWAYS_INLINE bool reserveNewBuffer(size_t size) {
     unprotectOldBuffer();
     bool ret = vector.reserve(size);
     protectNewBuffer();
     return ret;
   }
 
   template <typename U>
   MOZ_ALWAYS_INLINE void infallibleAppendNewPage(const U* values, size_t size) {
@@ -277,51 +277,51 @@ class PageProtectingVector final {
     unprotectUnusedPartial(currPage, nextPage);
     vector.infallibleAppend(values, size);
     protectUsedPartial(currPage, nextPage);
     currPage = nextPage;
     resetTest();
   }
 
   template <typename U>
-  MOZ_ALWAYS_INLINE MOZ_MUST_USE bool appendNewPage(const U* values,
-                                                    size_t size) {
+  [[nodiscard]] MOZ_ALWAYS_INLINE bool appendNewPage(const U* values,
+                                                     size_t size) {
     size_t nextPage = uintptr_t(begin() + length() + size) >> pageShift;
     MOZ_ASSERT(currPage < nextPage);
     unprotectUnusedPartial(currPage, nextPage);
     bool ret = vector.append(values, size);
     if (MOZ_LIKELY(ret)) {
       protectUsedPartial(currPage, nextPage);
       currPage = nextPage;
     } else {
       protectUnusedPartial(currPage, nextPage);
     }
     resetTest();
     return ret;
   }
 
   template <typename U>
-  MOZ_ALWAYS_INLINE MOZ_MUST_USE bool appendNewBuffer(const U* values,
-                                                      size_t size) {
+  [[nodiscard]] MOZ_ALWAYS_INLINE bool appendNewBuffer(const U* values,
+                                                       size_t size) {
     unprotectOldBuffer();
     bool ret = vector.append(values, size);
     protectNewBuffer();
     return ret;
   }
 
   MOZ_NEVER_INLINE void unprotectRegionSlow(uintptr_t l, uintptr_t r);
   MOZ_NEVER_INLINE void reprotectRegionSlow(uintptr_t l, uintptr_t r);
 
-  MOZ_NEVER_INLINE MOZ_MUST_USE bool reserveSlow(size_t size);
+  [[nodiscard]] MOZ_NEVER_INLINE bool reserveSlow(size_t size);
 
   template <typename U>
   MOZ_NEVER_INLINE void infallibleAppendSlow(const U* values, size_t size);
 
   template <typename U>
-  MOZ_NEVER_INLINE MOZ_MUST_USE bool appendSlow(const U* values, size_t size);
+  [[nodiscard]] MOZ_NEVER_INLINE bool appendSlow(const U* values, size_t size);
 
  public:
   explicit PageProtectingVector(AllocPolicy policy = AllocPolicy())
       : vector(std::move(policy)),
         elemsUntilTest(0),
         currPage(0),
         initPage(0),
         lastPage(0),
@@ -401,34 +401,34 @@ class PageProtectingVector final {
   MOZ_ALWAYS_INLINE const T* begin() const { return vector.begin(); }
 
   void clear() {
     unprotectOldBuffer();
     vector.clear();
     protectNewBuffer();
   }
 
-  MOZ_ALWAYS_INLINE MOZ_MUST_USE bool reserve(size_t size) {
+  [[nodiscard]] MOZ_ALWAYS_INLINE bool reserve(size_t size) {
     if (MOZ_LIKELY(size <= capacity())) {
       return vector.reserve(size);
     }
     return reserveSlow(size);
   }
 
   template <typename U>
   MOZ_ALWAYS_INLINE void infallibleAppend(const U* values, size_t size) {
     elemsUntilTest -= size;
     if (MOZ_LIKELY(elemsUntilTest >= 0)) {
       return vector.infallibleAppend(values, size);
     }
     infallibleAppendSlow(values, size);
   }
 
   template <typename U>
-  MOZ_ALWAYS_INLINE MOZ_MUST_USE bool append(const U* values, size_t size) {
+  [[nodiscard]] MOZ_ALWAYS_INLINE bool append(const U* values, size_t size) {
     elemsUntilTest -= size;
     if (MOZ_LIKELY(elemsUntilTest >= 0)) {
       return vector.append(values, size);
     }
     return appendSlow(values, size);
   }
 };
 
@@ -461,17 +461,17 @@ PageProtectingVector<T, A, B, C, D, E, F
   }
   T* addr = reinterpret_cast<T*>(l << pageShift);
   size_t size = (r - l + 1) << pageShift;
   gc::MakePagesReadOnly(addr, size);
 }
 
 template <typename T, size_t A, class B, bool C, bool D, size_t E, bool F,
           uint8_t G>
-MOZ_NEVER_INLINE MOZ_MUST_USE bool
+[[nodiscard]] MOZ_NEVER_INLINE bool
 PageProtectingVector<T, A, B, C, D, E, F, G>::reserveSlow(size_t size) {
   return reserveNewBuffer(size);
 }
 
 template <typename T, size_t A, class B, bool C, bool D, size_t E, bool F,
           uint8_t G>
 template <typename U>
 MOZ_NEVER_INLINE void
@@ -483,17 +483,17 @@ PageProtectingVector<T, A, B, C, D, E, F
       MOZ_LIKELY(length() + size <= capacity()),
       "About to overflow our AssemblerBuffer using infallibleAppend!");
   infallibleAppendNewPage(values, size);
 }
 
 template <typename T, size_t A, class B, bool C, bool D, size_t E, bool F,
           uint8_t G>
 template <typename U>
-MOZ_NEVER_INLINE MOZ_MUST_USE bool
+[[nodiscard]] MOZ_NEVER_INLINE bool
 PageProtectingVector<T, A, B, C, D, E, F, G>::appendSlow(const U* values,
                                                          size_t size) {
   if (MOZ_LIKELY(length() + size <= capacity())) {
     return appendNewPage(values, size);
   }
   return appendNewBuffer(values, size);
 }
 
--- a/js/src/frontend/BytecodeCompilation.h
+++ b/js/src/frontend/BytecodeCompilation.h
@@ -94,21 +94,21 @@ extern JSScript* CompileEvalScript(JSCon
                                    const JS::ReadOnlyCompileOptions& options,
                                    JS::SourceText<char16_t>& srcBuf,
                                    JS::Handle<js::Scope*> enclosingScope,
                                    JS::Handle<JSObject*> enclosingEnv);
 
 extern void FillCompileOptionsForLazyFunction(JS::CompileOptions& options,
                                               Handle<BaseScript*> lazy);
 
-extern MOZ_MUST_USE bool CompileLazyFunctionToStencil(
+[[nodiscard]] extern bool CompileLazyFunctionToStencil(
     JSContext* cx, CompilationStencil& stencil, JS::Handle<BaseScript*> lazy,
     const char16_t* units, size_t length);
 
-extern MOZ_MUST_USE bool CompileLazyFunctionToStencil(
+[[nodiscard]] extern bool CompileLazyFunctionToStencil(
     JSContext* cx, CompilationStencil& stencil, JS::Handle<BaseScript*> lazy,
     const mozilla::Utf8Unit* units, size_t length);
 
 extern bool InstantiateStencilsForDelazify(JSContext* cx,
                                            CompilationStencil& stencil);
 
 // Certain compile options will disable the syntax parser entirely.
 inline bool CanLazilyParse(const JS::ReadOnlyCompileOptions& options) {
--- a/js/src/frontend/BytecodeEmitter.h
+++ b/js/src/frontend/BytecodeEmitter.h
@@ -253,18 +253,18 @@ struct MOZ_STACK_CLASS BytecodeEmitter {
   }
 
   AbstractScopePtr outermostScope() const {
     return perScriptData().gcThingList().firstScope();
   }
   AbstractScopePtr innermostScope() const;
   ScopeIndex innermostScopeIndex() const;
 
-  MOZ_ALWAYS_INLINE MOZ_MUST_USE bool makeAtomIndex(TaggedParserAtomIndex atom,
-                                                    GCThingIndex* indexp) {
+  [[nodiscard]] MOZ_ALWAYS_INLINE bool makeAtomIndex(TaggedParserAtomIndex atom,
+                                                     GCThingIndex* indexp) {
     MOZ_ASSERT(perScriptData().atomIndices());
     AtomIndexMap::AddPtr p = perScriptData().atomIndices()->lookupForAdd(atom);
     if (p) {
       *indexp = GCThingIndex(p->value());
       return true;
     }
 
     GCThingIndex index;
@@ -620,24 +620,24 @@ struct MOZ_STACK_CLASS BytecodeEmitter {
       JSOp op, ShouldInstrument shouldInstrument = ShouldInstrument::No);
   [[nodiscard]] bool emitElemOp(PropertyByValue* elem, JSOp op);
   [[nodiscard]] bool emitElemIncDec(UnaryNode* incDec);
 
   [[nodiscard]] bool emitCatch(BinaryNode* catchClause);
   [[nodiscard]] bool emitIf(TernaryNode* ifNode);
   [[nodiscard]] bool emitWith(BinaryNode* withNode);
 
-  MOZ_NEVER_INLINE MOZ_MUST_USE bool emitLabeledStatement(
+  [[nodiscard]] MOZ_NEVER_INLINE bool emitLabeledStatement(
       const LabeledStatement* labeledStmt);
-  MOZ_NEVER_INLINE MOZ_MUST_USE bool emitLexicalScope(
+  [[nodiscard]] MOZ_NEVER_INLINE bool emitLexicalScope(
       LexicalScopeNode* lexicalScope);
   [[nodiscard]] bool emitLexicalScopeBody(
       ParseNode* body, EmitLineNumberNote emitLineNote = EMIT_LINENOTE);
-  MOZ_NEVER_INLINE MOZ_MUST_USE bool emitSwitch(SwitchStatement* switchStmt);
-  MOZ_NEVER_INLINE MOZ_MUST_USE bool emitTry(TryNode* tryNode);
+  [[nodiscard]] MOZ_NEVER_INLINE bool emitSwitch(SwitchStatement* switchStmt);
+  [[nodiscard]] MOZ_NEVER_INLINE bool emitTry(TryNode* tryNode);
 
   [[nodiscard]] bool emitGoSub(JumpList* jump);
 
   // emitDestructuringLHSRef emits the lhs expression's reference.
   // If the lhs expression is object property |OBJ.prop|, it emits |OBJ|.
   // If it's object element |OBJ[ELEM]|, it emits |OBJ| and |ELEM|.
   // If there's nothing to evaluate for the reference, it emits nothing.
   // |emitted| parameter receives the number of values pushed onto the stack.
@@ -763,17 +763,17 @@ struct MOZ_STACK_CLASS BytecodeEmitter {
 
   [[nodiscard]] bool emitUnary(UnaryNode* unaryNode);
   [[nodiscard]] bool emitRightAssociative(ListNode* node);
   [[nodiscard]] bool emitLeftAssociative(ListNode* node);
   [[nodiscard]] bool emitShortCircuit(ListNode* node);
   [[nodiscard]] bool emitSequenceExpr(
       ListNode* node, ValueUsage valueUsage = ValueUsage::WantValue);
 
-  MOZ_NEVER_INLINE MOZ_MUST_USE bool emitIncOrDec(UnaryNode* incDec);
+  [[nodiscard]] MOZ_NEVER_INLINE bool emitIncOrDec(UnaryNode* incDec);
 
   [[nodiscard]] bool emitConditionalExpression(
       ConditionalExpression& conditional,
       ValueUsage valueUsage = ValueUsage::WantValue);
 
   bool isOptimizableSpreadArgument(ParseNode* expr);
 
   [[nodiscard]] ParseNode* getCoordNode(ParseNode* callNode,
--- a/js/src/frontend/CompilationStencil.h
+++ b/js/src/frontend/CompilationStencil.h
@@ -568,25 +568,25 @@ struct CompilationStencil : public BaseC
   bool preparationIsPerformed = false;
 
   // End of fields.
 
   // Construct a CompilationStencil
   CompilationStencil(JSContext* cx, const JS::ReadOnlyCompileOptions& options)
       : alloc(LifoAllocChunkSize), input(options) {}
 
-  static MOZ_MUST_USE bool instantiateBaseStencilAfterPreparation(
+  [[nodiscard]] static bool instantiateBaseStencilAfterPreparation(
       JSContext* cx, CompilationInput& input,
       const BaseCompilationStencil& stencil, CompilationGCOutput& gcOutput);
 
-  static MOZ_MUST_USE bool prepareForInstantiate(
+  [[nodiscard]] static bool prepareForInstantiate(
       JSContext* cx, CompilationStencil& stencil, CompilationGCOutput& gcOutput,
       CompilationGCOutput* gcOutputForDelazification = nullptr);
 
-  static MOZ_MUST_USE bool instantiateStencils(
+  [[nodiscard]] static bool instantiateStencils(
       JSContext* cx, CompilationStencil& stencil, CompilationGCOutput& gcOutput,
       CompilationGCOutput* gcOutputForDelazification = nullptr);
 
   [[nodiscard]] bool serializeStencils(JSContext* cx, JS::TranscodeBuffer& buf,
                                        bool* succeededOut = nullptr);
   [[nodiscard]] bool deserializeStencils(JSContext* cx,
                                          const JS::TranscodeRange& range,
                                          bool* succeededOut = nullptr);
--- a/js/src/frontend/ErrorReporter.h
+++ b/js/src/frontend/ErrorReporter.h
@@ -53,18 +53,18 @@ class ErrorReportMixin : public StrictMo
   struct Current {};
   struct NoOffset {};
   using ErrorOffset = mozilla::Variant<uint32_t, Current, NoOffset>;
 
   // Fills ErrorMetadata fields for an error or warning at given offset.
   //   * offset is uint32_t if methods ending with "At" is called
   //   * offset is NoOffset if methods ending with "NoOffset" is called
   //   * offset is Current otherwise
-  virtual MOZ_MUST_USE bool computeErrorMetadata(ErrorMetadata* err,
-                                                 const ErrorOffset& offset) = 0;
+  [[nodiscard]] virtual bool computeErrorMetadata(
+      ErrorMetadata* err, const ErrorOffset& offset) = 0;
 
   // ==== error ====
   //
   // Reports an error.
   //
   // Methods ending with "At" are for an error at given offset.
   // The offset is passed to computeErrorMetadata method and is transparent
   // for this class.
--- a/js/src/frontend/FoldConstants.cpp
+++ b/js/src/frontend/FoldConstants.cpp
@@ -39,17 +39,17 @@ struct FoldInfo {
   JSContext* cx;
   ParserAtomsTable& parserAtoms;
   FullParseHandler* handler;
 };
 
 // Don't use ReplaceNode directly, because we want the constant folder to keep
 // the attributes isInParens and isDirectRHSAnonFunction of the old node being
 // replaced.
-inline MOZ_MUST_USE bool TryReplaceNode(ParseNode** pnp, ParseNode* pn) {
+[[nodiscard]] inline bool TryReplaceNode(ParseNode** pnp, ParseNode* pn) {
   // convenience check: can call TryReplaceNode(pnp, alloc_parsenode())
   // directly, without having to worry about alloc returning null.
   if (!pn) {
     return false;
   }
   pn->setInParens((*pnp)->isInParens());
   pn->setDirectRHSAnonFunction((*pnp)->isDirectRHSAnonFunction());
   ReplaceNode(pnp, pn);
--- a/js/src/frontend/FoldConstants.h
+++ b/js/src/frontend/FoldConstants.h
@@ -27,24 +27,24 @@ class ParserAtomsTable;
 // Usage:
 //    pn = parser->statement();
 //    if (!pn) {
 //        return false;
 //    }
 //    if (!FoldConstants(cx, parserAtoms, &pn, parser)) {
 //        return false;
 //    }
-extern MOZ_MUST_USE bool FoldConstants(JSContext* cx,
-                                       ParserAtomsTable& parserAtoms,
-                                       ParseNode** pnp,
-                                       FullParseHandler* handler);
+[[nodiscard]] extern bool FoldConstants(JSContext* cx,
+                                        ParserAtomsTable& parserAtoms,
+                                        ParseNode** pnp,
+                                        FullParseHandler* handler);
 
-inline MOZ_MUST_USE bool FoldConstants(JSContext* cx,
-                                       ParserAtomsTable& parserAtoms,
-                                       typename SyntaxParseHandler::Node* pnp,
-                                       SyntaxParseHandler* handler) {
+[[nodiscard]] inline bool FoldConstants(JSContext* cx,
+                                        ParserAtomsTable& parserAtoms,
+                                        typename SyntaxParseHandler::Node* pnp,
+                                        SyntaxParseHandler* handler) {
   return true;
 }
 
 } /* namespace frontend */
 } /* namespace js */
 
 #endif /* frontend_FoldConstants_h */
--- a/js/src/frontend/FullParseHandler.h
+++ b/js/src/frontend/FullParseHandler.h
@@ -843,17 +843,17 @@ class FullParseHandler {
     }
     if (!catchClause) {
       return false;
     }
     lexicalScope->setScopeBody(catchClause);
     return true;
   }
 
-  inline MOZ_MUST_USE bool setLastFunctionFormalParameterDefault(
+  [[nodiscard]] inline bool setLastFunctionFormalParameterDefault(
       FunctionNodeType funNode, Node defaultValue);
 
   void checkAndSetIsDirectRHSAnonFunction(Node pn) {
     if (IsAnonymousFunctionDefinition(pn)) {
       pn->setDirectRHSAnonFunction(true);
     }
   }
 
--- a/js/src/frontend/NameCollections.h
+++ b/js/src/frontend/NameCollections.h
@@ -175,19 +175,19 @@ using RecyclableNameMapBase =
 
 // Define wrapper methods to accept TaggedParserAtomIndex.
 template <typename MapValue>
 class RecyclableNameMap : public RecyclableNameMapBase<MapValue> {
   using Base = RecyclableNameMapBase<MapValue>;
 
  public:
   template <typename... Args>
-  MOZ_ALWAYS_INLINE MOZ_MUST_USE bool add(typename Base::AddPtr& p,
-                                          const TaggedParserAtomIndex& key,
-                                          Args&&... args) {
+  [[nodiscard]] MOZ_ALWAYS_INLINE bool add(typename Base::AddPtr& p,
+                                           const TaggedParserAtomIndex& key,
+                                           Args&&... args) {
     return Base::add(p, TrivialTaggedParserAtomIndex::from(key),
                      std::forward<Args>(args)...);
   }
 
   MOZ_ALWAYS_INLINE
   typename Base::Ptr lookup(const TaggedParserAtomIndex& l) {
     return Base::lookup(TrivialTaggedParserAtomIndex::from(l));
   }
--- a/js/src/frontend/ParseNodeVerify.h
+++ b/js/src/frontend/ParseNodeVerify.h
@@ -17,26 +17,26 @@ namespace frontend {
 // In most builds, examine the given ParseNode and crash if it's not
 // well-formed. (In late beta and shipping builds of Firefox, this does
 // nothing.)
 //
 // This returns true on success, and false only if we hit the recursion limit.
 // If the ParseNode is actually bad, we crash.
 
 #ifdef DEBUG
-extern MOZ_MUST_USE bool CheckParseTree(JSContext* cx, const LifoAlloc& alloc,
-                                        ParseNode* pn);
+[[nodiscard]] extern bool CheckParseTree(JSContext* cx, const LifoAlloc& alloc,
+                                         ParseNode* pn);
 #else
-inline MOZ_MUST_USE bool CheckParseTree(JSContext* cx, const LifoAlloc& alloc,
-                                        ParseNode* pn) {
+[[nodiscard]] inline bool CheckParseTree(JSContext* cx, const LifoAlloc& alloc,
+                                         ParseNode* pn) {
   return true;
 }
 #endif
 
-inline MOZ_MUST_USE bool CheckParseTree(JSContext* cx, const LifoAlloc& alloc,
-                                        SyntaxParseHandler::Node pn) {
+[[nodiscard]] inline bool CheckParseTree(JSContext* cx, const LifoAlloc& alloc,
+                                         SyntaxParseHandler::Node pn) {
   return true;
 }
 
 } /* namespace frontend */
 } /* namespace js */
 
 #endif  // frontend_ParseNodeVerify_h
--- a/js/src/frontend/TokenKind.h
+++ b/js/src/frontend/TokenKind.h
@@ -272,54 +272,54 @@ inline bool TokenKindIsRelational(TokenK
 inline bool TokenKindIsShift(TokenKind tt) {
   return TokenKind::ShiftOpStart <= tt && tt <= TokenKind::ShiftOpLast;
 }
 
 inline bool TokenKindIsAssignment(TokenKind tt) {
   return TokenKind::AssignmentStart <= tt && tt <= TokenKind::AssignmentLast;
 }
 
-inline MOZ_MUST_USE bool TokenKindIsKeyword(TokenKind tt) {
+[[nodiscard]] inline bool TokenKindIsKeyword(TokenKind tt) {
   return (TokenKind::KeywordFirst <= tt && tt <= TokenKind::KeywordLast) ||
          (TokenKind::KeywordBinOpFirst <= tt &&
           tt <= TokenKind::KeywordBinOpLast) ||
          (TokenKind::KeywordUnOpFirst <= tt &&
           tt <= TokenKind::KeywordUnOpLast);
 }
 
-inline MOZ_MUST_USE bool TokenKindIsContextualKeyword(TokenKind tt) {
+[[nodiscard]] inline bool TokenKindIsContextualKeyword(TokenKind tt) {
   return TokenKind::ContextualKeywordFirst <= tt &&
          tt <= TokenKind::ContextualKeywordLast;
 }
 
-inline MOZ_MUST_USE bool TokenKindIsFutureReservedWord(TokenKind tt) {
+[[nodiscard]] inline bool TokenKindIsFutureReservedWord(TokenKind tt) {
   return TokenKind::FutureReservedKeywordFirst <= tt &&
          tt <= TokenKind::FutureReservedKeywordLast;
 }
 
-inline MOZ_MUST_USE bool TokenKindIsStrictReservedWord(TokenKind tt) {
+[[nodiscard]] inline bool TokenKindIsStrictReservedWord(TokenKind tt) {
   return TokenKind::StrictReservedKeywordFirst <= tt &&
          tt <= TokenKind::StrictReservedKeywordLast;
 }
 
-inline MOZ_MUST_USE bool TokenKindIsReservedWordLiteral(TokenKind tt) {
+[[nodiscard]] inline bool TokenKindIsReservedWordLiteral(TokenKind tt) {
   return TokenKind::ReservedWordLiteralFirst <= tt &&
          tt <= TokenKind::ReservedWordLiteralLast;
 }
 
-inline MOZ_MUST_USE bool TokenKindIsReservedWord(TokenKind tt) {
+[[nodiscard]] inline bool TokenKindIsReservedWord(TokenKind tt) {
   return TokenKindIsKeyword(tt) || TokenKindIsFutureReservedWord(tt) ||
          TokenKindIsReservedWordLiteral(tt);
 }
 
-inline MOZ_MUST_USE bool TokenKindIsPossibleIdentifier(TokenKind tt) {
+[[nodiscard]] inline bool TokenKindIsPossibleIdentifier(TokenKind tt) {
   return tt == TokenKind::Name || TokenKindIsContextualKeyword(tt) ||
          TokenKindIsStrictReservedWord(tt);
 }
 
-inline MOZ_MUST_USE bool TokenKindIsPossibleIdentifierName(TokenKind tt) {
+[[nodiscard]] inline bool TokenKindIsPossibleIdentifierName(TokenKind tt) {
   return TokenKindIsPossibleIdentifier(tt) || TokenKindIsReservedWord(tt);
 }
 
 }  // namespace frontend
 }  // namespace js
 
 #endif /* frontend_TokenKind_h */
--- a/js/src/frontend/TokenStream.h
+++ b/js/src/frontend/TokenStream.h
@@ -1521,32 +1521,32 @@ inline void SourceUnits<mozilla::Utf8Uni
  *     |CharBuffer| to a |char16_t*|, is simpler if it doesn't have to convert.
  */
 using CharBuffer = Vector<char16_t, 32>;
 
 /**
  * Append the provided code point (in the range [U+0000, U+10FFFF], surrogate
  * code points included) to the buffer.
  */
-extern MOZ_MUST_USE bool AppendCodePointToCharBuffer(CharBuffer& charBuffer,
-                                                     uint32_t codePoint);
+[[nodiscard]] extern bool AppendCodePointToCharBuffer(CharBuffer& charBuffer,
+                                                      uint32_t codePoint);
 
 /**
  * Accumulate the range of UTF-16 text (lone surrogates permitted, because JS
  * allows them in source text) into |charBuffer|.  Normalize '\r', '\n', and
  * "\r\n" into '\n'.
  */
-extern MOZ_MUST_USE bool FillCharBufferFromSourceNormalizingAsciiLineBreaks(
+[[nodiscard]] extern bool FillCharBufferFromSourceNormalizingAsciiLineBreaks(
     CharBuffer& charBuffer, const char16_t* cur, const char16_t* end);
 
 /**
  * Accumulate the range of previously-validated UTF-8 text into |charBuffer|.
  * Normalize '\r', '\n', and "\r\n" into '\n'.
  */
-extern MOZ_MUST_USE bool FillCharBufferFromSourceNormalizingAsciiLineBreaks(
+[[nodiscard]] extern bool FillCharBufferFromSourceNormalizingAsciiLineBreaks(
     CharBuffer& charBuffer, const mozilla::Utf8Unit* cur,
     const mozilla::Utf8Unit* end);
 
 class TokenStreamCharsShared {
  protected:
   JSContext* cx;
 
   /**
@@ -1566,17 +1566,17 @@ class TokenStreamCharsShared {
   [[nodiscard]] bool copyCharBufferTo(
       JSContext* cx, UniquePtr<char16_t[], JS::FreePolicy>* destination);
 
   /**
    * Determine whether a code unit constitutes a complete ASCII code point.
    * (The code point's exact value might not be used, however, if subsequent
    * code observes that |unit| is part of a LineTerminatorSequence.)
    */
-  static constexpr MOZ_ALWAYS_INLINE MOZ_MUST_USE bool isAsciiCodePoint(
+  [[nodiscard]] static constexpr MOZ_ALWAYS_INLINE bool isAsciiCodePoint(
       int32_t unit) {
     return mozilla::IsAscii(static_cast<char32_t>(unit));
   }
 
   TaggedParserAtomIndex drainCharBufferIntoAtom() {
     // Add to parser atoms table.
     auto atom = this->parserAtoms->internChar16(cx, charBuffer.begin(),
                                                 charBuffer.length());
@@ -2713,17 +2713,17 @@ class MOZ_STACK_CLASS TokenStreamSpecifi
   }
 
   // This is like peekToken(), with one exception:  if there is an EOL
   // between the end of the current token and the start of the next token, it
   // return true and store Eol in |*ttp|.  In that case, no token with
   // Eol is actually created, just a Eol TokenKind is returned, and
   // currentToken() shouldn't be consulted.  (This is the only place Eol
   // is produced.)
-  MOZ_ALWAYS_INLINE MOZ_MUST_USE bool peekTokenSameLine(
+  [[nodiscard]] MOZ_ALWAYS_INLINE bool peekTokenSameLine(
       TokenKind* ttp, Modifier modifier = SlashIsDiv) {
     TokenStreamAnyChars& anyChars = anyCharsAccess();
     const Token& curr = anyChars.currentToken();
 
     // If lookahead != 0, we have scanned ahead at least one token, and
     // |lineno| is the line that the furthest-scanned token ends on.  If
     // it's the same as the line that the current token ends on, that's a
     // stronger condition than what we are looking for, and we don't need
--- a/js/src/gc/Nursery.h
+++ b/js/src/gc/Nursery.h
@@ -301,17 +301,17 @@ class Nursery {
   static const size_t MaxNurseryBufferSize = 1024;
 
   // Do a minor collection.
   void collect(JSGCInvocationKind kind, JS::GCReason reason);
 
   // If the thing at |*ref| in the Nursery has been forwarded, set |*ref| to
   // the new location and return true. Otherwise return false and leave
   // |*ref| unset.
-  MOZ_ALWAYS_INLINE MOZ_MUST_USE static bool getForwardedPointer(
+  [[nodiscard]] MOZ_ALWAYS_INLINE static bool getForwardedPointer(
       js::gc::Cell** ref);
 
   // Forward a slots/elements pointer stored in an Ion frame.
   void forwardBufferPointer(uintptr_t* pSlotsElems);
 
   inline void maybeSetForwardingPointer(JSTracer* trc, void* oldData,
                                         void* newData, bool direct);
   inline void setForwardingPointerWhileTenuring(void* oldData, void* newData,
--- a/js/src/gc/Statistics.h
+++ b/js/src/gc/Statistics.h
@@ -145,17 +145,17 @@ struct Statistics {
   using TimeDuration = mozilla::TimeDuration;
   using TimeStamp = mozilla::TimeStamp;
 
   // Create types for tables of times, by phase and phase kind.
   using PhaseTimes = EnumeratedArray<Phase, Phase::LIMIT, TimeDuration>;
   using PhaseKindTimes =
       EnumeratedArray<PhaseKind, PhaseKind::LIMIT, TimeDuration>;
 
-  static MOZ_MUST_USE bool initialize();
+  [[nodiscard]] static bool initialize();
 
   explicit Statistics(gc::GCRuntime* gc);
   ~Statistics();
 
   Statistics(const Statistics&) = delete;
   Statistics& operator=(const Statistics&) = delete;
 
   void beginPhase(PhaseKind phaseKind);
--- a/js/src/gc/WeakMap.h
+++ b/js/src/gc/WeakMap.h
@@ -113,17 +113,17 @@ class WeakMapBase : public mozilla::Link
   // Check all weak maps in a zone that have been marked as live in this garbage
   // collection, and mark the values of all entries that have become strong
   // references to them. Return true if we marked any new values, indicating
   // that we need to make another pass. In other words, mark my marked maps'
   // marked members' mid-collection.
   static bool markZoneIteratively(JS::Zone* zone, GCMarker* marker);
 
   // Add zone edges for weakmaps with key delegates in a different zone.
-  static MOZ_MUST_USE bool findSweepGroupEdgesForZone(JS::Zone* zone);
+  [[nodiscard]] static bool findSweepGroupEdgesForZone(JS::Zone* zone);
 
   // Sweep the weak maps in a zone, removing dead weak maps and removing
   // entries of live weak maps whose keys are dead.
   static void sweepZone(JS::Zone* zone);
 
   // Sweep the marked weak maps in a zone, updating moved keys.
   static void sweepZoneAfterMinorGC(JS::Zone* zone);
 
--- a/js/src/irregexp/RegExpAPI.cpp
+++ b/js/src/irregexp/RegExpAPI.cpp
@@ -447,22 +447,20 @@ class RegExpDepthCheck final : public v8
 };
 
 enum class AssembleResult {
   Success,
   TooLarge,
   OutOfMemory,
 };
 
-static MOZ_MUST_USE AssembleResult Assemble(JSContext* cx,
-                                            RegExpCompiler* compiler,
-                                            RegExpCompileData* data,
-                                            MutableHandleRegExpShared re,
-                                            HandleAtom pattern, Zone* zone,
-                                            bool useNativeCode, bool isLatin1) {
+[[nodiscard]] static AssembleResult Assemble(
+    JSContext* cx, RegExpCompiler* compiler, RegExpCompileData* data,
+    MutableHandleRegExpShared re, HandleAtom pattern, Zone* zone,
+    bool useNativeCode, bool isLatin1) {
   // Because we create a StackMacroAssembler, this function is not allowed
   // to GC. If needed, we allocate and throw errors in the caller.
   Maybe<jit::JitContext> jctx;
   Maybe<js::jit::StackMacroAssembler> stack_masm;
   UniquePtr<RegExpMacroAssembler> masm;
   if (useNativeCode) {
     NativeRegExpMacroAssembler::Mode mode =
         isLatin1 ? NativeRegExpMacroAssembler::LATIN1
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -3974,21 +3974,21 @@ JS_PUBLIC_API JSObject* JS::CallOriginal
   cx->check(promiseObj, onFulfilled, onRejected);
 
   MOZ_ASSERT_IF(onFulfilled, IsCallable(onFulfilled));
   MOZ_ASSERT_IF(onRejected, IsCallable(onRejected));
 
   return OriginalPromiseThen(cx, promiseObj, onFulfilled, onRejected);
 }
 
-static MOZ_MUST_USE bool ReactToPromise(JSContext* cx,
-                                        JS::Handle<JSObject*> promiseObj,
-                                        JS::Handle<JSObject*> onFulfilled,
-                                        JS::Handle<JSObject*> onRejected,
-                                        UnhandledRejectionBehavior behavior) {
+[[nodiscard]] static bool ReactToPromise(JSContext* cx,
+                                         JS::Handle<JSObject*> promiseObj,
+                                         JS::Handle<JSObject*> onFulfilled,
+                                         JS::Handle<JSObject*> onRejected,
+                                         UnhandledRejectionBehavior behavior) {
   AssertHeapIsIdle();
   CHECK_THREAD(cx);
   cx->check(promiseObj, onFulfilled, onRejected);
 
   MOZ_ASSERT_IF(onFulfilled, IsCallable(onFulfilled));
   MOZ_ASSERT_IF(onRejected, IsCallable(onRejected));
 
   Rooted<PromiseObject*> unwrappedPromise(cx);
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -2036,22 +2036,22 @@ extern JS_PUBLIC_API JSString* JS_Atomiz
                                                          size_t length);
 
 extern JS_PUBLIC_API JSString* JS_AtomizeAndPinUCString(JSContext* cx,
                                                         const char16_t* s);
 
 extern JS_PUBLIC_API bool JS_CompareStrings(JSContext* cx, JSString* str1,
                                             JSString* str2, int32_t* result);
 
-extern JS_PUBLIC_API MOZ_MUST_USE bool JS_StringEqualsAscii(
+[[nodiscard]] extern JS_PUBLIC_API bool JS_StringEqualsAscii(
     JSContext* cx, JSString* str, const char* asciiBytes, bool* match);
 
 // Same as above, but when the length of asciiBytes (excluding the
 // trailing null, if any) is known.
-extern JS_PUBLIC_API MOZ_MUST_USE bool JS_StringEqualsAscii(
+[[nodiscard]] extern JS_PUBLIC_API bool JS_StringEqualsAscii(
     JSContext* cx, JSString* str, const char* asciiBytes, size_t length,
     bool* match);
 
 template <size_t N>
 [[nodiscard]] bool JS_StringEqualsLiteral(JSContext* cx, JSString* str,
                                           const char (&asciiBytes)[N],
                                           bool* match) {
   MOZ_ASSERT(asciiBytes[N - 1] == '\0');
@@ -2793,17 +2793,17 @@ extern JS_PUBLIC_API StackFormat GetStac
 namespace JS {
 
 /**
  * Attempt to disable Wasm's usage of reserving a large virtual memory
  * allocation to avoid bounds checking overhead. This must be called before any
  * Wasm module or memory is created in this process, or else this function will
  * fail.
  */
-extern JS_PUBLIC_API MOZ_MUST_USE bool DisableWasmHugeMemory();
+[[nodiscard]] extern JS_PUBLIC_API bool DisableWasmHugeMemory();
 
 /**
  * If a large allocation fails when calling pod_{calloc,realloc}CanGC, the JS
  * engine may call the large-allocation-failure callback, if set, to allow the
  * embedding to flush caches, possibly perform shrinking GCs, etc. to make some
  * room. The allocation will then be retried (and may still fail.) This callback
  * can be called on any thread and must be set at most once in a process.
  */
--- a/js/src/jsnum.h
+++ b/js/src/jsnum.h
@@ -19,17 +19,17 @@
 
 #include "vm/StringType.h"
 
 namespace js {
 
 class GlobalObject;
 class StringBuffer;
 
-extern MOZ_MUST_USE bool InitRuntimeNumberState(JSRuntime* rt);
+[[nodiscard]] extern bool InitRuntimeNumberState(JSRuntime* rt);
 
 // This is a no-op if built with JS_HAS_INTL_API.
 extern void FinishRuntimeNumberState(JSRuntime* rt);
 
 /* Initialize the Number class, returning its prototype object. */
 extern JSObject* InitNumberClass(JSContext* cx, Handle<GlobalObject*> global);
 
 /*
@@ -61,17 +61,17 @@ frontend::TaggedParserAtomIndex Int32ToP
 extern bool IsInteger(const Value& val);
 
 extern bool IsInteger(double d);
 
 /*
  * Convert an integer or double (contained in the given value) to a string and
  * append to the given buffer.
  */
-extern MOZ_MUST_USE bool JS_FASTCALL
+[[nodiscard]] extern bool JS_FASTCALL
 NumberValueToStringBuffer(JSContext* cx, const Value& v, StringBuffer& sb);
 
 extern JSLinearString* IndexToString(JSContext* cx, uint32_t index);
 
 /*
  * Usually a small amount of static storage is enough, but sometimes we need
  * to dynamically allocate much more.  This struct encapsulates that.
  * Dynamically allocated memory will be freed when the object is destroyed.
@@ -129,17 +129,17 @@ enum class IntegerSeparatorHandling : bo
  * part of integer string. If the option is enabled, all '_' characters in the
  * string are ignored. Underscore characters must not appear directly next to
  * each other, e.g. '1__2' will lead to an assertion.
  *
  * If [start, end) does not begin with a number with the specified base,
  * *dp == 0 and *endp == start upon return.
  */
 template <typename CharT>
-extern MOZ_MUST_USE bool GetPrefixInteger(
+[[nodiscard]] extern bool GetPrefixInteger(
     JSContext* cx, const CharT* start, const CharT* end, int base,
     IntegerSeparatorHandling separatorHandling, const CharT** endp, double* dp);
 
 inline const char16_t* ToRawChars(const char16_t* units) { return units; }
 
 inline const unsigned char* ToRawChars(const unsigned char* units) {
   return units;
 }
@@ -148,17 +148,17 @@ inline const unsigned char* ToRawChars(c
   return mozilla::Utf8AsUnsignedChars(units);
 }
 
 /**
  * Like GetPrefixInteger, but [start, end) must all be digits in the given
  * base (and so this function doesn't take a useless outparam).
  */
 template <typename CharT>
-extern MOZ_MUST_USE bool GetFullInteger(
+[[nodiscard]] extern bool GetFullInteger(
     JSContext* cx, const CharT* start, const CharT* end, int base,
     IntegerSeparatorHandling separatorHandling, double* dp) {
   decltype(ToRawChars(start)) realEnd;
   if (GetPrefixInteger(cx, ToRawChars(start), ToRawChars(end), base,
                        separatorHandling, &realEnd, dp)) {
     MOZ_ASSERT(end == static_cast<const void*>(realEnd));
     return true;
   }
@@ -167,49 +167,50 @@ extern MOZ_MUST_USE bool GetFullInteger(
 
 /*
  * This is like GetPrefixInteger, but only deals with base 10, always ignores
  * '_', and doesn't have an |endp| outparam. It should only be used when the
  * characters are known to match |DecimalIntegerLiteral|, cf. ES2020, 11.8.3
  * Numeric Literals.
  */
 template <typename CharT>
-extern MOZ_MUST_USE bool GetDecimalInteger(JSContext* cx, const CharT* start,
-                                           const CharT* end, double* dp);
+[[nodiscard]] extern bool GetDecimalInteger(JSContext* cx, const CharT* start,
+                                            const CharT* end, double* dp);
 
 /*
  * This is like GetDecimalInteger, but also allows non-integer numbers. It
  * should only be used when the characters are known to match |DecimalLiteral|,
  * cf. ES2020, 11.8.3 Numeric Literals.
  */
 template <typename CharT>
-extern MOZ_MUST_USE bool GetDecimalNonInteger(JSContext* cx, const CharT* start,
-                                              const CharT* end, double* dp);
+[[nodiscard]] extern bool GetDecimalNonInteger(JSContext* cx,
+                                               const CharT* start,
+                                               const CharT* end, double* dp);
 
 template <typename CharT>
 bool CharsToNumber(JSContext* cx, const CharT* chars, size_t length,
                    double* result);
 
-extern MOZ_MUST_USE bool StringToNumber(JSContext* cx, JSString* str,
-                                        double* result);
+[[nodiscard]] extern bool StringToNumber(JSContext* cx, JSString* str,
+                                         double* result);
 
-extern MOZ_MUST_USE bool StringToNumberPure(JSContext* cx, JSString* str,
-                                            double* result);
+[[nodiscard]] extern bool StringToNumberPure(JSContext* cx, JSString* str,
+                                             double* result);
 
 /*
  * Return true and set |*result| to the parsed number value if |str| can be
  * parsed as a number using the same rules as in |StringToNumber|. Otherwise
  * return false and leave |*result| in an indeterminate state.
  */
-extern MOZ_MUST_USE bool MaybeStringToNumber(JSLinearString* str,
-                                             double* result);
+[[nodiscard]] extern bool MaybeStringToNumber(JSLinearString* str,
+                                              double* result);
 
 /* ES5 9.3 ToNumber, overwriting *vp with the appropriate number value. */
-MOZ_ALWAYS_INLINE MOZ_MUST_USE bool ToNumber(JSContext* cx,
-                                             JS::MutableHandleValue vp) {
+[[nodiscard]] MOZ_ALWAYS_INLINE bool ToNumber(JSContext* cx,
+                                              JS::MutableHandleValue vp) {
   if (vp.isNumber()) {
     return true;
   }
   double d;
   extern JS_PUBLIC_API bool ToNumberSlow(JSContext * cx, HandleValue v,
                                          double* dp);
   if (!ToNumberSlow(cx, vp, &d)) {
     return false;
@@ -217,28 +218,28 @@ MOZ_ALWAYS_INLINE MOZ_MUST_USE bool ToNu
 
   vp.setNumber(d);
   return true;
 }
 
 bool ToNumericSlow(JSContext* cx, JS::MutableHandleValue vp);
 
 // BigInt proposal section 3.1.6
-MOZ_ALWAYS_INLINE MOZ_MUST_USE bool ToNumeric(JSContext* cx,
-                                              JS::MutableHandleValue vp) {
+[[nodiscard]] MOZ_ALWAYS_INLINE bool ToNumeric(JSContext* cx,
+                                               JS::MutableHandleValue vp) {
   if (vp.isNumeric()) {
     return true;
   }
   return ToNumericSlow(cx, vp);
 }
 
 bool ToInt32OrBigIntSlow(JSContext* cx, JS::MutableHandleValue vp);
 
-MOZ_ALWAYS_INLINE MOZ_MUST_USE bool ToInt32OrBigInt(JSContext* cx,
-                                                    JS::MutableHandleValue vp) {
+[[nodiscard]] MOZ_ALWAYS_INLINE bool ToInt32OrBigInt(
+    JSContext* cx, JS::MutableHandleValue vp) {
   if (vp.isInt32()) {
     return true;
   }
   return ToInt32OrBigIntSlow(cx, vp);
 }
 
 } /* namespace js */
 
@@ -250,42 +251,42 @@ MOZ_ALWAYS_INLINE MOZ_MUST_USE bool ToIn
  * Also allows inputs of the form [+|-]Infinity, which produce an infinity of
  * the appropriate sign.  The case of the "Infinity" string must match exactly.
  * If the string does not contain a number, set *dEnd to begin and return 0.0
  * in *d.
  *
  * Return false if out of memory.
  */
 template <typename CharT>
-extern MOZ_MUST_USE bool js_strtod(JSContext* cx, const CharT* begin,
-                                   const CharT* end, const CharT** dEnd,
-                                   double* d);
+[[nodiscard]] extern bool js_strtod(JSContext* cx, const CharT* begin,
+                                    const CharT* end, const CharT** dEnd,
+                                    double* d);
 
 namespace js {
 
 /**
  * Like js_strtod, but for when the number always constitutes the entire range
  * (and so |dEnd| would be a value already known).
  */
 template <typename CharT>
-extern MOZ_MUST_USE bool FullStringToDouble(JSContext* cx, const CharT* begin,
-                                            const CharT* end, double* d) {
+[[nodiscard]] extern bool FullStringToDouble(JSContext* cx, const CharT* begin,
+                                             const CharT* end, double* d) {
   decltype(ToRawChars(begin)) realEnd;
   if (js_strtod(cx, ToRawChars(begin), ToRawChars(end), &realEnd, d)) {
     MOZ_ASSERT(end == static_cast<const void*>(realEnd));
     return true;
   }
   return false;
 }
 
-extern MOZ_MUST_USE bool ThisNumberValueForToLocaleString(JSContext* cx,
-                                                          unsigned argc,
-                                                          Value* vp);
+[[nodiscard]] extern bool ThisNumberValueForToLocaleString(JSContext* cx,
+                                                           unsigned argc,
+                                                           Value* vp);
 
-extern MOZ_MUST_USE bool num_valueOf(JSContext* cx, unsigned argc, Value* vp);
+[[nodiscard]] extern bool num_valueOf(JSContext* cx, unsigned argc, Value* vp);
 
 /*
  * Returns true if the given value is definitely an index: that is, the value
  * is a number that's an unsigned 32-bit integer.
  *
  * This method prioritizes common-case speed over accuracy in every case.  It
  * can produce false negatives (but not false positives): some values which are
  * indexes will be reported not to be indexes by this method.  Users must
@@ -309,18 +310,18 @@ static MOZ_ALWAYS_INLINE bool IsDefinite
     return true;
   }
 
   return false;
 }
 
 // ES2020 draft rev 6b05bc56ba4e3c7a2b9922c4282d9eb844426d9b
 // 7.1.5 ToInteger ( argument )
-static MOZ_MUST_USE inline bool ToInteger(JSContext* cx, HandleValue v,
-                                          double* dp) {
+[[nodiscard]] static inline bool ToInteger(JSContext* cx, HandleValue v,
+                                           double* dp) {
   if (v.isInt32()) {
     *dp = v.toInt32();
     return true;
   }
   if (v.isDouble()) {
     *dp = v.toDouble();
   } else if (v.isString() && v.toString()->hasIndexValue()) {
     *dp = v.toString()->getIndexValue();
@@ -338,33 +339,33 @@ static MOZ_MUST_USE inline bool ToIntege
 
 /* ES2017 draft 7.1.17 ToIndex
  *
  * Return true and set |*index| to the integer value if |v| is a valid
  * integer index value. Otherwise report a RangeError and return false.
  *
  * The returned index will always be in the range 0 <= *index <= 2^53-1.
  */
-extern MOZ_MUST_USE bool ToIndexSlow(JSContext* cx, JS::HandleValue v,
-                                     const unsigned errorNumber,
-                                     uint64_t* index);
+[[nodiscard]] extern bool ToIndexSlow(JSContext* cx, JS::HandleValue v,
+                                      const unsigned errorNumber,
+                                      uint64_t* index);
 
-static MOZ_MUST_USE inline bool ToIndex(JSContext* cx, JS::HandleValue v,
-                                        const unsigned errorNumber,
-                                        uint64_t* index) {
+[[nodiscard]] static inline bool ToIndex(JSContext* cx, JS::HandleValue v,
+                                         const unsigned errorNumber,
+                                         uint64_t* index) {
   if (v.isInt32()) {
     int32_t i = v.toInt32();
     if (i >= 0) {
       *index = uint64_t(i);
       return true;
     }
   }
   return ToIndexSlow(cx, v, errorNumber, index);
 }
 
-static MOZ_MUST_USE inline bool ToIndex(JSContext* cx, JS::HandleValue v,
-                                        uint64_t* index) {
+[[nodiscard]] static inline bool ToIndex(JSContext* cx, JS::HandleValue v,
+                                         uint64_t* index) {
   return ToIndex(cx, v, JSMSG_BAD_INDEX, index);
 }
 
 } /* namespace js */
 
 #endif /* jsnum_h */
--- a/js/src/shell/WasmTesting.h
+++ b/js/src/shell/WasmTesting.h
@@ -23,18 +23,18 @@
 
 namespace js {
 namespace wasm {
 
 // Translate the textual representation of a wasm module (given by a
 // char16_t array + length) into serialized bytes. If there is an error
 // other than out-of-memory an error message string will be stored in 'error'.
 
-extern MOZ_MUST_USE bool TextToBinary(const char16_t* text, size_t textLen,
-                                      Bytes* bytes, UniqueChars* error);
+[[nodiscard]] extern bool TextToBinary(const char16_t* text, size_t textLen,
+                                       Bytes* bytes, UniqueChars* error);
 
 // Decode the binary wasm module given and return the offsets of all
 // instructions inside of the the code section.
 //
 // This function is used exclusively for testing and handles errors by
 // returning an empty offset array.
 
 extern void CodeOffsets(const uint8_t* bytes, size_t bytesLen,
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -921,19 +921,19 @@ static bool RegisterScriptPathWithModule
   return true;
 }
 
 enum class CompileUtf8 {
   InflateToUtf16,
   DontInflate,
 };
 
-static MOZ_MUST_USE bool RunFile(JSContext* cx, const char* filename,
-                                 FILE* file, CompileUtf8 compileMethod,
-                                 bool compileOnly) {
+[[nodiscard]] static bool RunFile(JSContext* cx, const char* filename,
+                                  FILE* file, CompileUtf8 compileMethod,
+                                  bool compileOnly) {
   SkipUTF8BOM(file);
 
   int64_t t1 = PRMJ_Now();
   RootedScript script(cx);
 
   {
     CompileOptions options(cx);
     options.setIntroductionType("js shell file")
@@ -992,18 +992,18 @@ static MOZ_MUST_USE bool RunFile(JSConte
     int64_t t2 = PRMJ_Now() - t1;
     if (printTiming) {
       printf("runtime = %.3f ms\n", double(t2) / PRMJ_USEC_PER_MSEC);
     }
   }
   return true;
 }
 
-static MOZ_MUST_USE bool RunModule(JSContext* cx, const char* filename,
-                                   bool compileOnly) {
+[[nodiscard]] static bool RunModule(JSContext* cx, const char* filename,
+                                    bool compileOnly) {
   ShellContext* sc = GetShellContext(cx);
 
   RootedString path(cx, JS_NewStringCopyZ(cx, filename));
   if (!path) {
     return false;
   }
 
   path = ResolvePath(cx, path, RootRelative);
@@ -1405,19 +1405,19 @@ static bool AddIntlExtras(JSContext* cx,
     return false;
   }
 
   args.rval().setUndefined();
   return true;
 }
 #endif  // JS_HAS_INTL_API
 
-static MOZ_MUST_USE bool EvalUtf8AndPrint(JSContext* cx, const char* bytes,
-                                          size_t length, int lineno,
-                                          bool compileOnly) {
+[[nodiscard]] static bool EvalUtf8AndPrint(JSContext* cx, const char* bytes,
+                                           size_t length, int lineno,
+                                           bool compileOnly) {
   // Eval.
   JS::CompileOptions options(cx);
   options.setIntroductionType("js shell interactive")
       .setIsRunOnce(true)
       .setFileAndLine("typein", lineno);
 
   JS::SourceText<Utf8Unit> srcBuf;
   if (!srcBuf.init(cx, bytes, length, JS::SourceOwnership::Borrowed)) {
@@ -1447,18 +1447,18 @@ static MOZ_MUST_USE bool EvalUtf8AndPrin
     if (!utf8chars) {
       return false;
     }
     fprintf(gOutFile->fp, "%s\n", utf8chars.get());
   }
   return true;
 }
 
-static MOZ_MUST_USE bool ReadEvalPrintLoop(JSContext* cx, FILE* in,
-                                           bool compileOnly) {
+[[nodiscard]] static bool ReadEvalPrintLoop(JSContext* cx, FILE* in,
+                                            bool compileOnly) {
   ShellContext* sc = GetShellContext(cx);
   int lineno = 1;
   bool hitEOF = false;
 
   do {
     /*
      * Accumulate lines until we get a 'compilable unit' - one that either
      * generates an error (before running out of source) or that compiles
@@ -1554,18 +1554,18 @@ static void ReportCantOpenErrorUnknownEn
    * Latin-1 is possibly wrong for both of these -- but at least if it's
    * wrong it'll produce mojibake *safely*.  Run with Latin-1 til someone
    * complains.
    */
   JS_ReportErrorNumberLatin1(cx, my_GetErrorMessage, nullptr, JSSMSG_CANT_OPEN,
                              filename, strerror(errno));
 }
 
-static MOZ_MUST_USE bool Process(JSContext* cx, const char* filename,
-                                 bool forceTTY, FileKind kind) {
+[[nodiscard]] static bool Process(JSContext* cx, const char* filename,
+                                  bool forceTTY, FileKind kind) {
   FILE* file;
   if (forceTTY || !filename || strcmp(filename, "-") == 0) {
     file = stdin;
   } else {
     file = fopen(filename, "rb");
     if (!file) {
       ReportCantOpenErrorUnknownEncoding(cx, filename);
       return false;
@@ -3164,18 +3164,18 @@ static bool PCToLine(JSContext* cx, unsi
     return false;
   }
   args.rval().setInt32(lineno);
   return true;
 }
 
 #if defined(DEBUG) || defined(JS_JITSPEW)
 
-static MOZ_MUST_USE bool SrcNotes(JSContext* cx, HandleScript script,
-                                  Sprinter* sp) {
+[[nodiscard]] static bool SrcNotes(JSContext* cx, HandleScript script,
+                                   Sprinter* sp) {
   if (!sp->put("\nSource notes:\n") ||
       !sp->jsprintf("%4s %4s %6s %5s %6s %-10s %s\n", "ofs", "line", "column",
                     "pc", "delta", "desc", "args") ||
       !sp->put("---- ---- ------ ----- ------ ---------- ------\n")) {
     return false;
   }
 
   unsigned offset = 0;
@@ -3277,34 +3277,34 @@ static const char* TryNoteName(TryNoteKi
       return "for-of-iterclose";
     case TryNoteKind::Destructuring:
       return "destructuring";
   }
 
   MOZ_CRASH("Bad TryNoteKind");
 }
 
-static MOZ_MUST_USE bool TryNotes(JSContext* cx, HandleScript script,
-                                  Sprinter* sp) {
+[[nodiscard]] static bool TryNotes(JSContext* cx, HandleScript script,
+                                   Sprinter* sp) {
   if (!sp->put(
           "\nException table:\nkind               stack    start      end\n")) {
     return false;
   }
 
   for (const TryNote& tn : script->trynotes()) {
     if (!sp->jsprintf(" %-16s %6u %8u %8u\n", TryNoteName(tn.kind()),
                       tn.stackDepth, tn.start, tn.start + tn.length)) {
       return false;
     }
   }
   return true;
 }
 
-static MOZ_MUST_USE bool ScopeNotes(JSContext* cx, HandleScript script,
-                                    Sprinter* sp) {
+[[nodiscard]] static bool ScopeNotes(JSContext* cx, HandleScript script,
+                                     Sprinter* sp) {
   if (!sp->put("\nScope notes:\n   index   parent    start      end\n")) {
     return false;
   }
 
   for (const ScopeNote& note : script->scopeNotes()) {
     if (note.index == ScopeNote::NoScopeIndex) {
       if (!sp->jsprintf("%8s ", "(none)")) {
         return false;
@@ -3325,18 +3325,18 @@ static MOZ_MUST_USE bool ScopeNotes(JSCo
     }
     if (!sp->jsprintf("%8u %8u\n", note.start, note.start + note.length)) {
       return false;
     }
   }
   return true;
 }
 
-static MOZ_MUST_USE bool GCThings(JSContext* cx, HandleScript script,
-                                  Sprinter* sp) {
+[[nodiscard]] static bool GCThings(JSContext* cx, HandleScript script,
+                                   Sprinter* sp) {
   if (!sp->put("\nGC things:\n   index   type       value\n")) {
     return false;
   }
 
   size_t i = 0;
   for (JS::GCCellPtr gcThing : script->gcthings()) {
     if (!sp->jsprintf("%8zu   ", i)) {
       return false;
@@ -3442,20 +3442,20 @@ static MOZ_MUST_USE bool GCThings(JSCont
       }
     }
     i++;
   }
 
   return true;
 }
 
-static MOZ_MUST_USE bool DisassembleScript(JSContext* cx, HandleScript script,
-                                           HandleFunction fun, bool lines,
-                                           bool recursive, bool sourceNotes,
-                                           bool gcThings, Sprinter* sp) {
+[[nodiscard]] static bool DisassembleScript(JSContext* cx, HandleScript script,
+                                            HandleFunction fun, bool lines,
+                                            bool recursive, bool sourceNotes,
+                                            bool gcThings, Sprinter* sp) {
   if (fun) {
     if (!sp->put("flags:")) {
       return false;
     }
     if (fun->isLambda()) {
       if (!sp->put(" LAMBDA")) {
         return false;
       }
@@ -4125,19 +4125,19 @@ static void SetStandardRealmOptions(JS::
       .setWeakRefsEnabled(enableWeakRefs
                               ? JS::WeakRefSpecifier::EnabledWithCleanupSome
                               : JS::WeakRefSpecifier::Disabled)
       .setToSourceEnabled(enableToSource)
       .setPropertyErrorMessageFixEnabled(enablePropertyErrorMessageFix)
       .setIteratorHelpersEnabled(enableIteratorHelpers);
 }
 
-static MOZ_MUST_USE bool CheckRealmOptions(JSContext* cx,
-                                           JS::RealmOptions& options,
-                                           JSPrincipals* principals) {
+[[nodiscard]] static bool CheckRealmOptions(JSContext* cx,
+                                            JS::RealmOptions& options,
+                                            JSPrincipals* principals) {
   JS::RealmCreationOptions& creationOptions = options.creationOptions();
   if (creationOptions.compartmentSpecifier() !=
       JS::CompartmentSpecifier::ExistingCompartment) {
     return true;
   }
 
   JS::Compartment* comp = creationOptions.compartment();
 
@@ -5201,18 +5201,18 @@ static bool ParseModule(JSContext* cx, u
 class XDRBufferObject : public NativeObject {
   static const size_t VECTOR_SLOT = 0;
   static const unsigned RESERVED_SLOTS = 1;
 
  public:
   static const JSClassOps classOps_;
   static const JSClass class_;
 
-  inline static MOZ_MUST_USE XDRBufferObject* create(JSContext* cx,
-                                                     JS::TranscodeBuffer&& buf);
+  [[nodiscard]] inline static XDRBufferObject* create(
+      JSContext* cx, JS::TranscodeBuffer&& buf);
 
   JS::TranscodeBuffer* data() const {
     Value value = getReservedSlot(VECTOR_SLOT);
     auto buf = static_cast<JS::TranscodeBuffer*>(value.toPrivate());
     MOZ_ASSERT(buf);
     return buf;
   }
 
@@ -10364,17 +10364,17 @@ static bool BindScriptArgs(JSContext* cx
   return true;
 }
 
 static bool OptionFailure(const char* option, const char* str) {
   fprintf(stderr, "Unrecognized option for %s: %s\n", option, str);
   return false;
 }
 
-static MOZ_MUST_USE bool ProcessArgs(JSContext* cx, OptionParser* op) {
+[[nodiscard]] static bool ProcessArgs(JSContext* cx, OptionParser* op) {
   ShellContext* sc = GetShellContext(cx);
 
 #ifdef JS_ENABLE_SMOOSH
   if (op->getBoolOption("smoosh")) {
     JS::ContextOptionsRef(cx).setTrySmoosh(true);
     js::frontend::InitSmoosh();
   }
 
@@ -11047,17 +11047,17 @@ static void SetWorkerContextOptions(JSCo
       }
     }
   }
 #endif
 
   JS_SetNativeStackQuota(cx, gMaxStackSize);
 }
 
-static MOZ_MUST_USE bool PrintUnhandledRejection(
+[[nodiscard]] static bool PrintUnhandledRejection(
     JSContext* cx, Handle<PromiseObject*> promise) {
   RootedValue reason(cx, promise->reason());
   RootedObject site(cx, promise->resolutionSite());
 
   RootedString str(cx, JS_ValueToSource(cx, reason));
   if (!str) {
     return false;
   }
@@ -11087,17 +11087,17 @@ static MOZ_MUST_USE bool PrintUnhandledR
   }
 
   fputs("Stack:\n", fp);
   fputs(stack.get(), fp);
 
   return true;
 }
 
-static MOZ_MUST_USE bool ReportUnhandledRejections(JSContext* cx) {
+[[nodiscard]] static bool ReportUnhandledRejections(JSContext* cx) {
   ShellContext* sc = GetShellContext(cx);
   if (!sc->trackUnhandledRejections) {
     return true;
   }
 
   if (!sc->unhandledRejectedPromises) {
     return true;
   }
--- a/js/src/shell/jsshell.h
+++ b/js/src/shell/jsshell.h
@@ -262,18 +262,18 @@ struct ShellContext {
 
   // Queued finalization registry cleanup jobs.
   using FunctionVector = GCVector<JSFunction*, 0, SystemAllocPolicy>;
   JS::PersistentRooted<FunctionVector> finalizationRegistryCleanupCallbacks;
 };
 
 extern ShellContext* GetShellContext(JSContext* cx);
 
-extern MOZ_MUST_USE bool PrintStackTrace(JSContext* cx,
-                                         JS::Handle<JSObject*> stackObj);
+[[nodiscard]] extern bool PrintStackTrace(JSContext* cx,
+                                          JS::Handle<JSObject*> stackObj);
 
 extern JSObject* CreateScriptPrivate(JSContext* cx,
                                      HandleString path = nullptr);
 
 } /* namespace shell */
 } /* namespace js */
 
 #endif
--- a/js/src/util/StringBuffer.h
+++ b/js/src/util/StringBuffer.h
@@ -196,17 +196,17 @@ class StringBuffer {
     }
     return twoByteChars().append(c);
   }
   [[nodiscard]] bool append(Latin1Char c) {
     return isLatin1() ? latin1Chars().append(c) : twoByteChars().append(c);
   }
   [[nodiscard]] bool append(char c) { return append(Latin1Char(c)); }
 
-  inline MOZ_MUST_USE bool append(const char16_t* begin, const char16_t* end);
+  [[nodiscard]] inline bool append(const char16_t* begin, const char16_t* end);
 
   [[nodiscard]] bool append(const char16_t* chars, size_t len) {
     return append(chars, chars + len);
   }
 
   [[nodiscard]] bool append(const Latin1Char* begin, const Latin1Char* end) {
     return isLatin1() ? latin1Chars().append(begin, end)
                       : twoByteChars().append(begin, end);
@@ -226,22 +226,22 @@ class StringBuffer {
   [[nodiscard]] bool append(const JS::ConstCharPtr chars, size_t len) {
     return append(chars.get(), chars.get() + len);
   }
   [[nodiscard]] bool appendN(Latin1Char c, size_t n) {
     return isLatin1() ? latin1Chars().appendN(c, n)
                       : twoByteChars().appendN(c, n);
   }
 
-  inline MOZ_MUST_USE bool append(JSString* str);
-  inline MOZ_MUST_USE bool append(JSLinearString* str);
-  inline MOZ_MUST_USE bool appendSubstring(JSString* base, size_t off,
-                                           size_t len);
-  inline MOZ_MUST_USE bool appendSubstring(JSLinearString* base, size_t off,
-                                           size_t len);
+  [[nodiscard]] inline bool append(JSString* str);
+  [[nodiscard]] inline bool append(JSLinearString* str);
+  [[nodiscard]] inline bool appendSubstring(JSString* base, size_t off,
+                                            size_t len);
+  [[nodiscard]] inline bool appendSubstring(JSLinearString* base, size_t off,
+                                            size_t len);
   [[nodiscard]] bool append(const frontend::ParserAtomsTable& parserAtoms,
                             frontend::TaggedParserAtomIndex atom);
 
   [[nodiscard]] bool append(const char* chars, size_t len) {
     return append(reinterpret_cast<const Latin1Char*>(chars), len);
   }
 
   template <size_t ArrayLength>
--- a/js/src/vm/ArrayBufferObject.cpp
+++ b/js/src/vm/ArrayBufferObject.cpp
@@ -130,18 +130,18 @@ static const int32_t AllocatedBuffersPer
 
 static Atomic<int32_t, mozilla::ReleaseAcquire> liveBufferCount(0);
 static Atomic<int32_t, mozilla::ReleaseAcquire> allocatedSinceLastTrigger(0);
 
 int32_t js::LiveMappedBufferCount() { return liveBufferCount; }
 
 bool js::ArrayBufferObject::supportLargeBuffers = false;
 
-static MOZ_MUST_USE bool CheckArrayBufferTooLarge(JSContext* cx,
-                                                  uint64_t nbytes) {
+[[nodiscard]] static bool CheckArrayBufferTooLarge(JSContext* cx,
+                                                   uint64_t nbytes) {
   // Refuse to allocate too large buffers.
   if (MOZ_UNLIKELY(nbytes > ArrayBufferObject::maxBufferByteLength())) {
     JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
                               JSMSG_BAD_ARRAY_LENGTH);
     return false;
   }
 
   return true;
--- a/js/src/vm/ArrayBufferObject.h
+++ b/js/src/vm/ArrayBufferObject.h
@@ -451,20 +451,20 @@ class ArrayBufferObject : public ArrayBu
   /**
    * Prepare this ArrayBuffer for use with asm.js.  Returns true on success,
    * false on failure.  This function reports no errors.
    */
   [[nodiscard]] bool prepareForAsmJS();
 
   size_t wasmMappedSize() const;
   mozilla::Maybe<uint64_t> wasmMaxSize() const;
-  static MOZ_MUST_USE bool wasmGrowToSizeInPlace(
+  [[nodiscard]] static bool wasmGrowToSizeInPlace(
       BufferSize newSize, Handle<ArrayBufferObject*> oldBuf,
       MutableHandle<ArrayBufferObject*> newBuf, JSContext* cx);
-  static MOZ_MUST_USE bool wasmMovingGrowToSize(
+  [[nodiscard]] static bool wasmMovingGrowToSize(
       BufferSize newSize, Handle<ArrayBufferObject*> oldBuf,
       MutableHandle<ArrayBufferObject*> newBuf, JSContext* cx);
 
   static void finalize(JSFreeOp* fop, JSObject* obj);
 
   static BufferContents createMappedContents(int fd, size_t offset,
                                              size_t length);
 
--- a/js/src/vm/AsyncIteration.cpp
+++ b/js/src/vm/AsyncIteration.cpp
@@ -309,32 +309,32 @@ AsyncGeneratorRequest* AsyncGeneratorReq
   }
 
   request->init(completionKind, completionValue, promise);
   return request;
 }
 
 // ES2019 draft rev c012f9c70847559a1d9dc0d35d35b27fec42911e
 // 25.5.3.2 AsyncGeneratorStart
-static MOZ_MUST_USE bool AsyncGeneratorReturned(
+[[nodiscard]] static bool AsyncGeneratorReturned(
     JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
     HandleValue value) {
   // Step 5.d.
   asyncGenObj->setCompleted();
 
   // Step 5.e (done in bytecode).
   // Step 5.f.i (implicit).
 
   // Step 5.g.
   return AsyncGeneratorResolve(cx, asyncGenObj, value, true);
 }
 
 // ES2019 draft rev c012f9c70847559a1d9dc0d35d35b27fec42911e
 // 25.5.3.2 AsyncGeneratorStart
-static MOZ_MUST_USE bool AsyncGeneratorThrown(
+[[nodiscard]] static bool AsyncGeneratorThrown(
     JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj) {
   // Step 5.d.
   asyncGenObj->setCompleted();
 
   // Not much we can do about uncatchable exceptions, so just bail.
   if (!cx->isExceptionPending()) {
     return false;
   }
@@ -347,17 +347,17 @@ static MOZ_MUST_USE bool AsyncGeneratorT
 
   // Step 5.f.ii.
   return AsyncGeneratorReject(cx, asyncGenObj, value);
 }
 
 // ES2019 draft rev c012f9c70847559a1d9dc0d35d35b27fec42911e
 // 25.5.3.7 AsyncGeneratorYield (partially)
 // Most steps are done in generator.
-static MOZ_MUST_USE bool AsyncGeneratorYield(
+[[nodiscard]] static bool AsyncGeneratorYield(
     JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
     HandleValue value) {
   // Step 5 is done in bytecode.
 
   // Step 6.
   asyncGenObj->setSuspendedYield();
 
   // Step 9.
--- a/js/src/vm/AsyncIteration.h
+++ b/js/src/vm/AsyncIteration.h
@@ -473,17 +473,17 @@ class AsyncGeneratorObject : public Abst
 
   void setSuspendedStart() { setState(State_SuspendedStart); }
   void setSuspendedYield() { setState(State_SuspendedYield); }
   void setExecuting() { setState(State_Executing); }
   void setAwaitingYieldReturn() { setState(State_AwaitingYieldReturn); }
   void setAwaitingReturn() { setState(State_AwaitingReturn); }
   void setCompleted() { setState(State_Completed); }
 
-  static MOZ_MUST_USE bool enqueueRequest(
+  [[nodiscard]] static bool enqueueRequest(
       JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
       Handle<AsyncGeneratorRequest*> request);
 
   static AsyncGeneratorRequest* dequeueRequest(
       JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj);
 
   static AsyncGeneratorRequest* peekRequest(
       Handle<AsyncGeneratorObject*> asyncGenObj);
--- a/js/src/vm/BigIntType.h
+++ b/js/src/vm/BigIntType.h
@@ -263,20 +263,20 @@ class BigInt final : public js::gc::Cell
   // corresponding character count into a size_t, with space for a possible
   // sign prefix.
   static_assert(MaxBitLength <= std::numeric_limits<size_t>::max() - 1,
                 "BigInt max length must be small enough to be serialized as a "
                 "binary string");
 
   static size_t calculateMaximumCharactersRequired(HandleBigInt x,
                                                    unsigned radix);
-  static MOZ_MUST_USE bool calculateMaximumDigitsRequired(JSContext* cx,
-                                                          uint8_t radix,
-                                                          size_t charCount,
-                                                          size_t* result);
+  [[nodiscard]] static bool calculateMaximumDigitsRequired(JSContext* cx,
+                                                           uint8_t radix,
+                                                           size_t charCount,
+                                                           size_t* result);
 
   static bool absoluteDivWithDigitDivisor(
       JSContext* cx, Handle<BigInt*> x, Digit divisor,
       const mozilla::Maybe<MutableHandle<BigInt*>>& quotient, Digit* remainder,
       bool quotientNegative);
   static void internalMultiplyAdd(BigInt* source, Digit factor, Digit summand,
                                   unsigned, BigInt* result);
   static void multiplyAccumulate(BigInt* multiplicand, Digit multiplier,
--- a/js/src/vm/BytecodeUtil.cpp
+++ b/js/src/vm/BytecodeUtil.cpp
@@ -105,18 +105,18 @@ const char* const js::CodeNameTable[] = 
 
 /************************************************************************/
 
 static bool DecompileArgumentFromStack(JSContext* cx, int formalIndex,
                                        UniqueChars* res);
 
 /* static */ const char PCCounts::numExecName[] = "interp";
 
-static MOZ_MUST_USE bool DumpIonScriptCounts(Sprinter* sp, HandleScript script,
-                                             jit::IonScriptCounts* ionCounts) {
+[[nodiscard]] static bool DumpIonScriptCounts(Sprinter* sp, HandleScript script,
+                                              jit::IonScriptCounts* ionCounts) {
   if (!sp->jsprintf("IonScript [%zu blocks]:\n", ionCounts->numBlocks())) {
     return false;
   }
 
   for (size_t i = 0; i < ionCounts->numBlocks(); i++) {
     const jit::IonBlockCounts& block = ionCounts->block(i);
     unsigned lineNumber = 0, columnNumber = 0;
     lineNumber = PCToLineNumber(script, script->offsetToPC(block.offset()),
@@ -141,18 +141,18 @@ static MOZ_MUST_USE bool DumpIonScriptCo
     if (!sp->jsprintf("%s\n", block.code())) {
       return false;
     }
   }
 
   return true;
 }
 
-static MOZ_MUST_USE bool DumpPCCounts(JSContext* cx, HandleScript script,
-                                      Sprinter* sp) {
+[[nodiscard]] static bool DumpPCCounts(JSContext* cx, HandleScript script,
+                                       Sprinter* sp) {
   MOZ_ASSERT(script->hasScriptCounts());
 
   // Ensure the Disassemble1 call below does not discard the script counts.
   gc::AutoSuppressGC suppress(cx);
 
 #ifdef DEBUG
   jsbytecode* pc = script->code();
   while (pc < script->codeEnd()) {
@@ -986,17 +986,17 @@ static unsigned Disassemble1(JSContext* 
                              unsigned loc, bool lines,
                              const BytecodeParser* parser, Sprinter* sp);
 
 /*
  * If pc != nullptr, include a prefix indicating whether the PC is at the
  * current line. If showAll is true, include the source note type and the
  * entry stack depth.
  */
-static MOZ_MUST_USE bool DisassembleAtPC(
+[[nodiscard]] static bool DisassembleAtPC(
     JSContext* cx, JSScript* scriptArg, bool lines, const jsbytecode* pc,
     bool showAll, Sprinter* sp,
     DisassembleSkeptically skeptically = DisassembleSkeptically::No) {
   LifoAllocScope allocScope(&cx->tempLifoAlloc());
   RootedScript script(cx, scriptArg);
   mozilla::Maybe<BytecodeParser> parser;
 
   if (skeptically == DisassembleSkeptically::No) {
@@ -2608,18 +2608,18 @@ JS_FRIEND_API size_t js::GetPCCountScrip
 
   if (!rt->scriptAndCountsVector) {
     return 0;
   }
 
   return rt->scriptAndCountsVector->length();
 }
 
-static MOZ_MUST_USE bool JSONStringProperty(Sprinter& sp, JSONPrinter& json,
-                                            const char* name, JSString* str) {
+[[nodiscard]] static bool JSONStringProperty(Sprinter& sp, JSONPrinter& json,
+                                             const char* name, JSString* str) {
   json.beginStringProperty(name);
   if (!JSONQuoteString(&sp, str)) {
     return false;
   }
   json.endStringProperty();
   return true;
 }
 
--- a/js/src/vm/BytecodeUtil.h
+++ b/js/src/vm/BytecodeUtil.h
@@ -680,22 +680,22 @@ inline GeneratorResumeKind ResumeKindFro
 
 #if defined(DEBUG) || defined(JS_JITSPEW)
 
 enum class DisassembleSkeptically { No, Yes };
 
 /*
  * Disassemblers, for debugging only.
  */
-extern MOZ_MUST_USE bool Disassemble(
+[[nodiscard]] extern bool Disassemble(
     JSContext* cx, JS::Handle<JSScript*> script, bool lines, Sprinter* sp,
     DisassembleSkeptically skeptically = DisassembleSkeptically::No);
 
 unsigned Disassemble1(JSContext* cx, JS::Handle<JSScript*> script,
                       jsbytecode* pc, unsigned loc, bool lines, Sprinter* sp);
 
 #endif
 
-extern MOZ_MUST_USE bool DumpRealmPCCounts(JSContext* cx);
+[[nodiscard]] extern bool DumpRealmPCCounts(JSContext* cx);
 
 }  // namespace js
 
 #endif /* vm_BytecodeUtil_h */
--- a/js/src/vm/Compartment-inl.h
+++ b/js/src/vm/Compartment-inl.h
@@ -186,18 +186,19 @@ template <class ErrorCallback>
  *
  * DANGER: The result may not be same-compartment with `cx`.
  *
  * This calls `throwTypeError` if the value isn't an object, cannot be
  * unwrapped, or isn't an instance of the expected type. `throwTypeError` must
  * in fact throw a TypeError (or OOM trying).
  */
 template <class T, class ErrorCallback>
-inline MOZ_MUST_USE T* UnwrapAndTypeCheckValue(JSContext* cx, HandleValue value,
-                                               ErrorCallback throwTypeError) {
+[[nodiscard]] inline T* UnwrapAndTypeCheckValue(JSContext* cx,
+                                                HandleValue value,
+                                                ErrorCallback throwTypeError) {
   cx->check(value);
 
   static_assert(!std::is_convertible_v<T*, Wrapper*>,
                 "T can't be a Wrapper type; this function discards wrappers");
 
   if (value.isObject() && value.toObject().is<T>()) {
     return &value.toObject().as<T>();
   }
@@ -211,17 +212,17 @@ inline MOZ_MUST_USE T* UnwrapAndTypeChec
  *
  * DANGER: The result may not be same-compartment with |cx|.
  *
  * This calls |throwTypeError| if the value isn't an object, cannot be
  * unwrapped, or isn't an instance of the expected type.  |throwTypeError| must
  * in fact throw a TypeError (or OOM trying).
  */
 template <class ErrorCallback>
-inline MOZ_MUST_USE JSObject* UnwrapAndTypeCheckValue(
+[[nodiscard]] inline JSObject* UnwrapAndTypeCheckValue(
     JSContext* cx, HandleValue value, const JSClass* clasp,
     ErrorCallback throwTypeError) {
   cx->check(value);
 
   if (value.isObject() && value.toObject().hasClass(clasp)) {
     return &value.toObject();
   }
 
@@ -234,19 +235,19 @@ inline MOZ_MUST_USE JSObject* UnwrapAndT
  * class `T`.
  *
  * DANGER: The result may not be same-compartment with `cx`.
  *
  * This throws a TypeError if the value isn't an object, cannot be unwrapped,
  * or isn't an instance of the expected type.
  */
 template <class T>
-inline MOZ_MUST_USE T* UnwrapAndTypeCheckThis(JSContext* cx,
-                                              const CallArgs& args,
-                                              const char* methodName) {
+[[nodiscard]] inline T* UnwrapAndTypeCheckThis(JSContext* cx,
+                                               const CallArgs& args,
+                                               const char* methodName) {
   HandleValue thisv = args.thisv();
   return UnwrapAndTypeCheckValue<T>(cx, thisv, [cx, methodName, thisv] {
     JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr,
                                JSMSG_INCOMPATIBLE_PROTO, detail::ClassName<T>(),
                                methodName, InformalValueTypeName(thisv));
   });
 }
 
@@ -255,19 +256,20 @@ inline MOZ_MUST_USE T* UnwrapAndTypeChec
  * class `T`.
  *
  * DANGER: The result may not be same-compartment with `cx`.
  *
  * This throws a TypeError if the specified argument is missing, isn't an
  * object, cannot be unwrapped, or isn't an instance of the expected type.
  */
 template <class T>
-inline MOZ_MUST_USE T* UnwrapAndTypeCheckArgument(JSContext* cx, CallArgs& args,
-                                                  const char* methodName,
-                                                  int argIndex) {
+[[nodiscard]] inline T* UnwrapAndTypeCheckArgument(JSContext* cx,
+                                                   CallArgs& args,
+                                                   const char* methodName,
+                                                   int argIndex) {
   HandleValue val = args.get(argIndex);
   return UnwrapAndTypeCheckValue<T>(cx, val, [cx, val, methodName, argIndex] {
     ToCStringBuf cbuf;
     if (char* numStr = NumberToCString(cx, &cbuf, argIndex + 1, 10)) {
       JS_ReportErrorNumberLatin1(
           cx, GetErrorMessage, nullptr, JSMSG_WRONG_TYPE_ARG, numStr,
           methodName, detail::ClassName<T>(), InformalValueTypeName(val));
     } else {
@@ -283,17 +285,17 @@ inline MOZ_MUST_USE T* UnwrapAndTypeChec
  * `obj` is a wrapper for such an object, this tries to unwrap the object and
  * return a pointer to it. If access is denied, or `obj` was a wrapper but has
  * been nuked, this reports an error and returns null.
  *
  * In all other cases, the behavior is undefined, so call this only if `obj` is
  * known to have been an object of class T, or a wrapper to a T, at some point.
  */
 template <class T>
-inline MOZ_MUST_USE T* UnwrapAndDowncastObject(JSContext* cx, JSObject* obj) {
+[[nodiscard]] inline T* UnwrapAndDowncastObject(JSContext* cx, JSObject* obj) {
   static_assert(!std::is_convertible_v<T*, Wrapper*>,
                 "T can't be a Wrapper type; this function discards wrappers");
 
   if (IsProxy(obj)) {
     if (JS_IsDeadWrapper(obj)) {
       JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
                                 JSMSG_DEAD_OBJECT);
       return nullptr;
@@ -318,19 +320,19 @@ inline MOZ_MUST_USE T* UnwrapAndDowncast
  * wrapper for such an object, this tries to unwrap the object and return a
  * pointer to it.  If access is denied, or |obj| was a wrapper but has been
  * nuked, this reports an error and returns null.
  *
  * In all other cases, the behavior is undefined, so call this only if |obj| is
  * known to have had class |clasp|, or been a wrapper to such an object, at some
  * point.
  */
-inline MOZ_MUST_USE JSObject* UnwrapAndDowncastObject(JSContext* cx,
-                                                      JSObject* obj,
-                                                      const JSClass* clasp) {
+[[nodiscard]] inline JSObject* UnwrapAndDowncastObject(JSContext* cx,
+                                                       JSObject* obj,
+                                                       const JSClass* clasp) {
   if (IsProxy(obj)) {
     if (JS_IsDeadWrapper(obj)) {
       JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
                                 JSMSG_DEAD_OBJECT);
       return nullptr;
     }
 
     // It would probably be OK to do an unchecked unwrap here, but we allow
@@ -345,28 +347,28 @@ inline MOZ_MUST_USE JSObject* UnwrapAndD
   MOZ_ASSERT(obj->hasClass(clasp));
   return obj;
 }
 
 /**
  * Unwrap a value of a known type. See UnwrapAndDowncastObject.
  */
 template <class T>
-inline MOZ_MUST_USE T* UnwrapAndDowncastValue(JSContext* cx,
-                                              const Value& value) {
+[[nodiscard]] inline T* UnwrapAndDowncastValue(JSContext* cx,
+                                               const Value& value) {
   return UnwrapAndDowncastObject<T>(cx, &value.toObject());
 }
 
 /**
  * Unwrap an object of a known (but not compile-time-known) class.  See
  * UnwrapAndDowncastObject.
  */
-inline MOZ_MUST_USE JSObject* UnwrapAndDowncastValue(JSContext* cx,
-                                                     const Value& value,
-                                                     const JSClass* clasp) {
+[[nodiscard]] inline JSObject* UnwrapAndDowncastValue(JSContext* cx,
+                                                      const Value& value,
+                                                      const JSClass* clasp) {
   return UnwrapAndDowncastObject(cx, &value.toObject(), clasp);
 }
 
 /**
  * Read a private slot that is known to point to a particular type of object.
  *
  * Some internal slots specified in various standards effectively have static
  * types. For example, the [[ownerReadableStream]] slot of a stream reader is
@@ -379,19 +381,19 @@ inline MOZ_MUST_USE JSObject* UnwrapAndD
  * the expected type of object. Call this only if the slot is certain to
  * contain either an instance of T, a wrapper for a T, or a dead object.
  *
  * `cx` and `unwrappedObj` are not required to be same-compartment.
  *
  * DANGER: The result may not be same-compartment with either `cx` or `obj`.
  */
 template <class T>
-inline MOZ_MUST_USE T* UnwrapInternalSlot(JSContext* cx,
-                                          Handle<NativeObject*> unwrappedObj,
-                                          uint32_t slot) {
+[[nodiscard]] inline T* UnwrapInternalSlot(JSContext* cx,
+                                           Handle<NativeObject*> unwrappedObj,
+                                           uint32_t slot) {
   static_assert(!std::is_convertible_v<T*, Wrapper*>,
                 "T can't be a Wrapper type; this function discards wrappers");
 
   return UnwrapAndDowncastValue<T>(cx, unwrappedObj->getFixedSlot(slot));
 }
 
 /**
  * Read a function slot that is known to point to a particular type of object.
--- a/js/src/vm/CompilationAndEvaluation.cpp
+++ b/js/src/vm/CompilationAndEvaluation.cpp
@@ -289,17 +289,17 @@ class FunctionCompiler {
     // Remember the position of ")".
     parameterListEnd_ = funStr_.length();
     MOZ_ASSERT(FunctionConstructorMedialSigils[0] == ')');
 
     return funStr_.append(FunctionConstructorMedialSigils);
   }
 
   template <typename Unit>
-  inline MOZ_MUST_USE bool addFunctionBody(const SourceText<Unit>& srcBuf) {
+  [[nodiscard]] inline bool addFunctionBody(const SourceText<Unit>& srcBuf) {
     return funStr_.append(srcBuf.get(), srcBuf.length());
   }
 
   JSFunction* finish(HandleObjectVector envChain,
                      const ReadOnlyCompileOptions& optionsArg) {
     using js::frontend::FunctionSyntaxKind;
 
     if (!funStr_.append(FunctionConstructorFinalBrace)) {
--- a/js/src/vm/ErrorReporting.h
+++ b/js/src/vm/ErrorReporting.h
@@ -91,21 +91,21 @@ extern void ReportCompileErrorUTF8(JSCon
                                    UniquePtr<JSErrorNotes> notes,
                                    unsigned errorNumber, va_list* args);
 
 /**
  * Report a compile warning during script processing prior to execution of the
  * script.  Returns true if the warning was successfully reported, false if an
  * error occurred.
  */
-extern MOZ_MUST_USE bool ReportCompileWarning(JSContext* cx,
-                                              ErrorMetadata&& metadata,
-                                              UniquePtr<JSErrorNotes> notes,
-                                              unsigned errorNumber,
-                                              va_list* args);
+[[nodiscard]] extern bool ReportCompileWarning(JSContext* cx,
+                                               ErrorMetadata&& metadata,
+                                               UniquePtr<JSErrorNotes> notes,
+                                               unsigned errorNumber,
+                                               va_list* args);
 
 class GlobalObject;
 
 /**
  * Report the given error Value to the given global.  The JSContext is not
  * assumed to be in any particular realm, but the global and error are
  * expected to be same-compartment.
  */
--- a/js/src/vm/Iteration.cpp
+++ b/js/src/vm/Iteration.cpp
@@ -864,18 +864,18 @@ static bool CanStoreInIteratorCache(JSOb
     }
 
     obj = obj->staticPrototype();
   } while (obj);
 
   return true;
 }
 
-static MOZ_MUST_USE bool StoreInIteratorCache(JSContext* cx, JSObject* obj,
-                                              PropertyIteratorObject* iterobj) {
+[[nodiscard]] static bool StoreInIteratorCache(
+    JSContext* cx, JSObject* obj, PropertyIteratorObject* iterobj) {
   MOZ_ASSERT(CanStoreInIteratorCache(obj));
 
   NativeIterator* ni = iterobj->getNativeIterator();
   MOZ_ASSERT(ni->guardCount() > 0);
 
   IteratorHashPolicy::Lookup lookup(
       reinterpret_cast<ReceiverGuard*>(ni->guardsBegin()), ni->guardCount(),
       ni->guardKey());
--- a/js/src/vm/JSObject-inl.h
+++ b/js/src/vm/JSObject-inl.h
@@ -202,18 +202,18 @@ class MOZ_RAII AutoSuppressAllocationMet
 // object must be rooted. The usual way to do this would be to make our callers
 // pass a HandleObject, but that would require them to pay the cost of rooting
 // the object unconditionally, even though collecting metadata is rare. Instead,
 // SetNewObjectMetadata's contract is that the caller must use the pointer
 // returned in place of the pointer passed. If a GC occurs, the returned pointer
 // may be the passed pointer, relocated by GC. If no GC could occur, it's just
 // passed through. We root nothing unless necessary.
 template <typename T>
-static MOZ_ALWAYS_INLINE MOZ_MUST_USE T* SetNewObjectMetadata(JSContext* cx,
-                                                              T* obj) {
+[[nodiscard]] static MOZ_ALWAYS_INLINE T* SetNewObjectMetadata(JSContext* cx,
+                                                               T* obj) {
   MOZ_ASSERT(!cx->realm()->hasObjectPendingMetadata());
 
   // The metadata builder is invoked for each object created on the active
   // thread, except when analysis/compilation is active, to avoid recursion.
   if (!cx->isHelperThreadContext()) {
     if (MOZ_UNLIKELY(cx->realm()->hasAllocationMetadataBuilder()) &&
         !cx->zone()->suppressAllocationMetadataBuilder) {
       // Don't collect metadata on objects that represent metadata.
--- a/js/src/vm/JSObject.cpp
+++ b/js/src/vm/JSObject.cpp
@@ -1464,17 +1464,17 @@ bool js::ObjectMayBeSwapped(const JSObje
   }
 
   // WindowProxy, Wrapper, DeadProxyObject, DOMProxy, and DOMClass (non-global)
   // types may be swapped. It is hard to detect DOMProxy from shell, so target
   // proxies in general.
   return clasp->isProxy() || clasp->isDOMClass();
 }
 
-static MOZ_MUST_USE bool CopyProxyValuesBeforeSwap(
+[[nodiscard]] static bool CopyProxyValuesBeforeSwap(
     JSContext* cx, ProxyObject* proxy, MutableHandleValueVector values) {
   MOZ_ASSERT(values.empty());
 
   // Remove the GCPtrValues we're about to swap from the store buffer, to
   // ensure we don't trace bogus values.
   gc::StoreBuffer& sb = cx->runtime()->gc.storeBuffer();
 
   // Reserve space for the expando, private slot and the reserved slots.
--- a/js/src/vm/JSObject.h
+++ b/js/src/vm/JSObject.h
@@ -1018,21 +1018,21 @@ inline bool FreezeObject(JSContext* cx, 
 
 /*
  * ES6 rev 29 (6 Dec 2014) 7.3.14. Code shared by Object.isSealed and
  * Object.isFrozen.
  */
 extern bool TestIntegrityLevel(JSContext* cx, HandleObject obj,
                                IntegrityLevel level, bool* resultp);
 
-extern MOZ_MUST_USE JSObject* SpeciesConstructor(
+[[nodiscard]] extern JSObject* SpeciesConstructor(
     JSContext* cx, HandleObject obj, HandleObject defaultCtor,
     bool (*isDefaultSpecies)(JSContext*, JSFunction*));
 
-extern MOZ_MUST_USE JSObject* SpeciesConstructor(
+[[nodiscard]] extern JSObject* SpeciesConstructor(
     JSContext* cx, HandleObject obj, JSProtoKey ctorKey,
     bool (*isDefaultSpecies)(JSContext*, JSFunction*));
 
 extern bool GetObjectFromIncumbentGlobal(JSContext* cx,
                                          MutableHandleObject obj);
 
 #ifdef DEBUG
 inline bool IsObjectValueInCompartment(const Value& v, JS::Compartment* comp) {
--- a/js/src/vm/JSScript.cpp
+++ b/js/src/vm/JSScript.cpp
@@ -1651,17 +1651,17 @@ ScriptSourceObject* ScriptSourceObject::
 
 ScriptSourceObject* ScriptSourceObject::unwrappedCanonical() const {
   MOZ_ASSERT(CurrentThreadCanAccessRuntime(runtimeFromAnyThread()));
 
   JSObject* obj = &getReservedSlot(CANONICAL_SLOT).toObject();
   return &UncheckedUnwrap(obj)->as<ScriptSourceObject>();
 }
 
-static MOZ_MUST_USE bool MaybeValidateFilename(
+[[nodiscard]] static bool MaybeValidateFilename(
     JSContext* cx, HandleScriptSourceObject sso,
     const ReadOnlyCompileOptions& options) {
   // When parsing off-thread we want to do filename validation on the main
   // thread. This makes off-thread parsing more pure and is simpler because we
   // can't easily throw exceptions off-thread.
   MOZ_ASSERT(!cx->isHelperThreadContext());
 
   if (!gFilenameValidationCallback) {
@@ -2466,17 +2466,17 @@ void ScriptSource::finalizeGCData() {
 ScriptSource::~ScriptSource() {
   MOZ_ASSERT(refs == 0);
 
   // GC pointers must have been cleared earlier, because this destructor could
   // be called off-thread by SweepCompressionTasks. See above.
   MOZ_ASSERT(!xdrEncoder_);
 }
 
-static MOZ_MUST_USE bool reallocUniquePtr(UniqueChars& unique, size_t size) {
+[[nodiscard]] static bool reallocUniquePtr(UniqueChars& unique, size_t size) {
   auto newPtr = static_cast<char*>(js_realloc(unique.get(), size));
   if (!newPtr) {
     return false;
   }
 
   // Since the realloc succeeded, unique is now holding a freed pointer.
   mozilla::Unused << unique.release();
   unique.reset(newPtr);
--- a/js/src/vm/JSScript.h
+++ b/js/src/vm/JSScript.h
@@ -359,17 +359,17 @@ struct SourceTypeTraits<char16_t> {
   }
 
   static UniqueTwoByteChars toCacheable(EntryUnits<char16_t> str) {
     return UniqueTwoByteChars(std::move(str));
   }
 };
 
 // Synchronously compress the source of |script|, for testing purposes.
-extern MOZ_MUST_USE bool SynchronouslyCompressSource(
+[[nodiscard]] extern bool SynchronouslyCompressSource(
     JSContext* cx, JS::Handle<BaseScript*> script);
 
 // Retrievable source can be retrieved using the source hook (and therefore
 // need not be XDR'd, can be discarded if desired because it can always be
 // reconstituted later, etc.).
 enum class SourceRetrievable { Yes, No };
 
 // [SMDOC] ScriptSource
@@ -1058,34 +1058,34 @@ class ScriptSource {
 
  private:
   template <typename Unit,
             template <typename U, SourceRetrievable CanRetrieve> class Data,
             XDRMode mode>
   static void codeRetrievable(ScriptSource* ss);
 
   template <typename Unit, XDRMode mode>
-  static MOZ_MUST_USE XDRResult codeUncompressedData(XDRState<mode>* const xdr,
-                                                     ScriptSource* const ss);
+  [[nodiscard]] static XDRResult codeUncompressedData(XDRState<mode>* const xdr,
+                                                      ScriptSource* const ss);
 
   template <typename Unit, XDRMode mode>
-  static MOZ_MUST_USE XDRResult codeCompressedData(XDRState<mode>* const xdr,
-                                                   ScriptSource* const ss);
+  [[nodiscard]] static XDRResult codeCompressedData(XDRState<mode>* const xdr,
+                                                    ScriptSource* const ss);
 
   template <typename Unit, XDRMode mode>
   static void codeRetrievableData(ScriptSource* ss);
 
   template <XDRMode mode>
-  static MOZ_MUST_USE XDRResult xdrData(XDRState<mode>* const xdr,
-                                        ScriptSource* const ss);
+  [[nodiscard]] static XDRResult xdrData(XDRState<mode>* const xdr,
+                                         ScriptSource* const ss);
 
  public:
   template <XDRMode mode>
-  static MOZ_MUST_USE XDRResult
-  XDR(XDRState<mode>* xdr, const JS::ReadOnlyCompileOptions* maybeOptions,
+  [[nodiscard]] static XDRResult XDR(
+      XDRState<mode>* xdr, const JS::ReadOnlyCompileOptions* maybeOptions,
       RefPtr<ScriptSource>& source);
 };
 
 // [SMDOC] ScriptSourceObject
 //
 // ScriptSourceObject stores the ScriptSource and GC pointers related to it.
 //
 // ScriptSourceObjects can be cloned when we clone the JSScript (in order to
@@ -1340,21 +1340,21 @@ class alignas(uintptr_t) PrivateScriptDa
   const MemberInitializers& getMemberInitializers() {
     return memberInitializers_;
   }
 
   // Allocate a new PrivateScriptData. Headers and GCCellPtrs are initialized.
   static PrivateScriptData* new_(JSContext* cx, uint32_t ngcthings);
 
   template <XDRMode mode>
-  static MOZ_MUST_USE XDRResult XDR(js::XDRState<mode>* xdr,
-                                    js::HandleScript script,
-                                    js::HandleScriptSourceObject sourceObject,
-                                    js::HandleScope scriptEnclosingScope,
-                                    js::HandleObject funOrMod);
+  [[nodiscard]] static XDRResult XDR(js::XDRState<mode>* xdr,
+                                     js::HandleScript script,
+                                     js::HandleScriptSourceObject sourceObject,
+                                     js::HandleScope scriptEnclosingScope,
+                                     js::HandleObject funOrMod);
 
   // Clone src script data into dst script.
   static bool Clone(JSContext* cx, js::HandleScript src, js::HandleScript dst,
                     js::MutableHandle<JS::GCVector<js::Scope*>> scopes);
 
   static bool InitFromStencil(
       JSContext* cx, js::HandleScript script,
       const js::frontend::CompilationInput& input,
--- a/js/src/vm/List-inl.h
+++ b/js/src/vm/List-inl.h
@@ -89,34 +89,34 @@ inline T& js::ListObject::popFirstAs(JSC
   return popFirst(cx).toObject().as<T>();
 }
 
 namespace js {
 
 /**
  * Stores an empty ListObject in the given fixed slot of |obj|.
  */
-inline MOZ_MUST_USE bool StoreNewListInFixedSlot(JSContext* cx,
-                                                 JS::Handle<NativeObject*> obj,
-                                                 uint32_t slot) {
+[[nodiscard]] inline bool StoreNewListInFixedSlot(JSContext* cx,
+                                                  JS::Handle<NativeObject*> obj,
+                                                  uint32_t slot) {
   AutoRealm ar(cx, obj);
   ListObject* list = ListObject::create(cx);
   if (!list) {
     return false;
   }
 
   obj->setFixedSlot(slot, JS::ObjectValue(*list));
   return true;
 }
 
 /**
  * Given an object |obj| whose fixed slot |slot| contains a ListObject, append
  * |toAppend| to that list.
  */
-inline MOZ_MUST_USE bool AppendToListInFixedSlot(
+[[nodiscard]] inline bool AppendToListInFixedSlot(
     JSContext* cx, JS::Handle<NativeObject*> obj, uint32_t slot,
     JS::Handle<JSObject*> toAppend) {
   JS::Rooted<ListObject*> list(
       cx, &obj->getFixedSlot(slot).toObject().as<ListObject>());
 
   AutoRealm ar(cx, list);
   JS::Rooted<JS::Value> val(cx, JS::ObjectValue(*toAppend));
   if (!cx->compartment()->wrap(cx, &val)) {
--- a/js/src/vm/List.h
+++ b/js/src/vm/List.h
@@ -28,45 +28,45 @@ namespace js {
  * case where its internal queue never holds more than one element.
  *
  * ListObjects must not be exposed to content scripts.
  */
 class ListObject : public NativeObject {
  public:
   static const JSClass class_;
 
-  inline static MOZ_MUST_USE ListObject* create(JSContext* cx);
+  [[nodiscard]] inline static ListObject* create(JSContext* cx);
 
   uint32_t length() const { return getDenseInitializedLength(); }
 
   bool isEmpty() const { return length() == 0; }
 
   const Value& get(uint32_t index) const { return getDenseElement(index); }
 
   template <class T>
   T& getAs(uint32_t index) const {
     return get(index).toObject().as<T>();
   }
 
   /**
    * Add an element to the end of the list. Returns false on OOM.
    */
-  inline MOZ_MUST_USE bool append(JSContext* cx, HandleValue value);
+  [[nodiscard]] inline bool append(JSContext* cx, HandleValue value);
 
   /**
    * Adds |value| and |size| elements to a list consisting of (value, size)
    * pairs stored in successive elements.
    *
    * This function is intended for use by streams code's queue-with-sizes data
    * structure and related operations.  See builtin/streams/QueueWithSizes*.
    * (You *could* use this on any list of even length without issue, but it's
    * hard to imagine realistic situations where you'd want to...)
    */
-  inline MOZ_MUST_USE bool appendValueAndSize(JSContext* cx, HandleValue value,
-                                              double size);
+  [[nodiscard]] inline bool appendValueAndSize(JSContext* cx, HandleValue value,
+                                               double size);
 
   /**
    * Remove and return the first element of the list.
    *
    * Precondition: This list is not empty.
    */
   inline JS::Value popFirst(JSContext* cx);
 
--- a/js/src/vm/NativeObject-inl.h
+++ b/js/src/vm/NativeObject-inl.h
@@ -741,17 +741,17 @@ static MOZ_ALWAYS_INLINE bool LookupOwnP
   *donep = false;
   return true;
 }
 
 /*
  * Simplified version of LookupOwnPropertyInline that doesn't call resolve
  * hooks.
  */
-static inline MOZ_MUST_USE bool NativeLookupOwnPropertyNoResolve(
+[[nodiscard]] static inline bool NativeLookupOwnPropertyNoResolve(
     JSContext* cx, HandleNativeObject obj, HandleId id,
     MutableHandle<PropertyResult> result) {
   // Check for a native dense element.
   if (JSID_IS_INT(id)) {
     uint32_t index = JSID_TO_INT(id);
     if (obj->containsDenseElement(index)) {
       result.setDenseElement(index);
       return true;
--- a/js/src/vm/NativeObject.h
+++ b/js/src/vm/NativeObject.h
@@ -367,18 +367,18 @@ class ObjectElements {
            int(sizeof(ObjectElements));
   }
   static int offsetOfLength() {
     return int(offsetof(ObjectElements, length)) - int(sizeof(ObjectElements));
   }
 
   static void PrepareForPreventExtensions(JSContext* cx, NativeObject* obj);
   static void PreventExtensions(NativeObject* obj);
-  static MOZ_MUST_USE bool FreezeOrSeal(JSContext* cx, HandleNativeObject obj,
-                                        IntegrityLevel level);
+  [[nodiscard]] static bool FreezeOrSeal(JSContext* cx, HandleNativeObject obj,
+                                         IntegrityLevel level);
 
   bool isSealed() const { return flags & SEALED; }
 
   bool isPacked() const { return !(flags & NON_PACKED); }
 
   uint8_t elementAttributes() const {
     if (isFrozen()) {
       return JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY;
@@ -628,18 +628,18 @@ class NativeObject : public JSObject {
   inline bool canRemoveLastProperty();
 
   /*
    * Update the slot span directly for a dictionary object, and allocate
    * slots to cover the new span if necessary.
    */
   bool ensureSlotsForDictionaryObject(JSContext* cx, uint32_t span);
 
-  static MOZ_MUST_USE bool toDictionaryMode(JSContext* cx,
-                                            HandleNativeObject obj);
+  [[nodiscard]] static bool toDictionaryMode(JSContext* cx,
+                                             HandleNativeObject obj);
 
  private:
   inline void setEmptyDynamicSlots(uint32_t dictonarySlotSpan);
 
   inline void setDictionaryModeSlotSpan(uint32_t span);
 
   friend class TenuringTracer;
 
@@ -739,25 +739,25 @@ class NativeObject : public JSObject {
  public:
   /* Object allocation may directly initialize slots so this is public. */
   void initSlots(HeapSlot* slots) {
     MOZ_ASSERT(slots);
     slots_ = slots;
   }
   inline void initEmptyDynamicSlots();
 
-  static MOZ_MUST_USE bool generateOwnShape(JSContext* cx,
-                                            HandleNativeObject obj,
-                                            Shape* newShape = nullptr) {
+  [[nodiscard]] static bool generateOwnShape(JSContext* cx,
+                                             HandleNativeObject obj,
+                                             Shape* newShape = nullptr) {
     return replaceWithNewEquivalentShape(cx, obj, obj->lastProperty(),
                                          newShape);
   }
 
-  static MOZ_MUST_USE bool reshapeForShadowedProp(JSContext* cx,
-                                                  HandleNativeObject obj);
+  [[nodiscard]] static bool reshapeForShadowedProp(JSContext* cx,
+                                                   HandleNativeObject obj);
   static bool clearFlag(JSContext* cx, HandleNativeObject obj,
                         BaseShape::Flag flag);
 
   // The maximum number of slots in an object.
   // |MAX_SLOTS_COUNT * sizeof(JS::Value)| shouldn't overflow
   // int32_t (see slotsSizeMustNotOverflow).
   static const uint32_t MAX_SLOTS_COUNT = (1 << 28) - 1;
 
@@ -983,21 +983,21 @@ class NativeObject : public JSObject {
                                         ShapeTable::Entry* entry,
                                         const AutoKeepShapeCaches& keep);
 
   static Shape* addAccessorPropertyInternal(
       JSContext* cx, HandleNativeObject obj, HandleId id, JSGetterOp getter,
       JSSetterOp setter, unsigned attrs, ShapeTable* table,
       ShapeTable::Entry* entry, const AutoKeepShapeCaches& keep);
 
-  static MOZ_MUST_USE bool fillInAfterSwap(JSContext* cx,
-                                           HandleNativeObject obj,
-                                           NativeObject* old,
-                                           HandleValueVector values,
-                                           void* priv);
+  [[nodiscard]] static bool fillInAfterSwap(JSContext* cx,
+                                            HandleNativeObject obj,
+                                            NativeObject* old,
+                                            HandleValueVector values,
+                                            void* priv);
 
  public:
   // Return true if this object has been converted from shared-immutable
   // prototype-rooted shape storage to dictionary-shapes in a doubly-linked
   // list.
   bool inDictionaryMode() const { return lastProperty()->inDictionary(); }
 
   const Value& getSlot(uint32_t slot) const {
@@ -1321,18 +1321,18 @@ class NativeObject : public JSObject {
   // Preconditions: This must be a boring ArrayObject with dense initialized
   // length 0: no shifted elements, no frozen elements, no fixed "length", not
   // indexed, not inextensible, not copy-on-write. Existing capacity is
   // optional.
   //
   // This runs write barriers but does not update types. `end - begin` must
   // return the size of the range, which must be >= 0 and fit in an int32_t.
   template <typename Iter>
-  inline MOZ_MUST_USE bool initDenseElementsFromRange(JSContext* cx, Iter begin,
-                                                      Iter end);
+  [[nodiscard]] inline bool initDenseElementsFromRange(JSContext* cx,
+                                                       Iter begin, Iter end);
 
   inline void moveDenseElements(uint32_t dstStart, uint32_t srcStart,
                                 uint32_t count);
   inline void reverseDenseElementsNoPreBarrier(uint32_t length);
 
   inline DenseElementResult setOrExtendDenseElements(JSContext* cx,
                                                      uint32_t start,
                                                      const Value* vp,
--- a/js/src/vm/PromiseObject.h
+++ b/js/src/vm/PromiseObject.h
@@ -162,22 +162,22 @@ class PromiseObject : public NativeObjec
     return getFixedSlot(PromiseSlot_ReactionsOrResult);
   }
 
   JS::Value valueOrReason() {
     MOZ_ASSERT(state() != JS::PromiseState::Pending);
     return getFixedSlot(PromiseSlot_ReactionsOrResult);
   }
 
-  static MOZ_MUST_USE bool resolve(JSContext* cx,
+  [[nodiscard]] static bool resolve(JSContext* cx,
+                                    JS::Handle<PromiseObject*> promise,
+                                    JS::Handle<JS::Value> resolutionValue);
+  [[nodiscard]] static bool reject(JSContext* cx,
                                    JS::Handle<PromiseObject*> promise,
-                                   JS::Handle<JS::Value> resolutionValue);
-  static MOZ_MUST_USE bool reject(JSContext* cx,
-                                  JS::Handle<PromiseObject*> promise,
-                                  JS::Handle<JS::Value> rejectionValue);
+                                   JS::Handle<JS::Value> rejectionValue);
 
   static void onSettled(JSContext* cx, JS::Handle<PromiseObject*> promise,
                         JS::Handle<js::SavedFrame*> rejectionStack);
 
   double allocationTime();
   double resolutionTime();
   JSObject* allocationSite();
   JSObject* resolutionSite();
--- a/js/src/vm/RegExpObject.h
+++ b/js/src/vm/RegExpObject.h
@@ -161,19 +161,19 @@ class RegExpObject : public NativeObject
 
   // NOTE: This method is *only* safe to call on RegExps that haven't been
   //       exposed to script, because it requires that the "lastIndex"
   //       property be writable.
   void initAndZeroLastIndex(JSAtom* source, JS::RegExpFlags flags,
                             JSContext* cx);
 
 #ifdef DEBUG
-  static MOZ_MUST_USE bool dumpBytecode(JSContext* cx,
-                                        Handle<RegExpObject*> regexp,
-                                        HandleLinearString input);
+  [[nodiscard]] static bool dumpBytecode(JSContext* cx,
+                                         Handle<RegExpObject*> regexp,
+                                         HandleLinearString input);
 #endif
 
  private:
   /*
    * Precondition: the syntax for |source| has already been validated.
    * Side effect: sets the private field.
    */
   static RegExpShared* createShared(JSContext* cx,
--- a/js/src/vm/SavedFrame.h
+++ b/js/src/vm/SavedFrame.h
@@ -108,19 +108,19 @@ class SavedFrame : public NativeObject {
   struct Lookup;
   struct HashPolicy;
 
   typedef JS::GCHashSet<WeakHeapPtr<SavedFrame*>, HashPolicy, SystemAllocPolicy>
       Set;
 
  private:
   static SavedFrame* create(JSContext* cx);
-  static MOZ_MUST_USE bool finishSavedFrameInit(JSContext* cx,
-                                                HandleObject ctor,
-                                                HandleObject proto);
+  [[nodiscard]] static bool finishSavedFrameInit(JSContext* cx,
+                                                 HandleObject ctor,
+                                                 HandleObject proto);
   void initFromLookup(JSContext* cx, Handle<Lookup> lookup);
   void initSource(JSAtom* source);
   void initSourceId(uint32_t id);
   void initLine(uint32_t line);
   void initColumn(uint32_t column);
   void initFunctionDisplayName(JSAtom* maybeName);
   void initAsyncCause(JSAtom* maybeCause);
   void initParent(SavedFrame* maybeParent);
--- a/js/src/vm/SavedStacks.cpp
+++ b/js/src/vm/SavedStacks.cpp
@@ -679,19 +679,19 @@ JS_FRIEND_API JSObject* GetFirstSubsumed
   };
 
   bool skippedAsync;
   RootedSavedFrame frame(cx, &savedFrame->as<SavedFrame>());
   return GetFirstMatchedFrame(cx, principals, matcher, frame, selfHosted,
                               skippedAsync);
 }
 
-static MOZ_MUST_USE bool SavedFrame_checkThis(JSContext* cx, CallArgs& args,
-                                              const char* fnName,
-                                              MutableHandleObject frame) {
+[[nodiscard]] static bool SavedFrame_checkThis(JSContext* cx, CallArgs& args,
+                                               const char* fnName,
+                                               MutableHandleObject frame) {
   const Value& thisValue = args.thisv();
 
   if (!thisValue.isObject()) {
     JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
                               JSMSG_OBJECT_REQUIRED,
                               InformalValueTypeName(thisValue));
     return false;
   }
--- a/js/src/vm/Shape.h
+++ b/js/src/vm/Shape.h
@@ -1004,20 +1004,20 @@ class Shape : public gc::CellWithTenured
   void setDictionaryNextPtr(DictionaryShapeLink next);
   void clearDictionaryNextPtr();
   void dictNextPreWriteBarrier();
 
   template <MaybeAdding Adding = MaybeAdding::NotAdding>
   static MOZ_ALWAYS_INLINE Shape* search(JSContext* cx, Shape* start, jsid id);
 
   template <MaybeAdding Adding = MaybeAdding::NotAdding>
-  static inline MOZ_MUST_USE bool search(JSContext* cx, Shape* start, jsid id,
-                                         const AutoKeepShapeCaches&,
-                                         Shape** pshape, ShapeTable** ptable,
-                                         ShapeTable::Entry** pentry);
+  [[nodiscard]] static inline bool search(JSContext* cx, Shape* start, jsid id,
+                                          const AutoKeepShapeCaches&,
+                                          Shape** pshape, ShapeTable** ptable,
+                                          ShapeTable::Entry** pentry);
 
   static inline Shape* searchNoHashify(Shape* start, jsid id);
 
   void removeFromDictionary(NativeObject* obj);
   void insertIntoDictionaryBefore(DictionaryShapeLink next);
 
   inline void initDictionaryShape(const StackShape& child, uint32_t nfixed,
                                   DictionaryShapeLink next);
@@ -1048,17 +1048,17 @@ class Shape : public gc::CellWithTenured
     if (base()->isOwned()) {
       return true;
     }
     return makeOwnBaseShape(cx);
   }
 
   bool makeOwnBaseShape(JSContext* cx);
 
-  MOZ_ALWAYS_INLINE MOZ_MUST_USE bool maybeCreateCacheForLookup(JSContext* cx);
+  [[nodiscard]] MOZ_ALWAYS_INLINE bool maybeCreateCacheForLookup(JSContext* cx);
 
   MOZ_ALWAYS_INLINE void updateDictionaryTable(ShapeTable* table,
                                                ShapeTable::Entry* entry,
                                                const AutoKeepShapeCaches& keep);
 
  public:
   bool hasTable() const { return base()->hasTable(); }
   bool hasIC() const { return base()->hasIC(); }