Bug 1236321 - Annotate intentional switch fallthroughs to suppress -Wimplicit-fallthrough warnings in js/. r=luke
authorChris Peterson <cpeterson@mozilla.com>
Thu, 31 Dec 2015 01:05:49 -0700
changeset 314253 f998906d53bca783b99762b7999f9e692d1ec367
parent 314252 c1b0bb0c120141dd92e3cbc21e80221b7c5ff9b6
child 314254 2c86ca757a1ec2514eb6ac2d47ada5fd29cceac3
push id5703
push userraliiev@mozilla.com
push dateMon, 07 Mar 2016 14:18:41 +0000
treeherdermozilla-beta@31e373ad5b5f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersluke
bugs1236321
milestone46.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 1236321 - Annotate intentional switch fallthroughs to suppress -Wimplicit-fallthrough warnings in js/. r=luke
js/src/asmjs/AsmJS.cpp
js/src/asmjs/WasmStubs.cpp
js/src/builtin/ReflectParse.cpp
js/src/ctypes/CTypes.cpp
js/src/frontend/BytecodeEmitter.cpp
js/src/frontend/NameFunctions.cpp
js/src/frontend/Parser.cpp
js/src/irregexp/RegExpEngine.cpp
js/src/irregexp/RegExpParser.cpp
js/src/jit/BacktrackingAllocator.cpp
js/src/jit/BaselineBailouts.cpp
js/src/jit/BaselineIC.cpp
js/src/jit/IonBuilder.cpp
js/src/jit/JitcodeMap.h
js/src/jit/Lowering.cpp
js/src/jit/MIR.cpp
js/src/jit/MacroAssembler.cpp
js/src/jit/RangeAnalysis.cpp
js/src/jit/shared/CodeGenerator-shared-inl.h
js/src/jsdtoa.cpp
js/src/jsgc.cpp
js/src/jsiter.cpp
js/src/jsstr.cpp
js/src/moz.build
js/src/vm/Runtime.cpp
js/xpconnect/src/XPCConvert.cpp
js/xpconnect/src/XPCShellImpl.cpp
--- a/js/src/asmjs/AsmJS.cpp
+++ b/js/src/asmjs/AsmJS.cpp
@@ -13,16 +13,17 @@
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 #include "asmjs/AsmJS.h"
 
+#include "mozilla/Attributes.h"
 #include "mozilla/Compression.h"
 #include "mozilla/MathAlgorithms.h"
 
 #include "jsmath.h"
 #include "jsprf.h"
 #include "jsutil.h"
 
 #include "jswrapper.h"
@@ -2540,16 +2541,17 @@ IsSimdLiteral(ModuleValidator& m, ParseN
             return false;
 
         uint32_t _;
         switch (type) {
           case AsmJSSimdType_int32x4:
           case AsmJSSimdType_bool32x4:
             if (!IsLiteralInt(m, arg, &_))
                 return false;
+            MOZ_FALLTHROUGH;
           case AsmJSSimdType_float32x4:
             if (!IsNumericNonFloatLiteral(arg))
                 return false;
         }
 
         arg = NextNode(arg);
     }
 
@@ -3103,16 +3105,17 @@ CheckTypeAnnotation(ModuleValidator& m, 
         *coerceTo = ValType::F64;
         if (coercedExpr)
             *coercedExpr = UnaryKid(coercionNode);
         return true;
       }
       case PNK_CALL: {
         if (IsCoercionCall(m, coercionNode, coerceTo, coercedExpr))
             return true;
+        break;
       }
       default:;
     }
 
     return m.fail(coercionNode, "must be of the form +x, x|0, fround(x), or a SIMD check(x)");
 }
 
 static bool
--- a/js/src/asmjs/WasmStubs.cpp
+++ b/js/src/asmjs/WasmStubs.cpp
@@ -257,17 +257,17 @@ GenerateEntry(ModuleGenerator& mg, unsig
         break;
       case ExprType::I32:
         masm.storeValue(JSVAL_TYPE_INT32, ReturnReg, Address(argv, 0));
         break;
       case ExprType::I64:
         MOZ_CRASH("no int64 in asm.js");
       case ExprType::F32:
         masm.convertFloat32ToDouble(ReturnFloat32Reg, ReturnDoubleReg);
-        // Fall through as ReturnDoubleReg now contains a Double
+        MOZ_FALLTHROUGH; // as ReturnDoubleReg now contains a Double
       case ExprType::F64:
         masm.canonicalizeDouble(ReturnDoubleReg);
         masm.storeDouble(ReturnDoubleReg, Address(argv, 0));
         break;
       case ExprType::I32x4:
       case ExprType::B32x4:
         // We don't have control on argv alignment, do an unaligned access.
         masm.storeUnalignedInt32x4(ReturnSimd128Reg, Address(argv, 0));
--- a/js/src/builtin/ReflectParse.cpp
+++ b/js/src/builtin/ReflectParse.cpp
@@ -2443,17 +2443,17 @@ ASTSerializer::statement(ParseNode* pn, 
                    builder.expressionStatement(expr, &pn->pn_pos, dst);
         }
         return builder.emptyStatement(&pn->pn_pos, dst);
 
       case PNK_LEXICALSCOPE:
         pn = pn->pn_expr;
         if (!pn->isKind(PNK_STATEMENTLIST))
             return statement(pn, dst);
-        /* FALL THROUGH */
+        MOZ_FALLTHROUGH;
 
       case PNK_STATEMENTLIST:
         return blockStatement(pn, dst);
 
       case PNK_IF:
       {
         MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_kid1->pn_pos));
         MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_kid2->pn_pos));
