Bug 1321014 - Respect MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS for the purpose of identifying GC types and pointers, r=jonco
☠☠ backed out by f2e06bf4ba8e ☠ ☠
authorSteve Fink <sfink@mozilla.com>
Fri, 20 Jul 2018 18:36:20 -0700
changeset 489834 c7b32ffa822e353b5479b6224194e3cdfd135e65
parent 489833 a188327354ab83702eb9c2fec439f3a7cc019883
child 489835 c22b643cdf5168be413948a2437584426bfd8c06
push id247
push userfmarier@mozilla.com
push dateSat, 27 Oct 2018 01:06:44 +0000
reviewersjonco
bugs1321014
milestone64.0a1
Bug 1321014 - Respect MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS for the purpose of identifying GC types and pointers, r=jonco
browser/config/mozconfigs/linux64/hazards
js/public/GCAnnotations.h
js/public/StableStringChars.h
js/public/Utility.h
js/public/Value.h
js/src/devtools/rootAnalysis/computeGCTypes.js
js/src/devtools/rootAnalysis/mozconfig.haz
js/src/devtools/rootAnalysis/t/hazards/source.cpp
js/src/devtools/rootAnalysis/t/hazards/test.py
layout/base/AccessibleCaret.h
layout/base/gtest/TestAccessibleCaretEventHub.cpp
layout/base/gtest/TestAccessibleCaretManager.cpp
mfbt/Attributes.h
mfbt/CheckedInt.h
taskcluster/scripts/builder/hazard-browser.sh
--- a/browser/config/mozconfigs/linux64/hazards
+++ b/browser/config/mozconfigs/linux64/hazards
@@ -31,15 +31,18 @@ mk_add_options MOZ_OBJDIR=obj-analyzed
 ac_add_options --enable-debug
 ac_add_options --enable-tests
 ac_add_options --enable-optimize
 ac_add_options --with-compiler-wrapper=$TOOLTOOL_DIR/sixgill/usr/libexec/sixgill/scripts/wrap_gcc/basecc
 ac_add_options --without-ccache
 
 ac_add_options --disable-replace-malloc
 
-CFLAGS="$CFLAGS -Wno-attributes"
-CPPFLAGS="$CPPFLAGS -Wno-attributes"
-CXXFLAGS="$CXXFLAGS -Wno-attributes"
+# -Wattributes is very verbose due to attributes being ignored on template
+# instantiations. -Wignored-attributes is very verbose due to attributes being
+# ignored on template parameters.
+CFLAGS="$CFLAGS -Wno-attributes -Wno-ignored-attributes"
+CPPFLAGS="$CPPFLAGS -Wno-attributes -Wno-ignored-attributes"
+CXXFLAGS="$CXXFLAGS -Wno-attributes -Wno-ignored-attributes"
 
 NODEJS="$TOOLTOOL_DIR/node/bin/node"
 
 . "$topsrcdir/build/mozconfig.common.override"
--- a/js/public/GCAnnotations.h
+++ b/js/public/GCAnnotations.h
@@ -10,25 +10,28 @@
 // Set of annotations for the rooting hazard analysis, used to categorize types
 // and functions.
 #ifdef XGILL_PLUGIN
 
 // Mark a type as being a GC thing (eg js::gc::Cell has this annotation).
 # define JS_HAZ_GC_THING __attribute__((annotate("GC Thing")))
 
 // Mark a type as holding a pointer to a GC thing (eg JS::Value has this
-// annotation.)
+// annotation.) "Inherited" by templatized types with
+// MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS.
 # define JS_HAZ_GC_POINTER __attribute__((annotate("GC Pointer")))
 
 // Mark a type as a rooted pointer, suitable for use on the stack (eg all
-// Rooted<T> instantiations should have this.)
+// Rooted<T> instantiations should have this.) "Inherited" by templatized types with
+// MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS.
 # define JS_HAZ_ROOTED __attribute__((annotate("Rooted Pointer")))
 
 // Mark a type as something that should not be held live across a GC, but which
-// is not itself a GC pointer.
+// is not itself a GC pointer. Note that this property is *not* inherited by
+// templatized types with MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS.
 # define JS_HAZ_GC_INVALIDATED __attribute__((annotate("Invalidated by GC")))
 
 // Mark a class as a base class of rooted types, eg CustomAutoRooter. All
 // descendants of this class will be considered rooted, though classes that
 // merely contain these as a field member will not be. "Inherited" by
 // templatized types with MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS
 # define JS_HAZ_ROOTED_BASE __attribute__((annotate("Rooted Base")))
 
