Bug 1235277 - Define MOZ_FALLTHROUGH_ASSERT to workaround -Wunreachable-code warnings about MOZ_FALLTHROUGH in debug builds. r=botond
authorChris Peterson <cpeterson@mozilla.com>
Sun, 27 Dec 2015 13:27:17 -0700
changeset 277727 d0a8d632dce55ab7005aa38e6b8ed5ab377ec3bd
parent 277726 9dbf30a524936743102e1104236d7f066b93d4bf
child 277728 7752a04d13add587ac0decb59daf57fce513ae0d
push id69576
push usercpeterson@mozilla.com
push dateTue, 29 Dec 2015 01:57:18 +0000
treeherdermozilla-inbound@1b5c9493e4e9 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbotond
bugs1235277
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 1235277 - Define MOZ_FALLTHROUGH_ASSERT to workaround -Wunreachable-code warnings about MOZ_FALLTHROUGH in debug builds. r=botond
mfbt/Assertions.h
mfbt/Attributes.h
--- a/mfbt/Assertions.h
+++ b/mfbt/Assertions.h
@@ -491,16 +491,55 @@ struct AssertionConditionType
    MOZ_ASSERT(false, "MOZ_ASSERT_UNREACHABLE: " reason)
 
 #define MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE(reason) \
    do { \
      MOZ_ASSERT_UNREACHABLE(reason); \
      MOZ_ASSUME_UNREACHABLE_MARKER(); \
    } while (0)
 
+/**
+ * MOZ_FALLTHROUGH_ASSERT is an annotation to suppress compiler warnings about
+ * switch cases that MOZ_ASSERT(false) (or its alias MOZ_ASSERT_UNREACHABLE) in
+ * debug builds, but intentionally fall through in release builds to handle
+ * unexpected values.
+ *
+ * Why do we need MOZ_FALLTHROUGH_ASSERT in addition to MOZ_FALLTHROUGH? In
+ * release builds, the MOZ_ASSERT(false) will expand to `do { } while (0)`,
+ * requiring a MOZ_FALLTHROUGH annotation to suppress a -Wimplicit-fallthrough
+ * warning. In debug builds, the MOZ_ASSERT(false) will expand to something like
+ * `if (true) { MOZ_CRASH(); }` and the MOZ_FALLTHROUGH annotation will cause
+ * a -Wunreachable-code warning. The MOZ_FALLTHROUGH_ASSERT macro breaks this
+ * warning stalemate.
+ *
+ * // Example before MOZ_FALLTHROUGH_ASSERT:
+ * switch (foo) {
+ *   default:
+ *     // This case wants to assert in debug builds, fall through in release.
+ *     MOZ_ASSERT(false); // -Wimplicit-fallthrough warning in release builds!
+ *     MOZ_FALLTHROUGH;   // but -Wunreachable-code warning in debug builds!
+ *   case 5:
+ *     return 5;
+ * }
+ *
+ * // Example with MOZ_FALLTHROUGH_ASSERT:
+ * switch (foo) {
+ *   default:
+ *     // This case asserts in debug builds, falls through in release.
+ *     MOZ_FALLTHROUGH_ASSERT("Unexpected foo value?!");
+ *   case 5:
+ *     return 5;
+ * }
+ */
+#ifdef DEBUG
+#  define MOZ_FALLTHROUGH_ASSERT(reason) MOZ_CRASH("MOZ_FALLTHROUGH_ASSERT: " reason)
+#else
+#  define MOZ_FALLTHROUGH_ASSERT(...) MOZ_FALLTHROUGH
+#endif
+
 /*
  * MOZ_ALWAYS_TRUE(expr) and MOZ_ALWAYS_FALSE(expr) always evaluate the provided
  * expression, in debug builds and in release builds both.  Then, in debug
  * builds only, the value of the expression is asserted either true or false
  * using MOZ_ASSERT.
  */
 #ifdef DEBUG
 #  define MOZ_ALWAYS_TRUE(expr)      MOZ_ASSERT((expr))
--- a/mfbt/Attributes.h
+++ b/mfbt/Attributes.h
@@ -334,26 +334,37 @@
 #  define MOZ_WARN_UNUSED_RESULT __attribute__ ((warn_unused_result))
 #else
 #  define MOZ_WARN_UNUSED_RESULT
 #endif
 
 /**
  * MOZ_FALLTHROUGH is an annotation to suppress compiler warnings about switch
  * cases that fall through without a break or return statement. MOZ_FALLTHROUGH
- * is only needed on cases that have code:
+ * is only needed on cases that have code.
+ *
+ * MOZ_FALLTHROUGH_ASSERT is an annotation to suppress compiler warnings about
+ * switch cases that MOZ_ASSERT(false) (or its alias MOZ_ASSERT_UNREACHABLE) in
+ * debug builds, but intentionally fall through in release builds. See comment
+ * in Assertions.h for more details.
  *
  * switch (foo) {
  *   case 1: // These cases have no code. No fallthrough annotations are needed.
  *   case 2:
- *   case 3:
- *     foo = 4; // This case has code, so a fallthrough annotation is needed:
+ *   case 3: // This case has code, so a fallthrough annotation is needed!
+ *     foo++;
  *     MOZ_FALLTHROUGH;
+ *   case 4:
+ *     return foo;
+ *
  *   default:
- *     return foo;
+ *     // This case asserts in debug builds, falls through in release.
+ *     MOZ_FALLTHROUGH_ASSERT("Unexpected foo value?!");
+ *   case 5:
+ *     return 5;
  * }
  */
 #if defined(__clang__) && __cplusplus >= 201103L
    /* clang's fallthrough annotations are only available starting in C++11. */
 #  define MOZ_FALLTHROUGH [[clang::fallthrough]]
 #elif defined(_MSC_VER)
    /*
     * MSVC's __fallthrough annotations are checked by /analyze (Code Analysis):