--- a/js/src/ctypes/CTypes.cpp
+++ b/js/src/ctypes/CTypes.cpp
@@ -4054,17 +4054,18 @@ CType::Finalize(JSFreeOp* fop, JSObject*
     // Free the FieldInfoHash table.
     slot = JS_GetReservedSlot(obj, SLOT_FIELDINFO);
     if (!slot.isUndefined()) {
       void* info = slot.toPrivate();
       FreeOp::get(fop)->delete_(static_cast<FieldInfoHash*>(info));
     }
   }
 
-    // Fall through.
+    MOZ_FALLTHROUGH;
+
   case TYPE_array: {
     // Free the ffi_type info.
     slot = JS_GetReservedSlot(obj, SLOT_FFITYPE);
     if (!slot.isUndefined()) {
       ffi_type* ffiType = static_cast<ffi_type*>(slot.toPrivate());
       FreeOp::get(fop)->free_(ffiType->elements);
       FreeOp::get(fop)->delete_(ffiType);
     }
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -2103,16 +2103,17 @@ BytecodeEmitter::checkSideEffects(ParseN
       // perform no conversions.
       case PNK_OR:
       case PNK_AND:
       case PNK_STRICTEQ:
       case PNK_STRICTNE:
       // Any subexpression of a comma expression could be effectful.
       case PNK_COMMA:
         MOZ_ASSERT(pn->pn_count > 0);
+        MOZ_FALLTHROUGH;
       // Subcomponents of a literal may be effectful.
       case PNK_ARRAY:
       case PNK_OBJECT:
         MOZ_ASSERT(pn->isArity(PN_LIST));
         for (ParseNode* item = pn->pn_head; item; item = item->pn_next) {
             if (!checkSideEffects(item, answer))
                 return false;
             if (*answer)
@@ -8797,17 +8798,17 @@ BytecodeEmitter::emitTree(ParseNode* pn,
         break;
 
       case PNK_SETTHIS:
         if (!emitSetThis(pn))
             return false;
         break;
 
       case PNK_POSHOLDER:
-        MOZ_ASSERT_UNREACHABLE("Should never try to emit PNK_POSHOLDER");
+        MOZ_FALLTHROUGH_ASSERT("Should never try to emit PNK_POSHOLDER");
 
       default:
         MOZ_ASSERT(0);
     }
 
     /* bce->emitLevel == 1 means we're last on the stack, so finish up. */
     if (emitLevel == 1) {
         if (!updateSourceCoordNotes(pn->pn_pos.end))
--- a/js/src/frontend/NameFunctions.cpp
+++ b/js/src/frontend/NameFunctions.cpp
@@ -151,17 +151,17 @@ class NameResolver
 
               case PNK_COLON:
               case PNK_SHORTHAND:
                 /*
                  * Record the PNK_COLON/SHORTHAND but skip the PNK_OBJECT so we're not
                  * flagged as a contributor.
                  */
                 pos--;
-                /* fallthrough */
+                MOZ_FALLTHROUGH;
 
               default:
                 /* Save any other nodes we encounter on the way up. */
                 MOZ_ASSERT(*size < MaxParents);
                 nameable[(*size)++] = cur;
                 break;
             }
         }
@@ -722,18 +722,18 @@ class NameResolver
             MOZ_ASSERT(cur->isArity(PN_LIST));
             if (!resolveTaggedTemplate(cur, prefix))
                 return false;
             break;
 
           // Import/export spec lists contain import/export specs containing
           // only pairs of names. Alternatively, an export spec lists may
           // contain a single export batch specifier.
+          case PNK_EXPORT_SPEC_LIST:
           case PNK_IMPORT_SPEC_LIST: {
-          case PNK_EXPORT_SPEC_LIST:
             MOZ_ASSERT(cur->isArity(PN_LIST));
 #ifdef DEBUG
             bool isImport = cur->isKind(PNK_IMPORT_SPEC_LIST);
             ParseNode* item = cur->pn_head;
             if (!isImport && item && item->isKind(PNK_EXPORT_BATCH_SPEC)) {
                 MOZ_ASSERT(item->isArity(PN_NULLARY));
                 break;
             }
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -6351,17 +6351,17 @@ Parser<ParseHandler>::yieldExpression(In
           case TOK_COMMA:
             // No value.
             exprNode = null();
             tokenStream.addModifierException(TokenStream::NoneIsOperand);
             break;
           case TOK_MUL:
             kind = PNK_YIELD_STAR;
             tokenStream.consumeKnownToken(TOK_MUL, TokenStream::Operand);
-            // Fall through.
+            MOZ_FALLTHROUGH;
           default:
             exprNode = assignExpr(inHandling, YieldIsKeyword, TripledotProhibited);
             if (!exprNode)
                 return null();
         }
         return newYieldExpression(begin, exprNode, kind == PNK_YIELD_STAR);
       }
 
@@ -6383,17 +6383,17 @@ Parser<ParseHandler>::yieldExpression(In
         addTelemetry(JSCompartment::DeprecatedLegacyGenerator);
 
         if (pc->funHasReturnExpr) {
             /* As in Python (see PEP-255), disallow return v; in generators. */
             reportBadReturn(null(), ParseError, JSMSG_BAD_GENERATOR_RETURN,
                             JSMSG_BAD_ANON_GENERATOR_RETURN);
             return null();
         }
-        // Fall through.
+        MOZ_FALLTHROUGH;
 
       case LegacyGenerator:
       {
         // We are in a legacy generator: a function that has already seen a
         // yield.
         MOZ_ASSERT(pc->sc->isFunctionBox());
 
         pc->lastYieldOffset = begin;
@@ -6654,17 +6654,17 @@ Parser<ParseHandler>::tryStatement(Yield
                     report(ParseError, false, null(), JSMSG_RESERVED_ID, "yield");
                     return null();
                 }
 
                 // Even if yield is *not* necessarily a keyword, we still must
                 // check its validity for legacy generators.
                 if (!checkYieldNameValidity())
                     return null();
-                // Fall through.
+                MOZ_FALLTHROUGH;
               case TOK_NAME:
               {
                 RootedPropertyName label(context, tokenStream.currentName());
                 catchName = newBindingNode(label, false);
                 if (!catchName)
                     return null();
                 data.setNameNode(catchName);
                 if (!data.bind(label, this))
@@ -9116,17 +9116,17 @@ Parser<ParseHandler>::primaryExpr(YieldH
         return noSubstitutionTemplate();
 
       case TOK_STRING:
         return stringLiteral();
 
       case TOK_YIELD:
         if (!checkYieldNameValidity())
             return null();
-        // Fall through.
+        MOZ_FALLTHROUGH;
       case TOK_NAME:
         return identifierName(yieldHandling);
 
       case TOK_REGEXP:
         return newRegExp();
 
       case TOK_NUMBER:
         return newNumber(tokenStream.currentToken());
--- a/js/src/irregexp/RegExpEngine.cpp
+++ b/js/src/irregexp/RegExpEngine.cpp
@@ -3810,17 +3810,17 @@ EmitAtomLetter(RegExpCompiler* compiler,
             macro_assembler->CheckCharacter(chars[0], &ok);
             macro_assembler->CheckNotCharacter(chars[1], on_failure);
             macro_assembler->Bind(&ok);
         }
         break;
       }
       case 4:
         macro_assembler->CheckCharacter(chars[3], &ok);
-        // Fall through!
+        MOZ_FALLTHROUGH;
       case 3:
         macro_assembler->CheckCharacter(chars[0], &ok);
         macro_assembler->CheckCharacter(chars[1], &ok);
         macro_assembler->CheckNotCharacter(chars[2], on_failure);
         macro_assembler->Bind(&ok);
         break;
       default:
         MOZ_CRASH("Bad length");
--- a/js/src/irregexp/RegExpParser.cpp
+++ b/js/src/irregexp/RegExpParser.cpp
@@ -1558,17 +1558,17 @@ RegExpParser<CharT>::ParseDisjunction()
               case 'D': case 'S': case 'W':
                 if (unicode_) {
                     Advance();
                     builder->AddAtom(UnicodeCharacterClassEscapeAtom(alloc, current(),
                                                                      ignore_case_));
                     Advance();
                     break;
                 }
-                // Fall through
+                MOZ_FALLTHROUGH;
               case 'd': case 's': case 'w': {
                 widechar c = Next();
                 Advance(2);
                 CharacterRangeVector* ranges =
                     alloc->newInfallible<CharacterRangeVector>(*alloc);
                 if (unicode_)
                     CharacterRange::AddClassEscapeUnicode(alloc, c, ranges, ignore_case_);
                 else
@@ -1600,18 +1600,18 @@ RegExpParser<CharT>::ParseDisjunction()
                     return ReportError(JSMSG_BACK_REF_OUT_OF_RANGE);
                 widechar first_digit = Next();
                 if (first_digit == '8' || first_digit == '9') {
                     // Treat as identity escape
                     builder->AddCharacter(first_digit);
                     Advance(2);
                     break;
                 }
+                MOZ_FALLTHROUGH;
               }
-                // FALLTHROUGH
               case '0': {
                 if (unicode_) {
                     Advance(2);
                     if (IsDecimalDigit(current()))
                         return ReportError(JSMSG_INVALID_DECIMAL_ESCAPE);
                     builder->AddCharacter(0);
                     break;
                 }
@@ -1730,17 +1730,17 @@ RegExpParser<CharT>::ParseDisjunction()
             }
             break;
           case '{': {
             if (unicode_)
                 return ReportError(JSMSG_RAW_BRACE_IN_REGEP);
             int dummy;
             if (ParseIntervalQuantifier(&dummy, &dummy))
                 return ReportError(JSMSG_NOTHING_TO_REPEAT);
-            // fallthrough
+            MOZ_FALLTHROUGH;
           }
           default:
             if (unicode_) {
                 char16_t lead, trail;
                 if (ParseRawSurrogatePair(&lead, &trail)) {
                     builder->AddAtom(SurrogatePairAtom(alloc, lead, trail, ignore_case_));
                 } else {
                     widechar c = current();
--- a/js/src/jit/BacktrackingAllocator.cpp
+++ b/js/src/jit/BacktrackingAllocator.cpp
@@ -2476,16 +2476,17 @@ BacktrackingAllocator::computeSpillWeigh
         for (UsePositionIterator iter = range->usesBegin(); iter; iter++) {
             switch (iter->usePolicy()) {
               case LUse::ANY:
                 usesTotal += 1000;
                 break;
 
               case LUse::FIXED:
                 fixed = true;
+                MOZ_FALLTHROUGH;
               case LUse::REGISTER:
                 usesTotal += 2000;
                 break;
 
               case LUse::KEEPALIVE:
                 break;
 
               default:
--- a/js/src/jit/BaselineBailouts.cpp
+++ b/js/src/jit/BaselineBailouts.cpp
@@ -1908,17 +1908,17 @@ jit::FinishBailoutToBaseline(BaselineBai
         // Do not return directly, as this was not frequent in the first place,
         // thus rely on the check for frequent bailouts to recompile the current
         // script.
         break;
 
       // Invalid assumption based on baseline code.
       case Bailout_OverflowInvalidate:
         outerScript->setHadOverflowBailout();
-        // FALL THROUGH
+        MOZ_FALLTHROUGH;
       case Bailout_NonStringInputInvalidate:
       case Bailout_DoubleOutput:
       case Bailout_ObjectIdentityOrTypeGuard:
         if (!HandleBaselineInfoBailout(cx, outerScript, innerScript))
             return false;
         break;
 
       case Bailout_ArgumentCheck:
--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -1168,16 +1168,17 @@ RemoveExistingGetElemNativeStubs(JSConte
     MOZ_ASSERT_IF(indirect, holder->isNative());
 
     for (ICStubIterator iter = stub->beginChain(); !iter.atEnd(); iter++) {
         switch (iter->kind()) {
           case ICStub::GetElem_NativeSlotName:
           case ICStub::GetElem_NativeSlotSymbol:
             if (indirect)
                 continue;
+            MOZ_FALLTHROUGH;
           case ICStub::GetElem_NativePrototypeSlotName:
           case ICStub::GetElem_NativePrototypeSlotSymbol:
           case ICStub::GetElem_NativePrototypeCallNativeName:
           case ICStub::GetElem_NativePrototypeCallNativeSymbol:
           case ICStub::GetElem_NativePrototypeCallScriptedName:
           case ICStub::GetElem_NativePrototypeCallScriptedSymbol:
             break;
           default:
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -716,16 +716,17 @@ IonBuilder::analyzeNewLoopTypes(MBasicBl
                 break;
               case JSOP_ADD:
               case JSOP_SUB:
               case JSOP_MUL:
               case JSOP_DIV:
               case JSOP_MOD:
               case JSOP_NEG:
                 type = inspector->expectedResultType(last);
+                break;
               default:
                 break;
             }
             if (type != MIRType_None) {
                 if (!phi->addBackedgeType(type, nullptr))
                     return false;
             }
         }
@@ -1544,17 +1545,17 @@ IonBuilder::traverseBytecode()
               case JSOP_TOSTRING:
                 // These ops may leave their input on the stack without setting
                 // the ImplicitlyUsed flag. If this value will be popped immediately,
                 // we may replace it with |undefined|, but the difference is
                 // not observable.
                 MOZ_ASSERT(i == 0);
                 if (current->peek(-1) == popped[0])
                     break;
-                // FALL THROUGH
+                MOZ_FALLTHROUGH;
 
               default:
                 MOZ_ASSERT(popped[i]->isImplicitlyUsed() ||
 
                            // MNewDerivedTypedObject instances are
                            // often dead unless they escape from the
                            // fn. See IonBuilder::loadTypedObjectData()
                            // for more details.
@@ -1935,16 +1936,17 @@ IonBuilder::inspectOpcode(JSOp op)
       }
 
       case JSOP_BINDGNAME:
         if (!script()->hasNonSyntacticScope()) {
             if (JSObject* scope = testGlobalLexicalBinding(info().getName(pc)))
                 return pushConstant(ObjectValue(*scope));
         }
         // Fall through to JSOP_BINDNAME
+        MOZ_FALLTHROUGH;
       case JSOP_BINDNAME:
         return jsop_bindname(info().getName(pc));
 
       case JSOP_BINDVAR:
         return jsop_bindvar();
 
       case JSOP_DUP:
         current->pushSlot(current->stackDepth() - 1);
--- a/js/src/jit/JitcodeMap.h
+++ b/js/src/jit/JitcodeMap.h
@@ -918,16 +918,17 @@ class JitcodeGlobalEntry
           case Ion:
             markedAny |= ionEntry().mark<ShouldMarkProvider>(trc);
             break;
           case Baseline:
             markedAny |= baselineEntry().mark<ShouldMarkProvider>(trc);
             break;
           case IonCache:
             markedAny |= ionCacheEntry().mark<ShouldMarkProvider>(trc);
+            break;
           case Dummy:
             break;
           default:
             MOZ_CRASH("Invalid JitcodeGlobalEntry kind.");
         }
         return markedAny;
     }
 
@@ -936,16 +937,17 @@ class JitcodeGlobalEntry
           case Ion:
             ionEntry().sweepChildren();
             break;
           case Baseline:
             baselineEntry().sweepChildren();
             break;
           case IonCache:
             ionCacheEntry().sweepChildren(rt);
+            break;
           case Dummy:
             break;
           default:
             MOZ_CRASH("Invalid JitcodeGlobalEntry kind.");
         }
     }
 
     bool isMarkedFromAnyThread(JSRuntime* rt) {
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -1810,17 +1810,17 @@ LIRGenerator::visitToDouble(MToDouble* c
 
       case MIRType_Undefined:
         MOZ_ASSERT(conversion != MToFPInstruction::NumbersOnly);
         lowerConstantDouble(GenericNaN(), convert);
         break;
 
       case MIRType_Boolean:
         MOZ_ASSERT(conversion != MToFPInstruction::NumbersOnly);
-        /* FALLTHROUGH */
+        MOZ_FALLTHROUGH;
 
       case MIRType_Int32:
       {
         LInt32ToDouble* lir = new(alloc()) LInt32ToDouble(useRegisterAtStart(opd));
         define(lir, convert);
         break;
       }
 
@@ -1866,17 +1866,17 @@ LIRGenerator::visitToFloat32(MToFloat32*
 
       case MIRType_Undefined:
         MOZ_ASSERT(conversion != MToFPInstruction::NumbersOnly);
         lowerConstantFloat32(GenericNaN(), convert);
         break;
 
       case MIRType_Boolean:
         MOZ_ASSERT(conversion != MToFPInstruction::NumbersOnly);
-        /* FALLTHROUGH */
+        MOZ_FALLTHROUGH;
 
       case MIRType_Int32:
       {
         LInt32ToFloat32* lir = new(alloc()) LInt32ToFloat32(useRegisterAtStart(opd));
         define(lir, convert);
         break;
       }
 
--- a/js/src/jit/MIR.cpp
+++ b/js/src/jit/MIR.cpp
@@ -2231,16 +2231,17 @@ MUrsh::infer(BaselineInspector* inspecto
 static inline bool
 CanProduceNegativeZero(MDefinition* def) {
     // Test if this instruction can produce negative zero even when bailing out
     // and changing types.
     switch (def->op()) {
         case MDefinition::Op_Constant:
             if (def->type() == MIRType_Double && def->constantValue().toDouble() == -0.0)
                 return true;
+            MOZ_FALLTHROUGH;
         case MDefinition::Op_BitAnd:
         case MDefinition::Op_BitOr:
         case MDefinition::Op_BitXor:
         case MDefinition::Op_BitNot:
         case MDefinition::Op_Lsh:
         case MDefinition::Op_Rsh:
             return false;
         default:
@@ -2309,17 +2310,17 @@ NeedNegativeZeroCheck(MDefinition* def)
             // first. However if the rhs is executed first, the lhs can bail,
             // change type and become -0.0 while the rhs has already been
             // optimized to not make a difference between zero and negative zero.
             MDefinition* lhs = use_def->toSub()->lhs();
             MDefinition* rhs = use_def->toSub()->rhs();
             if (rhs->id() < lhs->id() && CanProduceNegativeZero(lhs))
                 return true;
 
-            /* Fall through...  */
+            MOZ_FALLTHROUGH;
           }
           case MDefinition::Op_StoreElement:
           case MDefinition::Op_StoreElementHole:
           case MDefinition::Op_LoadElement:
           case MDefinition::Op_LoadElementHole:
           case MDefinition::Op_LoadUnboxedScalar:
           case MDefinition::Op_LoadTypedArrayElementHole:
           case MDefinition::Op_CharCodeAt:
@@ -3088,17 +3089,17 @@ MTypeOf::foldsTo(TempAllocator& alloc)
         break;
       case MIRType_Object:
         if (!inputMaybeCallableOrEmulatesUndefined()) {
             // Object is not callable and does not emulate undefined, so it's
             // safe to fold to "object".
             type = JSTYPE_OBJECT;
             break;
         }
-        // FALL THROUGH
+        MOZ_FALLTHROUGH;
       default:
         return this;
     }
 
     return MConstant::New(alloc, StringValue(TypeName(type, GetJitContext()->runtime->names())));
 }
 
 void
@@ -3373,19 +3374,20 @@ MToInt32::foldsTo(TempAllocator& alloc)
             MOZ_ASSERT(convert == MacroAssembler::IntConversion_Any ||
                        convert == MacroAssembler::IntConversion_NumbersOrBoolsOnly);
             return MConstant::New(alloc, Int32Value(val.toBoolean()));
           case MIRType_Int32:
             return MConstant::New(alloc, Int32Value(val.toInt32()));
           case MIRType_Float32:
           case MIRType_Double:
             int32_t ival;
-            // Only the value within the range of Int32 can be substitued as constant.
+            // Only the value within the range of Int32 can be substituted as constant.
             if (mozilla::NumberEqualsInt32(val.toNumber(), &ival))
                 return MConstant::New(alloc, Int32Value(ival));
+            break;
           default:
             break;
         }
     }
 
     if (input->type() == MIRType_Int32)
         return input;
     return this;
--- a/js/src/jit/MacroAssembler.cpp
+++ b/js/src/jit/MacroAssembler.cpp
@@ -452,17 +452,17 @@ MacroAssembler::loadUnboxedProperty(T ad
 {
     switch (type) {
       case JSVAL_TYPE_INT32: {
           // Handle loading an int32 into a double reg.
           if (output.type() == MIRType_Double) {
               convertInt32ToDouble(address, output.typedReg().fpu());
               break;
           }
-          // Fallthrough.
+          MOZ_FALLTHROUGH;
       }
 
       case JSVAL_TYPE_BOOLEAN:
       case JSVAL_TYPE_STRING: {
         Register outReg;
         if (output.hasValue()) {
             outReg = output.valueReg().scratchReg();
         } else {
--- a/js/src/jit/RangeAnalysis.cpp
+++ b/js/src/jit/RangeAnalysis.cpp
@@ -255,24 +255,26 @@ RangeAnalysis::addBetaNodes()
             if (bound == 0)
                 comp.refineToExcludeNegativeZero();
             break;
           case JSOP_STRICTEQ:
             // A strict comparison can test for things other than numeric value.
             if (!compare->isNumericComparison())
                 continue;
             // Otherwise fall through to handle JSOP_STRICTEQ the same as JSOP_EQ.
+            MOZ_FALLTHROUGH;
           case JSOP_EQ:
             comp.setDouble(bound, bound);
             break;
           case JSOP_STRICTNE:
             // A strict comparison can test for things other than numeric value.
             if (!compare->isNumericComparison())
                 continue;
             // Otherwise fall through to handle JSOP_STRICTNE the same as JSOP_NE.
+            MOZ_FALLTHROUGH;
           case JSOP_NE:
             // Negative zero is not not-equal to zero.
             if (bound == 0) {
                 comp.refineToExcludeNegativeZero();
                 break;
             }
             continue; // well, we could have
                       // [-\inf, bound-1] U [bound+1, \inf] but we only use contiguous ranges.
@@ -3001,16 +3003,17 @@ RangeAnalysis::truncate()
               case MDefinition::Op_BitAnd:
               case MDefinition::Op_BitOr:
               case MDefinition::Op_BitXor:
               case MDefinition::Op_Lsh:
               case MDefinition::Op_Rsh:
               case MDefinition::Op_Ursh:
                 if (!bitops.append(static_cast<MBinaryBitwiseInstruction*>(*iter)))
                     return false;
+                break;
               default:;
             }
 
             bool shouldClone = false;
             MDefinition::TruncateKind kind = ComputeTruncateKind(*iter, &shouldClone);
             if (kind == MDefinition::NoTruncate)
                 continue;
 
--- a/js/src/jit/shared/CodeGenerator-shared-inl.h
+++ b/js/src/jit/shared/CodeGenerator-shared-inl.h
@@ -298,17 +298,17 @@ CodeGeneratorShared::verifyHeapAccessDis
 
     OtherOperand op;
     Disassembler::HeapAccess::Kind kind = isLoad ? HeapAccess::Load : HeapAccess::Store;
     switch (type) {
       case Scalar::Int8:
       case Scalar::Int16:
         if (kind == HeapAccess::Load)
             kind = HeapAccess::LoadSext32;
-        // FALL THROUGH
+        MOZ_FALLTHROUGH;
       case Scalar::Uint8:
       case Scalar::Uint16:
       case Scalar::Int32:
       case Scalar::Uint32:
         if (!alloc.isConstant()) {
             op = OtherOperand(ToRegister(alloc).encoding());
         } else {
             int32_t i = ToInt32(&alloc);
--- a/js/src/jsdtoa.cpp
+++ b/js/src/jsdtoa.cpp
@@ -131,17 +131,17 @@ js_dtostr(DtoaState* state, char* buffer
                     minNDigits = decPt + precision;
                 else
                     minNDigits = decPt;
                 break;
 
             case DTOSTR_EXPONENTIAL:
                 MOZ_ASSERT(precision > 0);
                 minNDigits = precision;
-                /* Fall through */
+                MOZ_FALLTHROUGH;
             case DTOSTR_STANDARD_EXPONENTIAL:
                 exponentialNotation = true;
                 break;
 
             case DTOSTR_PRECISION:
                 MOZ_ASSERT(precision > 0);
                 minNDigits = precision;
                 if (decPt < -5 || decPt > precision)
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -6047,33 +6047,34 @@ GCRuntime::incrementalCollectSlice(Slice
     switch (incrementalState) {
       case NO_INCREMENTAL:
         initialReason = reason;
         cleanUpEverything = ShouldCleanUpEverything(reason, invocationKind);
         isCompacting = shouldCompact();
         lastMarkSlice = false;
 
         incrementalState = MARK_ROOTS;
-        /* fall through */
+
+        MOZ_FALLTHROUGH;
 
       case MARK_ROOTS:
         if (!beginMarkPhase(reason)) {
             incrementalState = NO_INCREMENTAL;
             return;
         }
 
         if (!destroyingRuntime)
             pushZealSelectedObjects();
 
         incrementalState = MARK;
 
         if (isIncremental && zeal == ZealIncrementalRootsThenFinish)
             break;
 
-        /* fall through */
+        MOZ_FALLTHROUGH;
 
       case MARK:
         AutoGCRooter::traceAllWrappers(&marker);
 
         /* If we needed delayed marking for gray roots, then collect until done. */
         if (!hasBufferedGrayRoots()) {
             budget.makeUnlimited();
             isIncremental = false;
@@ -6109,31 +6110,33 @@ GCRuntime::incrementalCollectSlice(Slice
 
         /*
          * Always yield here when running in incremental multi-slice zeal
          * mode, so RunDebugGC can reset the slice buget.
          */
         if (isIncremental && zeal == ZealIncrementalMultipleSlices)
             break;
 
-        /* fall through */
+        MOZ_FALLTHROUGH;
 
       case SWEEP:
         if (sweepPhase(budget) == NotFinished)
             break;
 
         endSweepPhase(destroyingRuntime);
 
         incrementalState = COMPACT;
         MOZ_ASSERT(!startedCompacting);
 
         /* Yield before compacting since it is not incremental. */
         if (isCompacting && isIncremental)
             break;
 
+        MOZ_FALLTHROUGH;
+
       case COMPACT:
         if (isCompacting) {
             if (!startedCompacting && beginCompactPhase() == NotFinished)
                 break;
 
             if (compactPhase(reason, budget) == NotFinished)
                 break;
 
--- a/js/src/jsiter.cpp
+++ b/js/src/jsiter.cpp
@@ -525,23 +525,23 @@ GetCustomIterator(JSContext* cx, HandleO
 }
 
 template <typename T>
 static inline bool
 Compare(T* a, T* b, size_t c)
 {
     size_t n = (c + size_t(7)) / size_t(8);
     switch (c % 8) {
-      case 0: do { if (*a++ != *b++) return false;
-      case 7:      if (*a++ != *b++) return false;
-      case 6:      if (*a++ != *b++) return false;
-      case 5:      if (*a++ != *b++) return false;
-      case 4:      if (*a++ != *b++) return false;
-      case 3:      if (*a++ != *b++) return false;
-      case 2:      if (*a++ != *b++) return false;
+      case 0: do { if (*a++ != *b++) return false; MOZ_FALLTHROUGH;
+      case 7:      if (*a++ != *b++) return false; MOZ_FALLTHROUGH;
+      case 6:      if (*a++ != *b++) return false; MOZ_FALLTHROUGH;
+      case 5:      if (*a++ != *b++) return false; MOZ_FALLTHROUGH;
+      case 4:      if (*a++ != *b++) return false; MOZ_FALLTHROUGH;
+      case 3:      if (*a++ != *b++) return false; MOZ_FALLTHROUGH;
+      case 2:      if (*a++ != *b++) return false; MOZ_FALLTHROUGH;
       case 1:      if (*a++ != *b++) return false;
               } while (--n > 0);
     }
     return true;
 }
 
 static bool legacy_iterator_next(JSContext* cx, unsigned argc, Value* vp);
 
--- a/js/src/jsstr.cpp
+++ b/js/src/jsstr.cpp
@@ -1124,23 +1124,23 @@ struct ManualCmp {
 template <typename TextChar, typename PatChar>
 static const TextChar*
 FirstCharMatcherUnrolled(const TextChar* text, uint32_t n, const PatChar pat)
 {
     const TextChar* textend = text + n;
     const TextChar* t = text;
 
     switch ((textend - t) & 7) {
-        case 0: if (*t++ == pat) return t - 1;
-        case 7: if (*t++ == pat) return t - 1;
-        case 6: if (*t++ == pat) return t - 1;
-        case 5: if (*t++ == pat) return t - 1;
-        case 4: if (*t++ == pat) return t - 1;
-        case 3: if (*t++ == pat) return t - 1;
-        case 2: if (*t++ == pat) return t - 1;
+        case 0: if (*t++ == pat) return t - 1; MOZ_FALLTHROUGH;
+        case 7: if (*t++ == pat) return t - 1; MOZ_FALLTHROUGH;
+        case 6: if (*t++ == pat) return t - 1; MOZ_FALLTHROUGH;
+        case 5: if (*t++ == pat) return t - 1; MOZ_FALLTHROUGH;
+        case 4: if (*t++ == pat) return t - 1; MOZ_FALLTHROUGH;
+        case 3: if (*t++ == pat) return t - 1; MOZ_FALLTHROUGH;
+        case 2: if (*t++ == pat) return t - 1; MOZ_FALLTHROUGH;
         case 1: if (*t++ == pat) return t - 1;
     }
     while (textend != t) {
         if (t[0] == pat) return t;
         if (t[1] == pat) return t + 1;
         if (t[2] == pat) return t + 2;
         if (t[3] == pat) return t + 3;
         if (t[4] == pat) return t + 4;
--- a/js/src/moz.build
+++ b/js/src/moz.build
@@ -256,17 +256,16 @@ UNIFIED_SOURCES += [
     'jit/ValueNumbering.cpp',
     'jit/VMFunctions.cpp',
     'jsalloc.cpp',
     'jsapi.cpp',
     'jsbool.cpp',
     'jscntxt.cpp',
     'jscompartment.cpp',
     'jsdate.cpp',
-    'jsdtoa.cpp',
     'jsexn.cpp',
     'jsfriendapi.cpp',
     'jsfun.cpp',
     'jsgc.cpp',
     'jsiter.cpp',
     'jsnativestack.cpp',
     'jsnum.cpp',
     'jsobj.cpp',
@@ -344,29 +343,32 @@ UNIFIED_SOURCES += [
 ]
 
 # jsarray.cpp and jsatom.cpp cannot be built in unified mode because
 # xpcshell is broken during packaging when compiled with gcc-4.8.2
 # builtin/RegExp.cpp cannot be built in unified mode because it is built
 # without PGO
 # frontend/Parser.cpp cannot be built in unified mode because of explicit
 # template instantiations.
+# jsdtoa.cpp cannot be built in unified mode because we want to suppress
+# compiler warnings in third-party dtoa.c.
 # jsmath.cpp cannot be built in unified mode because it needs to pull rand_s
 # from <stdlib.h> on Windows through a preprocessor define.
 # jsutil.cpp cannot be built in unified mode because it is needed for
 # check-vanilla-allocations.
 # StoreBuffer.cpp cannot be built in unified because its template
 # instantiations may or may not be needed depending on what it gets bundled
 # with.
 SOURCES += [
     'builtin/RegExp.cpp',
     'frontend/Parser.cpp',
     'gc/StoreBuffer.cpp',
     'jsarray.cpp',
     'jsatom.cpp',
+    'jsdtoa.cpp',
     'jsmath.cpp',
     'jsutil.cpp',
     'vm/Initialization.cpp',
 ]
 
 if CONFIG['JS_POSIX_NSPR']:
     UNIFIED_SOURCES += [
         'vm/PosixNSPR.cpp',
@@ -712,8 +714,12 @@ selfhosted.inputs = [
 ]
 
 if CONFIG['JS_HAS_CTYPES']:
     if CONFIG['MOZ_NATIVE_FFI']:
         CXXFLAGS += CONFIG['MOZ_FFI_CFLAGS']
     else:
         # Windows needs this to be linked with a static library.
         DEFINES['FFI_BUILDING'] = True
+
+# Suppress warnings in third-party code.
+if CONFIG['CLANG_CXX']:
+    SOURCES['jsdtoa.cpp'].flags += ['-Wno-implicit-fallthrough']
--- a/js/src/vm/Runtime.cpp
+++ b/js/src/vm/Runtime.cpp
@@ -865,18 +865,20 @@ void
 JSRuntime::assertCanLock(RuntimeLock which)
 {
     // In the switch below, each case falls through to the one below it. None
     // of the runtime locks are reentrant, and when multiple locks are acquired
     // it must be done in the order below.
     switch (which) {
       case ExclusiveAccessLock:
         MOZ_ASSERT(exclusiveAccessOwner != PR_GetCurrentThread());
+        MOZ_FALLTHROUGH;
       case HelperThreadStateLock:
         MOZ_ASSERT(!HelperThreadState().isLocked());
+        MOZ_FALLTHROUGH;
       case GCLock:
         gc.assertCanLock();
         break;
       default:
         MOZ_CRASH();
     }
 }
 
--- a/js/xpconnect/src/XPCConvert.cpp
+++ b/js/xpconnect/src/XPCConvert.cpp
@@ -487,17 +487,17 @@ XPCConvert::JSData2Native(void* d, Handl
     }
 
     case nsXPTType::T_ASTRING:
     {
         if (s.isUndefined()) {
             (**((nsAString**)d)).SetIsVoid(true);
             return true;
         }
-        // Fall through to T_DOMSTRING case.
+        MOZ_FALLTHROUGH;
     }
     case nsXPTType::T_DOMSTRING:
     {
         if (s.isNull()) {
             (**((nsAString**)d)).SetIsVoid(true);
             return true;
         }
         size_t length = 0;
--- a/js/xpconnect/src/XPCShellImpl.cpp
+++ b/js/xpconnect/src/XPCShellImpl.cpp
@@ -958,16 +958,17 @@ ProcessArgsForCompartment(JSContext* cx,
           case 'v':
           case 'f':
           case 'e':
             if (++i == argc)
                 return;
             break;
         case 'S':
             RuntimeOptionsRef(cx).toggleWerror();
+            MOZ_FALLTHROUGH; // because -S implies -s
         case 's':
             RuntimeOptionsRef(cx).toggleExtraWarnings();
             break;
         case 'I':
             RuntimeOptionsRef(cx).toggleIon()
                                  .toggleAsmJS();
             break;
         }