--- a/js/public/StableStringChars.h
+++ b/js/public/StableStringChars.h
@@ -51,17 +51,17 @@ class MOZ_STACK_CLASS JS_FRIEND_API(Auto
      * When copying string char, use this many bytes of inline storage.  This is
      * chosen to allow the inline string types to be copied without allocating.
      * This is asserted in AutoStableStringChars::allocOwnChars.
      */
     static const size_t InlineCapacity = 24;
 
     /* Ensure the string is kept alive while we're using its chars. */
     Rooted<JSString*> s_;
-    MOZ_INIT_OUTSIDE_CTOR union {
+    union MOZ_INIT_OUTSIDE_CTOR {
         const char16_t* twoByteChars_;
         const Latin1Char* latin1Chars_;
     };
     mozilla::Maybe<js::Vector<uint8_t, InlineCapacity>> ownChars_;
     enum State { Uninitialized, Latin1, TwoByte };
     State state_;
 
   public:
--- a/js/public/Utility.h
+++ b/js/public/Utility.h
@@ -506,17 +506,17 @@ static inline void js_free(void* p)
  * JS_DECLARE_NEW_METHODS (see js::MallocProvider for an example).
  *
  * Note: Do not add a ; at the end of a use of JS_DECLARE_NEW_METHODS,
  * or the build will break.
  */
 #define JS_DECLARE_NEW_METHODS(NEWNAME, ALLOCATOR, QUALIFIERS) \
     template <class T, typename... Args> \
     QUALIFIERS T * \
-    NEWNAME(Args&&... args) MOZ_HEAP_ALLOCATOR { \
+    MOZ_HEAP_ALLOCATOR NEWNAME(Args&&... args) { \
         void* memory = ALLOCATOR(sizeof(T)); \
         return MOZ_LIKELY(memory) \
             ? new(memory) T(std::forward<Args>(args)...) \
             : nullptr; \
     }
 
 /*
  * Given a class which should provide 'make' methods, add
@@ -526,17 +526,17 @@ static inline void js_free(void* p)
  * ownership of the created object.
  *
  * Note: Do not add a ; at the end of a use of JS_DECLARE_MAKE_METHODS,
  * or the build will break.
  */
 #define JS_DECLARE_MAKE_METHODS(MAKENAME, NEWNAME, QUALIFIERS)\
     template <class T, typename... Args> \
     QUALIFIERS mozilla::UniquePtr<T, JS::DeletePolicy<T>> \
-    MAKENAME(Args&&... args) MOZ_HEAP_ALLOCATOR { \
+    MOZ_HEAP_ALLOCATOR MAKENAME(Args&&... args) { \
         T* ptr = NEWNAME<T>(std::forward<Args>(args)...); \
         return mozilla::UniquePtr<T, JS::DeletePolicy<T>>(ptr); \
     }
 
 JS_DECLARE_NEW_METHODS(js_new, js_malloc, static MOZ_ALWAYS_INLINE)
 
 namespace js {
 
--- a/js/public/Value.h
+++ b/js/public/Value.h
@@ -311,17 +311,17 @@ CanonicalizeNaN(double d)
  *   that toString, toObject, toSymbol will return an invalid pointer (because
  *   some high bits will be set) when called on a Value with a different type
  *   tag.
  *
  * - On 32-bit platforms,when unboxing an object/string/symbol Value, we use a
  *   conditional move (not speculated) to zero the payload register if the type
  *   doesn't match.
  */
-union MOZ_NON_PARAM alignas(8) Value
+union alignas(8) Value
 {
   private:
     uint64_t asBits_;
     double asDouble_;
 
 #if defined(JS_PUNBOX64) && !defined(_WIN64)
     // MSVC doesn't pack these correctly :-(
     struct {
@@ -924,17 +924,17 @@ union MOZ_NON_PARAM alignas(8) Value
         MOZ_ASSERT((((uintptr_t)cell) >> JSVAL_TAG_SHIFT) == 0);
 #endif
         asBits_ = bitsFromTagAndPayload(JSVAL_TAG_PRIVATE_GCTHING, PayloadType(cell));
     }
 
     bool isPrivateGCThing() const {
         return toTag() == JSVAL_TAG_PRIVATE_GCTHING;
     }
-} JS_HAZ_GC_POINTER;
+} JS_HAZ_GC_POINTER MOZ_NON_PARAM;
 
 static_assert(sizeof(Value) == 8,
               "Value size must leave three tag bits, be a binary power, and "
               "is ubiquitously depended upon everywhere");
 
 inline bool
 IsOptimizedPlaceholderMagicValue(const Value& v)
 {
--- a/js/src/devtools/rootAnalysis/computeGCTypes.js
+++ b/js/src/devtools/rootAnalysis/computeGCTypes.js
@@ -6,21 +6,23 @@ loadRelativeToScript('utility.js');
 loadRelativeToScript('annotations.js');
 
 var gcTypes_filename = scriptArgs[0] || "gcTypes.txt";
 var typeInfo_filename = scriptArgs[1] || "typeInfo.txt";
 
 var typeInfo = {
     'GCPointers': [],
     'GCThings': [],
+    'GCInvalidated': [],
     'NonGCTypes': {}, // unused
     'NonGCPointers': {},
     'RootedGCThings': {},
     'RootedPointers': {},
     'RootedBases': {'JS::AutoGCRooter': true},
+    'InheritFromTemplateArgs': {},
 
     // RAII types within which we should assume GC is suppressed, eg
     // AutoSuppressGC.
     'GCSuppressors': {},
 };
 
 var gDescriptors = new Map; // Map from descriptor string => Set of typeName
 
@@ -39,27 +41,29 @@ function processCSU(csu, body)
 {
     for (let { 'Name': [ annType, tag ] } of (body.Annotation || [])) {
         if (annType != 'annotate')
             continue;
 
         if (tag == 'GC Pointer')
             typeInfo.GCPointers.push(csu);
         else if (tag == 'Invalidated by GC')
-            typeInfo.GCPointers.push(csu);
+            typeInfo.GCInvalidated.push(csu);
         else if (tag == 'GC Thing')
             typeInfo.GCThings.push(csu);
         else if (tag == 'Suppressed GC Pointer')
             typeInfo.NonGCPointers[csu] = true;
         else if (tag == 'Rooted Pointer')
             typeInfo.RootedPointers[csu] = true;
         else if (tag == 'Rooted Base')
             typeInfo.RootedBases[csu] = true;
         else if (tag == 'Suppress GC')
             typeInfo.GCSuppressors[csu] = true;
+        else if (tag == 'moz_inherit_type_annotations_from_template_args')
+            typeInfo.InheritFromTemplateArgs[csu] = true;
     }
 
     for (let { 'Base': base } of (body.CSUBaseClass || []))
         addBaseClass(csu, base);
 
     for (let field of (body.DataField || [])) {
         var type = field.Field.Type;
         var fieldName = field.Field.Name[0];
@@ -134,16 +138,57 @@ for (const typename of extraRootedPointe
     typeInfo.RootedPointers[typename] = true;
 
 // Now that we have the whole hierarchy set up, add all the types and propagate
 // info.
 for (const csu of typeInfo.GCThings)
     addGCType(csu);
 for (const csu of typeInfo.GCPointers)
     addGCPointer(csu);
+for (const csu of typeInfo.GCInvalidated)
+    addGCPointer(csu);
+
+// GC Thing and GC Pointer annotations can be inherited from template args if
+// this annotation is used. Think of Maybe<T> for example: Maybe<JSObject*> has
+// the same GC rules as JSObject*. But this needs to be done in a conservative
+// direction: Maybe<AutoSuppressGC> should not be regarding as suppressing GC
+// (because it might still be None).
+//
+// Note that there is an order-dependence here that is being mostly ignored (eg
+// Maybe<Maybe<Cell*>> -- if that is processed before Maybe<Cell*> is
+// processed, we won't get the right answer). We'll at least sort by string
+// length to make it hard to hit that case.
+var inheritors = Object.keys(typeInfo.InheritFromTemplateArgs).sort((a, b) => a.length - b.length);
+for (const csu of inheritors) {
+    // Unfortunately, we just have a string type name, not the full structure
+    // of a templatized type, so we will have to resort to loose (buggy)
+    // pattern matching.
+    //
+    // Currently, the simplest ways I know of to break this are:
+    //
+    //   foo<T>::bar<U>
+    //   foo<bar<T,U>>
+    //
+    const [_, params_str] = csu.match(/<(.*)>/);
+    for (let param of params_str.split(",")) {
+        param = param.replace(/^\s+/, '')
+        param = param.replace(/\s+$/, '')
+        const pieces = param.split("*");
+        const core_type = pieces[0];
+        const ptrdness = pieces.length - 1;
+        if (ptrdness > 1)
+            continue;
+        const paramDesc = 'template-param-' + param;
+        const why = '(inherited annotations from ' + param + ')';
+        if (typeInfo.GCThings.indexOf(core_type) != -1)
+            markGCType(csu, paramDesc, why, ptrdness, 0, "");
+        if (typeInfo.GCPointers.indexOf(core_type) != -1)
+            markGCType(csu, paramDesc, why, ptrdness + 1, 0, "");
+    }
+}
 
 // Everything that inherits from a "Rooted Base" is considered to be rooted.
 // This is for things like CustomAutoRooter and its subclasses.
 var basework = Object.keys(typeInfo.RootedBases);
 while (basework.length) {
     const base = basework.pop();
     typeInfo.RootedPointers[base] = true;
     if (base in subClasses)
new file mode 100644
--- /dev/null
+++ b/js/src/devtools/rootAnalysis/mozconfig.haz
@@ -0,0 +1,46 @@
+# This mozconfig is used when compiling the browser for the rooting hazard
+# analysis build (labeled H on treeherder). See
+# https://wiki.mozilla.org/Javascript:SpiderMonkey:ExactStackRooting
+
+# Do NOT include build/unix/mozconfig.linux because it points directly at the
+# tooltool-installed gcc, and the analysis works by wrapping the gcc invocation
+# with a script that invokes the real gcc with -fplugin and its configuration
+# directives. Instead, duplicate the contents of that mozconfig here:
+
+MOZ_HAZARD=1
+
+# Skip as many non-compile steps as we can.
+MOZ_AUTOMATION_BUILD_SYMBOLS=0
+MOZ_AUTOMATION_L10N_CHECK=0
+MOZ_AUTOMATION_PACKAGE=0
+MOZ_AUTOMATION_PACKAGE_TESTS=0
+MOZ_AUTOMATION_UPLOAD=0
+
+ac_add_options --enable-js-shell
+
+# The objdir must be at a known location so its path can be stripped from the
+# filenames stored by the analysis
+mk_add_options MOZ_OBJDIR=obj-analyzed
+
+export LLVM_CONFIG=$TOOLTOOL_DIR/clang/bin/llvm-config
+export CBINDGEN="${TOOLTOOL_DIR}/cbindgen/cbindgen"
+
+# The configuration options are chosen to compile the most code
+# (--enable-debug, --enable-tests) in the trickiest way possible
+# (--enable-optimize) to maximize the chance of seeing tricky static orderings.
+ac_add_options --enable-debug
+ac_add_options --enable-tests
+ac_add_options --enable-optimize
+ac_add_options --with-compiler-wrapper=$TOOLTOOL_DIR/sixgill/usr/libexec/sixgill/scripts/wrap_gcc/basecc
+ac_add_options --without-ccache
+
+ac_add_options --disable-replace-malloc
+
+# -Wattributes is very verbose due to attributes being ignored on template
+# instantiations. -Wignored-attributes is very verbose due to attributes being
+# ignored on template parameters.
+CFLAGS="$CFLAGS -Wno-attributes -Wno-ignored-attributes"
+CPPFLAGS="$CPPFLAGS -Wno-attributes -Wno-ignored-attributes"
+CXXFLAGS="$CXXFLAGS -Wno-attributes -Wno-ignored-attributes"
+
+NODEJS="$TOOLTOOL_DIR/node/bin/node"
--- a/js/src/devtools/rootAnalysis/t/hazards/source.cpp
+++ b/js/src/devtools/rootAnalysis/t/hazards/source.cpp
@@ -1,12 +1,17 @@
 #define ANNOTATE(property) __attribute__((annotate(property)))
 
 struct Cell { int f; } ANNOTATE("GC Thing");
 
+template<typename T, typename U>
+struct UntypedContainer {
+    char data[sizeof(T) + sizeof(U)];
+} ANNOTATE("moz_inherit_type_annotations_from_template_args");
+
 struct RootedCell { RootedCell(Cell*) {} } ANNOTATE("Rooted Pointer");
 
 class AutoSuppressGC_Base {
   public:
     AutoSuppressGC_Base() {}
     ~AutoSuppressGC_Base() {}
 } ANNOTATE("Suppress GC");
 
@@ -52,16 +57,22 @@ struct GCInDestructor {
     ~GCInDestructor() {
         invisible();
         asm("");
         *xp = 4;
         GC();
     }
 };
 
+template <typename T>
+void
+usecontainer(T* value) {
+    if (value) asm("");
+}
+
 Cell*
 f()
 {
     GCInDestructor kaboom;
 
     Cell cell;
     Cell* cell1 = &cell;
     Cell* cell2 = &cell;
@@ -80,16 +91,33 @@ f()
         // Old bug: it would look from the first AutoSuppressGC constructor it
         // found to the last destructor. This statement *should* have no effect.
         AutoSuppressGC nogc;
     }
     usecell(cell3);
     Cell* cell5 = &cell;
     usecell(cell5);
 
+    {
+        // Templatized container that inherits attributes from Cell*, should
+        // report a hazard.
+        UntypedContainer<int, Cell*> container1;
+        usecontainer(&container1);
+        GC();
+        usecontainer(&container1);
+    }
+
+    {
+        // As above, but with a non-GC type.
+        UntypedContainer<int, double> container2;
+        usecontainer(&container2);
+        GC();
+        usecontainer(&container2);
+    }
+
     // Hazard in return value due to ~GCInDestructor
     Cell* cell6 = &cell;
     return cell6;
 }
 
 Cell* copy_and_gc(Cell* src)
 {
     GC();
--- a/js/src/devtools/rootAnalysis/t/hazards/test.py
+++ b/js/src/devtools/rootAnalysis/t/hazards/test.py
@@ -30,16 +30,19 @@ assert(len(set(haz.function for haz in h
 # Check that the correct GC call is reported for each hazard. (cell3 has a
 # hazard from two different GC calls; it doesn't really matter which is
 # reported.)
 assert(hazmap['cell2'].GCFunction == 'void halfSuppressedFunction()')
 assert(hazmap['cell3'].GCFunction in (
     'void halfSuppressedFunction()', 'void unsuppressedFunction()'))
 assert(hazmap['<returnvalue>'].GCFunction == 'void GCInDestructor::~GCInDestructor()')
 
+assert('container1' in hazmap);
+assert('container2' not in hazmap);
+
 # Type names are handy to have in the report.
 assert(hazmap['cell2'].type == 'Cell*')
 assert(hazmap['<returnvalue>'].type == 'Cell*')
 
 # loopy hazards. See comments in source.
 assert('haz1' not in hazmap)
 assert('haz2' not in hazmap)
 assert('haz3' in hazmap)
--- a/layout/base/AccessibleCaret.h
+++ b/layout/base/AccessibleCaret.h
@@ -209,17 +209,17 @@ protected:
 
   // Member variables
   Appearance mAppearance = Appearance::None;
 
   // AccessibleCaretManager owns us by a UniquePtr. When it's terminated by
   // AccessibleCaretEventHub::Terminate() which is called in
   // PresShell::Destroy(), it frees us automatically. No need to worry if we
   // outlive mPresShell.
-  nsIPresShell* MOZ_NON_OWNING_REF const mPresShell = nullptr;
+  nsIPresShell* const MOZ_NON_OWNING_REF mPresShell = nullptr;
 
   RefPtr<dom::AnonymousContent> mCaretElementHolder;
 
   // mImaginaryCaretRect is relative to root frame.
   nsRect mImaginaryCaretRect;
 
   // Cache current zoom level to determine whether position is changed.
   float mZoomLevel = 0.0f;
--- a/layout/base/gtest/TestAccessibleCaretEventHub.cpp
+++ b/layout/base/gtest/TestAccessibleCaretEventHub.cpp
@@ -257,23 +257,23 @@ public:
     ReleaseEventCreator aReleaseEventCreator);
 
   // Member variables
   RefPtr<MockAccessibleCaretEventHub> mHub{new MockAccessibleCaretEventHub()};
 
 }; // class AccessibleCaretEventHubTester
 
 TEST_F(AccessibleCaretEventHubTester, TestMousePressReleaseOnNoCaret)
-MOZ_CAN_RUN_SCRIPT
+MOZ_CAN_RUN_SCRIPT_FOR_DEFINITION
 {
   TestPressReleaseOnNoCaret(CreateMousePressEvent, CreateMouseReleaseEvent);
 }
 
 TEST_F(AccessibleCaretEventHubTester, TestTouchPressReleaseOnNoCaret)
-MOZ_CAN_RUN_SCRIPT
+MOZ_CAN_RUN_SCRIPT_FOR_DEFINITION
 {
   TestPressReleaseOnNoCaret(CreateTouchStartEvent, CreateTouchEndEvent);
 }
 
 template <typename PressEventCreator, typename ReleaseEventCreator>
 void
 AccessibleCaretEventHubTester::TestPressReleaseOnNoCaret(
   PressEventCreator aPressEventCreator,
@@ -291,23 +291,23 @@ AccessibleCaretEventHubTester::TestPress
                            nsEventStatus_eIgnore);
 
   HandleEventAndCheckState(aReleaseEventCreator(0, 0),
                            MockAccessibleCaretEventHub::NoActionState(),
                            nsEventStatus_eIgnore);
 }
 
 TEST_F(AccessibleCaretEventHubTester, TestMousePressReleaseOnCaret)
-MOZ_CAN_RUN_SCRIPT
+MOZ_CAN_RUN_SCRIPT_FOR_DEFINITION
 {
   TestPressReleaseOnCaret(CreateMousePressEvent, CreateMouseReleaseEvent);
 }
 
 TEST_F(AccessibleCaretEventHubTester, TestTouchPressReleaseOnCaret)
-MOZ_CAN_RUN_SCRIPT
+MOZ_CAN_RUN_SCRIPT_FOR_DEFINITION
 {
   TestPressReleaseOnCaret(CreateTouchStartEvent, CreateTouchEndEvent);
 }
 
 template <typename PressEventCreator, typename ReleaseEventCreator>
 void
 AccessibleCaretEventHubTester::TestPressReleaseOnCaret(
   PressEventCreator aPressEventCreator,
@@ -335,24 +335,24 @@ AccessibleCaretEventHubTester::TestPress
                            nsEventStatus_eConsumeNoDefault);
 
   HandleEventAndCheckState(aReleaseEventCreator(0, 0),
                            MockAccessibleCaretEventHub::NoActionState(),
                            nsEventStatus_eConsumeNoDefault);
 }
 
 TEST_F(AccessibleCaretEventHubTester, TestMousePressMoveReleaseOnNoCaret)
-MOZ_CAN_RUN_SCRIPT
+MOZ_CAN_RUN_SCRIPT_FOR_DEFINITION
 {
   TestPressMoveReleaseOnNoCaret(CreateMousePressEvent, CreateMouseMoveEvent,
                                 CreateMouseReleaseEvent);
 }
 
 TEST_F(AccessibleCaretEventHubTester, TestTouchPressMoveReleaseOnNoCaret)
-MOZ_CAN_RUN_SCRIPT
+MOZ_CAN_RUN_SCRIPT_FOR_DEFINITION
 {
   TestPressMoveReleaseOnNoCaret(CreateTouchStartEvent, CreateTouchMoveEvent,
                                 CreateTouchEndEvent);
 }
 
 template <typename PressEventCreator, typename MoveEventCreator,
           typename ReleaseEventCreator>
 void
@@ -391,24 +391,24 @@ AccessibleCaretEventHubTester::TestPress
                            nsEventStatus_eIgnore);
 
   HandleEventAndCheckState(aReleaseEventCreator(x3, y3),
                            MockAccessibleCaretEventHub::NoActionState(),
                            nsEventStatus_eIgnore);
 }
 
 TEST_F(AccessibleCaretEventHubTester, TestMousePressMoveReleaseOnCaret)
-MOZ_CAN_RUN_SCRIPT
+MOZ_CAN_RUN_SCRIPT_FOR_DEFINITION
 {
   TestPressMoveReleaseOnCaret(CreateMousePressEvent, CreateMouseMoveEvent,
                               CreateMouseReleaseEvent);
 }
 
 TEST_F(AccessibleCaretEventHubTester, TestTouchPressMoveReleaseOnCaret)
-MOZ_CAN_RUN_SCRIPT
+MOZ_CAN_RUN_SCRIPT_FOR_DEFINITION
 {
   TestPressMoveReleaseOnCaret(CreateTouchStartEvent, CreateTouchMoveEvent,
                               CreateTouchEndEvent);
 }
 
 template <typename PressEventCreator, typename MoveEventCreator,
           typename ReleaseEventCreator>
 void
@@ -460,17 +460,17 @@ AccessibleCaretEventHubTester::TestPress
 
   HandleEventAndCheckState(aReleaseEventCreator(x3, y3),
                            MockAccessibleCaretEventHub::NoActionState(),
                            nsEventStatus_eConsumeNoDefault);
 }
 
 TEST_F(AccessibleCaretEventHubTester,
        TestTouchStartMoveEndOnCaretWithTouchCancelIgnored)
-MOZ_CAN_RUN_SCRIPT
+MOZ_CAN_RUN_SCRIPT_FOR_DEFINITION
 {
   nscoord x0 = 0, y0 = 0;
   nscoord x1 = 100, y1 = 100;
   nscoord x2 = 300, y2 = 300;
   nscoord x3 = 400, y3 = 400;
 
   {
     InSequence dummy;
@@ -519,24 +519,24 @@ MOZ_CAN_RUN_SCRIPT
                            MockAccessibleCaretEventHub::NoActionState(),
                            nsEventStatus_eConsumeNoDefault);
 
   HandleEventAndCheckState(CreateTouchCancelEvent(x3, y3),
                            MockAccessibleCaretEventHub::NoActionState(),
                            nsEventStatus_eIgnore);}
 
 TEST_F(AccessibleCaretEventHubTester, TestMouseLongTapWithSelectWordSuccessful)
-MOZ_CAN_RUN_SCRIPT
+MOZ_CAN_RUN_SCRIPT_FOR_DEFINITION
 {
   TestLongTapWithSelectWordSuccessful(CreateMousePressEvent,
                                       CreateMouseReleaseEvent);
 }
 
 TEST_F(AccessibleCaretEventHubTester, TestTouchLongTapWithSelectWordSuccessful)
-MOZ_CAN_RUN_SCRIPT
+MOZ_CAN_RUN_SCRIPT_FOR_DEFINITION
 {
   TestLongTapWithSelectWordSuccessful(CreateTouchStartEvent,
                                       CreateTouchEndEvent);
 }
 
 template <typename PressEventCreator, typename ReleaseEventCreator>
 void
 AccessibleCaretEventHubTester::TestLongTapWithSelectWordSuccessful(
@@ -601,24 +601,24 @@ AccessibleCaretEventHubTester::TestLongT
   EXPECT_EQ(mHub->GetState(), MockAccessibleCaretEventHub::NoActionState());
 
   HandleEventAndCheckState(aReleaseEventCreator(1, 1),
                            MockAccessibleCaretEventHub::NoActionState(),
                            nsEventStatus_eIgnore);
 }
 
 TEST_F(AccessibleCaretEventHubTester, TestMouseLongTapWithSelectWordFailed)
-MOZ_CAN_RUN_SCRIPT
+MOZ_CAN_RUN_SCRIPT_FOR_DEFINITION
 {
   TestLongTapWithSelectWordFailed(CreateMousePressEvent,
                                   CreateMouseReleaseEvent);
 }
 
 TEST_F(AccessibleCaretEventHubTester, TestTouchLongTapWithSelectWordFailed)
-MOZ_CAN_RUN_SCRIPT
+MOZ_CAN_RUN_SCRIPT_FOR_DEFINITION
 {
   TestLongTapWithSelectWordFailed(CreateTouchStartEvent,
                                   CreateTouchEndEvent);
 }
 
 template <typename PressEventCreator, typename ReleaseEventCreator>
 void
 AccessibleCaretEventHubTester::TestLongTapWithSelectWordFailed(
@@ -644,24 +644,24 @@ AccessibleCaretEventHubTester::TestLongT
                            nsEventStatus_eIgnore);
 
   HandleEventAndCheckState(aReleaseEventCreator(0, 0),
                            MockAccessibleCaretEventHub::NoActionState(),
                            nsEventStatus_eIgnore);
 }
 
 TEST_F(AccessibleCaretEventHubTester, TestTouchEventDrivenAsyncPanZoomScroll)
-MOZ_CAN_RUN_SCRIPT
+MOZ_CAN_RUN_SCRIPT_FOR_DEFINITION
 {
   TestEventDrivenAsyncPanZoomScroll(CreateTouchStartEvent, CreateTouchMoveEvent,
                                     CreateTouchEndEvent);
 }
 
 TEST_F(AccessibleCaretEventHubTester, TestMouseEventDrivenAsyncPanZoomScroll)
-MOZ_CAN_RUN_SCRIPT
+MOZ_CAN_RUN_SCRIPT_FOR_DEFINITION
 {
   TestEventDrivenAsyncPanZoomScroll(CreateMousePressEvent, CreateMouseMoveEvent,
                                     CreateMouseReleaseEvent);
 }
 
 template <typename PressEventCreator, typename MoveEventCreator,
           typename ReleaseEventCreator>
 void
@@ -745,17 +745,18 @@ AccessibleCaretEventHubTester::TestEvent
   mHub->AsyncPanZoomStopped();
   EXPECT_EQ(mHub->GetState(), MockAccessibleCaretEventHub::NoActionState());
 
   HandleEventAndCheckState(aReleaseEventCreator(310, 310),
                            MockAccessibleCaretEventHub::NoActionState(),
                            nsEventStatus_eIgnore);
 }
 
-TEST_F(AccessibleCaretEventHubTester, TestAsyncPanZoomScroll) MOZ_CAN_RUN_SCRIPT
+TEST_F(AccessibleCaretEventHubTester, TestAsyncPanZoomScroll)
+MOZ_CAN_RUN_SCRIPT_FOR_DEFINITION
 {
   TestAsyncPanZoomScroll();
 }
 
 void
 AccessibleCaretEventHubTester::TestAsyncPanZoomScroll()
 {
   MockFunction<void(::std::string aCheckPointName)> check;
@@ -796,17 +797,17 @@ AccessibleCaretEventHubTester::TestAsync
   mHub->ScrollPositionChanged();
   EXPECT_EQ(mHub->GetState(), MockAccessibleCaretEventHub::ScrollState());
 
   mHub->AsyncPanZoomStopped();
   EXPECT_EQ(mHub->GetState(), MockAccessibleCaretEventHub::NoActionState());
 }
 
 TEST_F(AccessibleCaretEventHubTester, TestAsyncPanZoomScrollStartedThenBlur)
-MOZ_CAN_RUN_SCRIPT
+MOZ_CAN_RUN_SCRIPT_FOR_DEFINITION
 {
   {
     InSequence dummy;
 
     EXPECT_CALL(*mHub->GetMockAccessibleCaretManager(), OnScrollStart());
     EXPECT_CALL(*mHub->GetMockAccessibleCaretManager(), OnScrollEnd()).Times(0);
     EXPECT_CALL(*mHub->GetMockAccessibleCaretManager(), OnBlur());
   }
@@ -817,17 +818,17 @@ MOZ_CAN_RUN_SCRIPT
   mHub->ScrollPositionChanged();
   EXPECT_EQ(mHub->GetState(), MockAccessibleCaretEventHub::ScrollState());
 
   mHub->NotifyBlur(true);
   EXPECT_EQ(mHub->GetState(), MockAccessibleCaretEventHub::NoActionState());
 }
 
 TEST_F(AccessibleCaretEventHubTester, TestAsyncPanZoomScrollEndedThenBlur)
-MOZ_CAN_RUN_SCRIPT
+MOZ_CAN_RUN_SCRIPT_FOR_DEFINITION
 {
   {
     InSequence dummy;
 
     EXPECT_CALL(*mHub->GetMockAccessibleCaretManager(), OnScrollStart());
     EXPECT_CALL(*mHub->GetMockAccessibleCaretManager(), OnScrollEnd());
     EXPECT_CALL(*mHub->GetMockAccessibleCaretManager(), OnBlur());
   }
--- a/layout/base/gtest/TestAccessibleCaretManager.cpp
+++ b/layout/base/gtest/TestAccessibleCaretManager.cpp
@@ -133,17 +133,17 @@ public:
   }
 
   // Member variables
   MockAccessibleCaretManager mManager;
 
 }; // class AccessibleCaretManagerTester
 
 TEST_F(AccessibleCaretManagerTester, TestUpdatesInSelectionMode)
-MOZ_CAN_RUN_SCRIPT
+MOZ_CAN_RUN_SCRIPT_FOR_DEFINITION
 {
   EXPECT_CALL(mManager, GetCaretMode())
     .WillRepeatedly(Return(CaretMode::Selection));
 
   EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
                 CaretChangedReason::Updateposition)).Times(3);
 
   mManager.UpdateCarets();
@@ -155,17 +155,17 @@ MOZ_CAN_RUN_SCRIPT
   EXPECT_EQ(SecondCaretAppearance(), Appearance::Normal);
 
   mManager.OnScrollPositionChanged();
   EXPECT_EQ(FirstCaretAppearance(), Appearance::Normal);
   EXPECT_EQ(SecondCaretAppearance(), Appearance::Normal);
 }
 
 TEST_F(AccessibleCaretManagerTester, TestSingleTapOnNonEmptyInput)
-MOZ_CAN_RUN_SCRIPT
+MOZ_CAN_RUN_SCRIPT_FOR_DEFINITION
 {
   EXPECT_CALL(mManager, GetCaretMode())
     .WillRepeatedly(Return(CaretMode::Cursor));
 
   EXPECT_CALL(mManager, HasNonEmptyTextContent(_))
     .WillRepeatedly(Return(true));
 
   MockFunction<void(std::string aCheckPointName)> check;
@@ -226,17 +226,17 @@ MOZ_CAN_RUN_SCRIPT
   EXPECT_EQ(FirstCaretAppearance(), Appearance::Normal);
   check.Call("reflow2");
 
   mManager.OnScrollPositionChanged();
   EXPECT_EQ(FirstCaretAppearance(), Appearance::Normal);
 }
 
 TEST_F(AccessibleCaretManagerTester, TestSingleTapOnEmptyInput)
-MOZ_CAN_RUN_SCRIPT
+MOZ_CAN_RUN_SCRIPT_FOR_DEFINITION
 {
   EXPECT_CALL(mManager, GetCaretMode())
     .WillRepeatedly(Return(CaretMode::Cursor));
 
   EXPECT_CALL(mManager, HasNonEmptyTextContent(_))
     .WillRepeatedly(Return(false));
 
   MockFunction<void(std::string aCheckPointName)> check;
@@ -296,17 +296,18 @@ MOZ_CAN_RUN_SCRIPT
   mManager.OnReflow();
   EXPECT_EQ(FirstCaretAppearance(), Appearance::NormalNotShown);
   check.Call("reflow2");
 
   mManager.OnScrollPositionChanged();
   EXPECT_EQ(FirstCaretAppearance(), Appearance::NormalNotShown);
 }
 
-TEST_F(AccessibleCaretManagerTester, TestTypingAtEndOfInput) MOZ_CAN_RUN_SCRIPT
+TEST_F(AccessibleCaretManagerTester, TestTypingAtEndOfInput)
+MOZ_CAN_RUN_SCRIPT_FOR_DEFINITION
 {
   EXPECT_CALL(mManager, GetCaretMode())
     .WillRepeatedly(Return(CaretMode::Cursor));
 
   EXPECT_CALL(mManager, HasNonEmptyTextContent(_))
     .WillRepeatedly(Return(true));
 
   MockFunction<void(std::string aCheckPointName)> check;
@@ -339,17 +340,17 @@ TEST_F(AccessibleCaretManagerTester, Tes
                               nsISelectionListener::NO_REASON);
   EXPECT_EQ(FirstCaretAppearance(), Appearance::None);
 
   mManager.OnScrollPositionChanged();
   EXPECT_EQ(FirstCaretAppearance(), Appearance::None);
 }
 
 TEST_F(AccessibleCaretManagerTester, TestScrollInSelectionMode)
-MOZ_CAN_RUN_SCRIPT
+MOZ_CAN_RUN_SCRIPT_FOR_DEFINITION
 {
   EXPECT_CALL(mManager, GetCaretMode())
     .WillRepeatedly(Return(CaretMode::Selection));
 
   MockFunction<void(std::string aCheckPointName)> check;
   {
     InSequence dummy;
 
@@ -425,17 +426,17 @@ MOZ_CAN_RUN_SCRIPT
   mManager.OnScrollEnd();
   EXPECT_EQ(FirstCaretAppearance(), Appearance::Normal);
   EXPECT_EQ(SecondCaretAppearance(), Appearance::Normal);
   check.Call("scrollend2");
 }
 
 TEST_F(AccessibleCaretManagerTester,
        TestScrollInSelectionModeWithAlwaysTiltPref)
-MOZ_CAN_RUN_SCRIPT
+MOZ_CAN_RUN_SCRIPT_FOR_DEFINITION
 {
   // Simulate Firefox Android preference.
   bool oldPref = StaticPrefs::layout_accessiblecaret_always_tilt();
   Preferences::SetBool("layout.accessiblecaret.always_tilt", true);
 
   EXPECT_CALL(mManager, GetCaretMode())
     .WillRepeatedly(Return(CaretMode::Selection));
 
@@ -532,17 +533,17 @@ MOZ_CAN_RUN_SCRIPT
   EXPECT_EQ(FirstCaretAppearance(), Appearance::Left);
   EXPECT_EQ(SecondCaretAppearance(), Appearance::Right);
   check.Call("scrollend2");
 
   Preferences::SetBool("layout.accessiblecaret.always_tilt", oldPref);
 }
 
 TEST_F(AccessibleCaretManagerTester, TestScrollInCursorModeWhenLogicallyVisible)
-MOZ_CAN_RUN_SCRIPT
+MOZ_CAN_RUN_SCRIPT_FOR_DEFINITION
 {
   EXPECT_CALL(mManager, GetCaretMode())
     .WillRepeatedly(Return(CaretMode::Cursor));
 
   EXPECT_CALL(mManager, HasNonEmptyTextContent(_))
     .WillRepeatedly(Return(true));
 
   MockFunction<void(std::string aCheckPointName)> check;
@@ -593,17 +594,17 @@ MOZ_CAN_RUN_SCRIPT
   check.Call("scrollstart2");
 
   mManager.OnScrollEnd();
   EXPECT_EQ(FirstCaretAppearance(), Appearance::Normal);
   check.Call("scrollend2");
 }
 
 TEST_F(AccessibleCaretManagerTester, TestScrollInCursorModeWhenHidden)
-MOZ_CAN_RUN_SCRIPT
+MOZ_CAN_RUN_SCRIPT_FOR_DEFINITION
 {
   EXPECT_CALL(mManager, GetCaretMode())
     .WillRepeatedly(Return(CaretMode::Cursor));
 
   EXPECT_CALL(mManager, HasNonEmptyTextContent(_))
     .WillRepeatedly(Return(true));
 
   MockFunction<void(std::string aCheckPointName)> check;
@@ -648,17 +649,17 @@ MOZ_CAN_RUN_SCRIPT
   EXPECT_EQ(FirstCaretAppearance(), Appearance::None);
 
   mManager.OnScrollEnd();
   EXPECT_EQ(FirstCaretAppearance(), Appearance::None);
   check.Call("scrollend2");
 }
 
 TEST_F(AccessibleCaretManagerTester, TestScrollInCursorModeOnEmptyContent)
-MOZ_CAN_RUN_SCRIPT
+MOZ_CAN_RUN_SCRIPT_FOR_DEFINITION
 {
   EXPECT_CALL(mManager, GetCaretMode())
     .WillRepeatedly(Return(CaretMode::Cursor));
 
   EXPECT_CALL(mManager, HasNonEmptyTextContent(_))
     .WillRepeatedly(Return(false));
 
   MockFunction<void(std::string aCheckPointName)> check;
@@ -720,17 +721,17 @@ MOZ_CAN_RUN_SCRIPT
   check.Call("scrollstart3");
   mManager.OnScrollEnd();
   EXPECT_EQ(FirstCaretAppearance(), Appearance::NormalNotShown);
   check.Call("scrollend3");
 }
 
 TEST_F(AccessibleCaretManagerTester,
        TestScrollInCursorModeWithCaretShownWhenLongTappingOnEmptyContentPref)
-MOZ_CAN_RUN_SCRIPT
+MOZ_CAN_RUN_SCRIPT_FOR_DEFINITION
 {
   // Simulate Firefox Android preference.
   bool oldPref = StaticPrefs::layout_accessiblecaret_caret_shown_when_long_tapping_on_empty_content();
   Preferences::SetBool("layout.accessiblecaret.caret_shown_when_long_tapping_on_empty_content", true);
 
   EXPECT_CALL(mManager, GetCaretMode())
     .WillRepeatedly(Return(CaretMode::Cursor));
 
--- a/mfbt/Attributes.h
+++ b/mfbt/Attributes.h
@@ -531,17 +531,23 @@
  *     goto target;
  *   MOZ_CASE_ATTRIBUTE case 5:
  *   MOZ_DEFAULT_ATTRIBUTE default:
  *
  * The static analyses that are performed by the plugin are as follows:
  *
  * MOZ_CAN_RUN_SCRIPT: Applies to functions which can run script. Callers of
  *   this function must also be marked as MOZ_CAN_RUN_SCRIPT, and all refcounted
- *   arguments must be strongly held in the caller.
+ *   arguments must be strongly held in the caller. Note that MOZ_CAN_RUN_SCRIPT
+ *   should only be applied to function declarations, not definitions. If you
+ *   need to apply it to a definition (eg because both are generated by a macro)
+ *   use MOZ_CAN_RUN_SCRIPT_FOR_DEFINITION.
+ * MOZ_CAN_RUN_SCRIPT_FOR_DEFINITION: Same as MOZ_CAN_RUN_SCRIPT, but usable on
+ *   a definition. If the declaration is in a header file, users of that header
+ *   file may not see the annotation.
  * MOZ_CAN_RUN_SCRIPT_BOUNDARY: Applies to functions which need to call
  *   MOZ_CAN_RUN_SCRIPT functions, but should not themselves be considered
  *   MOZ_CAN_RUN_SCRIPT. This is important for some bindings and low level code
  *   which need to opt out of the safety checks performed by MOZ_CAN_RUN_SCRIPT.
  * MOZ_MUST_OVERRIDE: Applies to all C++ member functions. All immediate
  *   subclasses must provide an exact override of this method; if a subclass
  *   does not override this method, the compiler will emit an error. This
  *   attribute is not limited to virtual methods, so if it is applied to a
@@ -709,18 +715,39 @@
  *   within the calling block using an explicit `return` statement.
  *   Only calls to Constructors, references to local and member variables,
  *   and calls to functions or methods marked as MOZ_MAY_CALL_AFTER_MUST_RETURN
  *   may be made after the MUST_RETURN_FROM_CALLER call.
  * MOZ_MAY_CALL_AFTER_MUST_RETURN: Applies to function or method declarations.
  *   Calls to these methods may be made in functions after calls a
  *   MOZ_MUST_RETURN_FROM_CALLER function or method.
  */
-#ifdef MOZ_CLANG_PLUGIN
+
+// gcc emits a nuisance warning -Wignored-attributes because attributes do not
+// affect mangled names, and therefore template arguments do not propagate
+// their attributes. It is rare that this would affect anything in practice,
+// and most compilers are silent about it. Similarly, -Wattributes complains
+// about attributes being ignored during template instantiation.
+//
+// Be conservative and only suppress the warning when running in a
+// configuration where it would be emitted, namely when compiling with the
+// XGILL_PLUGIN for the rooting hazard analysis (which runs under gcc.) If we
+// end up wanting these attributes in general GCC builds, change this to
+// something like
+//
+//     #if defined(__GNUC__) && ! defined(__clang__)
+//
+#ifdef XGILL_PLUGIN
+#pragma GCC diagnostic ignored "-Wignored-attributes"
+#pragma GCC diagnostic ignored "-Wattributes"
+#endif
+
+#if defined(MOZ_CLANG_PLUGIN) || defined(XGILL_PLUGIN)
 #  define MOZ_CAN_RUN_SCRIPT __attribute__((annotate("moz_can_run_script")))
+#  define MOZ_CAN_RUN_SCRIPT_FOR_DEFINITION __attribute__((annotate("moz_can_run_script")))
 #  define MOZ_CAN_RUN_SCRIPT_BOUNDARY __attribute__((annotate("moz_can_run_script_boundary")))
 #  define MOZ_MUST_OVERRIDE __attribute__((annotate("moz_must_override")))
 #  define MOZ_STATIC_CLASS __attribute__((annotate("moz_global_class")))
 #  define MOZ_STACK_CLASS __attribute__((annotate("moz_stack_class")))
 #  define MOZ_NONHEAP_CLASS __attribute__((annotate("moz_nonheap_class")))
 #  define MOZ_HEAP_CLASS __attribute__((annotate("moz_heap_class")))
 #  define MOZ_NON_TEMPORARY_CLASS __attribute__((annotate("moz_non_temporary_class")))
 #  define MOZ_TEMPORARY_CLASS __attribute__((annotate("moz_temporary_class")))
@@ -757,26 +784,30 @@
 #  define MOZ_REQUIRED_BASE_METHOD \
     __attribute__((annotate("moz_required_base_method")))
 #  define MOZ_MUST_RETURN_FROM_CALLER \
     __attribute__((annotate("moz_must_return_from_caller")))
 #  define MOZ_MAY_CALL_AFTER_MUST_RETURN \
     __attribute__((annotate("moz_may_call_after_must_return")))
 /*
  * It turns out that clang doesn't like void func() __attribute__ {} without a
- * warning, so use pragmas to disable the warning. This code won't work on GCC
- * anyways, so the warning is safe to ignore.
+ * warning, so use pragmas to disable the warning.
  */
-#  define MOZ_HEAP_ALLOCATOR \
-    _Pragma("clang diagnostic push") \
-    _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \
-    __attribute__((annotate("moz_heap_allocator"))) \
-    _Pragma("clang diagnostic pop")
+#  ifdef __clang__
+#    define MOZ_HEAP_ALLOCATOR \
+       _Pragma("clang diagnostic push") \
+       _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \
+       __attribute__((annotate("moz_heap_allocator"))) \
+       _Pragma("clang diagnostic pop")
+#  else
+#    define MOZ_HEAP_ALLOCATOR __attribute__((annotate("moz_heap_allocator")))
+#  endif
 #else
 #  define MOZ_CAN_RUN_SCRIPT /* nothing */
+#  define MOZ_CAN_RUN_SCRIPT_FOR_DEFINITION /* nothing */
 #  define MOZ_CAN_RUN_SCRIPT_BOUNDARY /* nothing */
 #  define MOZ_MUST_OVERRIDE /* nothing */
 #  define MOZ_STATIC_CLASS /* nothing */
 #  define MOZ_STACK_CLASS /* nothing */
 #  define MOZ_NONHEAP_CLASS /* nothing */
 #  define MOZ_HEAP_CLASS /* nothing */
 #  define MOZ_NON_TEMPORARY_CLASS /* nothing */
 #  define MOZ_TEMPORARY_CLASS /* nothing */
@@ -801,20 +832,31 @@
 #  define MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS /* nothing */
 #  define MOZ_INIT_OUTSIDE_CTOR /* nothing */
 #  define MOZ_IS_CLASS_INIT /* nothing */
 #  define MOZ_NON_PARAM /* nothing */
 #  define MOZ_NON_AUTOABLE /* nothing */
 #  define MOZ_REQUIRED_BASE_METHOD /* nothing */
 #  define MOZ_MUST_RETURN_FROM_CALLER /* nothing */
 #  define MOZ_MAY_CALL_AFTER_MUST_RETURN /* nothing */
-#endif /* MOZ_CLANG_PLUGIN */
+#endif /* defined(MOZ_CLANG_PLUGIN) || defined(XGILL_PLUGIN) */
 
 #define MOZ_RAII MOZ_NON_TEMPORARY_CLASS MOZ_STACK_CLASS
 
+// gcc has different rules governing attribute placement. Since none of these
+// attributes are actually used by the gcc-based static analysis, just
+// eliminate them rather than updating all of the code.
+
+#ifdef XGILL_PLUGIN
+#  undef MOZ_MUST_OVERRIDE
+#  define MOZ_MUST_OVERRIDE /* nothing */
+#  undef MOZ_CAN_RUN_SCRIPT_FOR_DEFINITION
+#  define MOZ_CAN_RUN_SCRIPT_FOR_DEFINITION /* nothing */
+#endif
+
 #endif /* __cplusplus */
 
 /**
  * Printf style formats.  MOZ_FORMAT_PRINTF can be used to annotate a
  * function or method that is "printf-like"; this will let (some)
  * compilers check that the arguments match the template string.
  *
  * This macro takes two arguments.  The first argument is the argument
--- a/mfbt/CheckedInt.h
+++ b/mfbt/CheckedInt.h
@@ -553,17 +553,17 @@ public:
    *
    * This constructor is not explicit. Instead, the type of its argument is a
    * separate template parameter, ensuring that no conversion is performed
    * before this constructor is actually called. As explained in the above
    * documentation for class CheckedInt, this constructor checks that its
    * argument is valid.
    */
   template<typename U>
-  MOZ_IMPLICIT constexpr CheckedInt(U aValue) MOZ_NO_ARITHMETIC_EXPR_IN_ARGUMENT
+  MOZ_IMPLICIT MOZ_NO_ARITHMETIC_EXPR_IN_ARGUMENT constexpr CheckedInt(U aValue)
     : mValue(T(aValue)),
       mIsValid(detail::IsInRange<T>(aValue))
   {
     static_assert(detail::IsSupported<T>::value &&
                   detail::IsSupported<U>::value,
                   "This type is not supported by CheckedInt");
   }
 
--- a/taskcluster/scripts/builder/hazard-browser.sh
+++ b/taskcluster/scripts/builder/hazard-browser.sh
@@ -1,10 +1,10 @@
 #!/bin/bash -e
 
 cd $SOURCE
 TOP=$(cd ..; pwd)
 export MOZBUILD_STATE_PATH=$TOP/mozbuild-state
 [ -d $MOZBUILD_STATE_PATH ] || mkdir $MOZBUILD_STATE_PATH
 
-export MOZCONFIG=$SOURCE/browser/config/mozconfigs/linux64/hazards
+export MOZCONFIG=$SOURCE/js/src/devtools/rootAnalysis/mozconfig.haz
 
 exec ./mach build -v -j8