Import Tint changes from Dawn

Changes:
  - 7cdaffed00cc5a7d9dd9af639e06af92438cb1be [tint][ice] Make the InternalCompilerErrors abort by Ben Clayton <bclayton@google.com>
GitOrigin-RevId: 7cdaffed00cc5a7d9dd9af639e06af92438cb1be
Change-Id: Ie482680e8c3fc681cfe07576a94a1fddc37105a4
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/187640
Commit-Queue: James Price <jrprice@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: James Price <jrprice@google.com>
diff --git a/src/tint/CMakeLists.txt b/src/tint/CMakeLists.txt
index 80cbdfa..0405576 100644
--- a/src/tint/CMakeLists.txt
+++ b/src/tint/CMakeLists.txt
@@ -153,9 +153,15 @@
       target_compile_options(${TARGET} PRIVATE /WX)
     endif()
 
-    # When building with clang-cl on Windows, try to match our clang build
-    # options as much as possible.
+    # Some versions of MSVC ignores the [[noreturn]] on ~InternalCompilerError(), triggering a
+    # warning if its the last statement on a function that has a return value.
+    target_compile_options(${TARGET} PRIVATE
+      /wd4715 # not all control paths return a value
+    )
+
     if(COMPILER_IS_CLANG_CL)
+      # When building with clang-cl on Windows, try to match our clang build
+      # options as much as possible.
       target_compile_options(${TARGET} PRIVATE
         ${COMMON_GNU_OPTIONS}
         ${COMMON_CLANG_OPTIONS}
@@ -169,6 +175,14 @@
         -Wno-reserved-id-macro
         -Wno-language-extension-token
       )
+    else()
+      if(NOT $CMAKE_BUILD_TYPE STREQUAL "Debug")
+        # MSVC sometimes warns code is unreachable after inlining of code, which
+        # is impossible to silence with pragmas.
+        target_compile_options(${TARGET} PRIVATE
+          /wd4702 # unreachable code
+        )
+      endif()
     endif()
   endif()
 
@@ -227,6 +241,7 @@
 
 function(tint_bench_compile_options TARGET)
   tint_core_compile_options(${TARGET})
+  set_target_properties(${TARGET} PROPERTIES FOLDER "Benchmarks")
 endfunction()
 
 function(tint_fuzz_compile_options TARGET)
diff --git a/src/tint/cmd/fuzz/ir/fuzz.cc b/src/tint/cmd/fuzz/ir/fuzz.cc
index a74fef3..771a37a 100644
--- a/src/tint/cmd/fuzz/ir/fuzz.cc
+++ b/src/tint/cmd/fuzz/ir/fuzz.cc
@@ -83,7 +83,6 @@
 
             if (auto val = core::ir::Validate(ir.Get()); val != Success) {
                 TINT_ICE() << val.Failure();
-                return;
             }
 
             return fn(ir.Get(), data);
diff --git a/src/tint/cmd/test/BUILD.bazel b/src/tint/cmd/test/BUILD.bazel
index 6d99985..c99263c 100644
--- a/src/tint/cmd/test/BUILD.bazel
+++ b/src/tint/cmd/test/BUILD.bazel
@@ -74,9 +74,7 @@
     "//src/tint/utils/containers:test",
     "//src/tint/utils/diagnostic:test",
     "//src/tint/utils/file:test",
-    "//src/tint/utils/ice",
     "//src/tint/utils/ice:test",
-    "//src/tint/utils/macros",
     "//src/tint/utils/macros:test",
     "//src/tint/utils/math:test",
     "//src/tint/utils/memory:test",
diff --git a/src/tint/cmd/test/BUILD.cmake b/src/tint/cmd/test/BUILD.cmake
index a280f99..0cb839e 100644
--- a/src/tint/cmd/test/BUILD.cmake
+++ b/src/tint/cmd/test/BUILD.cmake
@@ -75,9 +75,7 @@
   tint_utils_containers_test
   tint_utils_diagnostic_test
   tint_utils_file_test
-  tint_utils_ice
   tint_utils_ice_test
-  tint_utils_macros
   tint_utils_macros_test
   tint_utils_math_test
   tint_utils_memory_test
diff --git a/src/tint/cmd/test/BUILD.gn b/src/tint/cmd/test/BUILD.gn
index 59b2b6c..54897e3 100644
--- a/src/tint/cmd/test/BUILD.gn
+++ b/src/tint/cmd/test/BUILD.gn
@@ -80,9 +80,7 @@
       "${tint_src_dir}/utils/containers:unittests",
       "${tint_src_dir}/utils/diagnostic:unittests",
       "${tint_src_dir}/utils/file:unittests",
-      "${tint_src_dir}/utils/ice",
       "${tint_src_dir}/utils/ice:unittests",
-      "${tint_src_dir}/utils/macros",
       "${tint_src_dir}/utils/macros:unittests",
       "${tint_src_dir}/utils/math:unittests",
       "${tint_src_dir}/utils/memory:unittests",
diff --git a/src/tint/cmd/test/main_test.cc b/src/tint/cmd/test/main_test.cc
index 5409746..fcd0e5e 100644
--- a/src/tint/cmd/test/main_test.cc
+++ b/src/tint/cmd/test/main_test.cc
@@ -28,15 +28,6 @@
 #include "gmock/gmock.h"
 
 #include "src/tint/api/tint.h"
-#include "src/tint/utils/ice/ice.h"
-
-namespace {
-
-void TintInternalCompilerErrorReporter(const tint::InternalCompilerError& err) {
-    FAIL() << err.Error();
-}
-
-}  // namespace
 
 // Entry point for tint unit tests
 int main(int argc, char** argv) {
@@ -44,8 +35,6 @@
 
     tint::Initialize();
 
-    tint::SetInternalCompilerErrorReporter(&TintInternalCompilerErrorReporter);
-
     auto res = RUN_ALL_TESTS();
 
     tint::Shutdown();
diff --git a/src/tint/lang/core/constant/eval.cc b/src/tint/lang/core/constant/eval.cc
index 36069fd..105ed38 100644
--- a/src/tint/lang/core/constant/eval.cc
+++ b/src/tint/lang/core/constant/eval.cc
@@ -425,7 +425,6 @@
                         if (members[i]->Type() != target_el_ty) {
                             TINT_ICE()
                                 << "inconsistent target struct member types for SplatConvert";
-                            return false;
                         }
                     }
                 } else {
@@ -447,7 +446,6 @@
                     if (TINT_UNLIKELY(str->Members().Length() != el_count)) {
                         TINT_ICE()
                             << "const-eval conversion of structure has mismatched element counts";
-                        return false;
                     }
                     // Struct composites can have different types for each member.
                     auto members = str->Members();
@@ -1222,7 +1220,6 @@
                 v2->Index(0), v2->Index(1), v2->Index(2), v2->Index(3));
     }
     TINT_ICE() << "Expected vector";
-    return error;
 }
 
 Eval::Result Eval::Length(const Source& source, const core::type::Type* ty, const Value* c0) {
@@ -2066,7 +2063,6 @@
 
     if (TINT_UNLIKELY(!args[1]->Type()->DeepestElement()->Is<core::type::U32>())) {
         TINT_ICE() << "Element type of rhs of ShiftLeft must be a u32";
-        return error;
     }
 
     return TransformBinaryElements(mgr, ty, transform, args[0], args[1]);
@@ -2132,7 +2128,6 @@
 
     if (TINT_UNLIKELY(!args[1]->Type()->DeepestElement()->Is<core::type::U32>())) {
         TINT_ICE() << "Element type of rhs of ShiftLeft must be a u32";
-        return error;
     }
 
     return TransformBinaryElements(mgr, ty, transform, args[0], args[1]);
@@ -2500,7 +2495,6 @@
                                            me(0, 3), me(1, 3), me(2, 3), me(3, 3));
         }
         TINT_ICE() << "Unexpected number of matrix rows";
-        return error;
     };
     auto r = calculate();
     if (r != Success) {
diff --git a/src/tint/lang/core/intrinsic/table.cc b/src/tint/lang/core/intrinsic/table.cc
index b3ab2f6..0caceee 100644
--- a/src/tint/lang/core/intrinsic/table.cc
+++ b/src/tint/lang/core/intrinsic/table.cc
@@ -246,7 +246,6 @@
             StyledText err;
             err << "MatchState.MatchState() returned null";
             TINT_ICE() << err.Plain();
-            return err;
         }
     } else {
         return_type = context.types.void_();
@@ -495,7 +494,6 @@
         }
     }
     TINT_ICE() << err.Plain();
-    return err;
 }
 
 }  // namespace
diff --git a/src/tint/lang/core/ir/access_test.cc b/src/tint/lang/core/ir/access_test.cc
index f3be39c..aee7288 100644
--- a/src/tint/lang/core/ir/access_test.cc
+++ b/src/tint/lang/core/ir/access_test.cc
@@ -28,7 +28,7 @@
 #include "src/tint/lang/core/ir/access.h"
 
 #include "gmock/gmock.h"
-#include "gtest/gtest-spi.h"
+#include "gtest/gtest.h"
 #include "src/tint/lang/core/ir/ir_helper_test.h"
 
 using namespace tint::core::fluent_types;     // NOLINT
@@ -62,7 +62,7 @@
 }
 
 TEST_F(IR_AccessTest, Fail_NullType) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             Module mod;
             Builder b{mod};
diff --git a/src/tint/lang/core/ir/binary/decode.cc b/src/tint/lang/core/ir/binary/decode.cc
index 5fbb84d..eb320b2 100644
--- a/src/tint/lang/core/ir/binary/decode.cc
+++ b/src/tint/lang/core/ir/binary/decode.cc
@@ -202,7 +202,6 @@
                 break;
         }
         TINT_ICE() << "unhandled PipelineStage: " << stage;
-        return Function::PipelineStage::kCompute;
     }
 
     ////////////////////////////////////////////////////////////////////////////
@@ -328,7 +327,7 @@
             case pb::Instruction::KindCase::KIND_NOT_SET:
                 break;
         }
-        TINT_ASSERT_OR_RETURN_VALUE(inst_out, nullptr);
+        TINT_ASSERT(inst_out);
 
         Vector<ir::Value*, 4> operands;
         for (auto id : inst_in.operands()) {
@@ -556,7 +555,6 @@
                 break;
         }
         TINT_ICE() << type_in.kind_case();
-        return nullptr;
     }
 
     const type::Type* CreateTypeBasic(pb::TypeBasic basic_in) {
@@ -579,7 +577,6 @@
                 break;
         }
         TINT_ICE() << "invalid TypeBasic: " << basic_in;
-        return nullptr;
     }
 
     const type::Vector* CreateTypeVector(const pb::TypeVector& vector_in) {
@@ -723,7 +720,6 @@
 
         if (!value_out) {
             TINT_ICE() << "invalid TypeDecl.kind: " << value_in.kind_case();
-            return nullptr;
         }
 
         return value_out;
@@ -802,7 +798,6 @@
                 break;
         }
         TINT_ICE() << "invalid ConstantValue.kind: " << value_in.kind_case();
-        return nullptr;
     }
 
     const core::constant::Value* CreateConstantScalar(const pb::ConstantValueScalar& value_in) {
@@ -821,7 +816,6 @@
                 break;
         }
         TINT_ICE() << "invalid ConstantValueScalar.kind: " << value_in.kind_case();
-        return nullptr;
     }
 
     const core::constant::Value* CreateConstantComposite(
@@ -892,7 +886,6 @@
                 break;
         }
         TINT_ICE() << "invalid AddressSpace: " << in;
-        return core::AddressSpace::kUndefined;
     }
 
     core::Access AccessControl(pb::AccessControl in) {
@@ -909,7 +902,6 @@
                 break;
         }
         TINT_ICE() << "invalid Access: " << in;
-        return core::Access::kUndefined;
     }
 
     core::UnaryOp UnaryOp(pb::UnaryOp in) {
@@ -930,7 +922,6 @@
                 break;
         }
         TINT_ICE() << "invalid UnaryOp: " << in;
-        return core::UnaryOp::kComplement;
     }
 
     core::BinaryOp BinaryOp(pb::BinaryOp in) {
@@ -977,7 +968,6 @@
                 break;
         }
         TINT_ICE() << "invalid BinaryOp: " << in;
-        return core::BinaryOp::kAdd;
     }
 
     core::type::TextureDimension TextureDimension(pb::TextureDimension in) {
@@ -1001,7 +991,6 @@
         }
 
         TINT_ICE() << "invalid TextureDimension: " << in;
-        return core::type::TextureDimension::k1d;
     }
 
     core::TexelFormat TexelFormat(pb::TexelFormat in) {
@@ -1049,7 +1038,6 @@
         }
 
         TINT_ICE() << "invalid TexelFormat: " << in;
-        return core::TexelFormat::kBgra8Unorm;
     }
 
     core::type::SamplerKind SamplerKind(pb::SamplerKind in) {
@@ -1065,7 +1053,6 @@
         }
 
         TINT_ICE() << "invalid SamplerKind: " << in;
-        return core::type::SamplerKind::kSampler;
     }
 
     core::InterpolationType InterpolationType(pb::InterpolationType in) {
@@ -1082,7 +1069,6 @@
                 break;
         }
         TINT_ICE() << "invalid InterpolationType: " << in;
-        return core::InterpolationType::kFlat;
     }
 
     core::InterpolationSampling InterpolationSampling(pb::InterpolationSampling in) {
@@ -1099,7 +1085,6 @@
                 break;
         }
         TINT_ICE() << "invalid InterpolationSampling: " << in;
-        return core::InterpolationSampling::kCenter;
     }
 
     core::BuiltinValue BuiltinValue(pb::BuiltinValue in) {
@@ -1140,7 +1125,6 @@
                 break;
         }
         TINT_ICE() << "invalid BuiltinValue: " << in;
-        return core::BuiltinValue::kPointSize;
     }
 
     core::BuiltinFn BuiltinFn(pb::BuiltinFn in) {
@@ -1393,7 +1377,6 @@
                 break;
         }
         TINT_ICE() << "invalid BuiltinFn: " << in;
-        return core::BuiltinFn::kAbs;
     }
 };
 
diff --git a/src/tint/lang/core/ir/binary/encode.cc b/src/tint/lang/core/ir/binary/encode.cc
index 562a568..70305bd 100644
--- a/src/tint/lang/core/ir/binary/encode.cc
+++ b/src/tint/lang/core/ir/binary/encode.cc
@@ -166,7 +166,6 @@
                 break;
         }
         TINT_ICE() << "unhandled PipelineStage: " << stage;
-        return pb::PipelineStage::Compute;
     }
 
     ////////////////////////////////////////////////////////////////////////////
@@ -663,7 +662,6 @@
                 break;
         }
         TINT_ICE() << "invalid AddressSpace: " << in;
-        return pb::AddressSpace::function;
     }
 
     pb::AccessControl AccessControl(core::Access in) {
@@ -678,7 +676,6 @@
                 break;
         }
         TINT_ICE() << "invalid Access: " << in;
-        return pb::AccessControl::read;
     }
 
     pb::UnaryOp UnaryOp(core::UnaryOp in) {
@@ -695,7 +692,6 @@
                 return pb::UnaryOp::not_;
         }
         TINT_ICE() << "invalid UnaryOp: " << in;
-        return pb::UnaryOp::complement;
     }
 
     pb::BinaryOp BinaryOp(core::BinaryOp in) {
@@ -739,7 +735,6 @@
         }
 
         TINT_ICE() << "invalid BinaryOp: " << in;
-        return pb::BinaryOp::add_;
     }
 
     pb::TextureDimension TextureDimension(core::type::TextureDimension in) {
@@ -761,7 +756,6 @@
         }
 
         TINT_ICE() << "invalid TextureDimension: " << in;
-        return pb::TextureDimension::_1d;
     }
 
     pb::TexelFormat TexelFormat(core::TexelFormat in) {
@@ -807,7 +801,6 @@
         }
 
         TINT_ICE() << "invalid TexelFormat: " << in;
-        return pb::TexelFormat::bgra8_unorm;
     }
 
     pb::SamplerKind SamplerKind(core::type::SamplerKind in) {
@@ -819,7 +812,6 @@
         }
 
         TINT_ICE() << "invalid SamplerKind: " << in;
-        return pb::SamplerKind::sampler;
     }
 
     pb::InterpolationType InterpolationType(core::InterpolationType in) {
@@ -834,7 +826,6 @@
                 break;
         }
         TINT_ICE() << "invalid InterpolationType: " << in;
-        return pb::InterpolationType::flat;
     }
 
     pb::InterpolationSampling InterpolationSampling(core::InterpolationSampling in) {
@@ -849,7 +840,6 @@
                 break;
         }
         TINT_ICE() << "invalid InterpolationSampling: " << in;
-        return pb::InterpolationSampling::center;
     }
 
     pb::BuiltinValue BuiltinValue(core::BuiltinValue in) {
@@ -888,7 +878,6 @@
                 break;
         }
         TINT_ICE() << "invalid BuiltinValue: " << in;
-        return pb::BuiltinValue::point_size;
     }
 
     pb::BuiltinFn BuiltinFn(core::BuiltinFn in) {
@@ -1139,7 +1128,6 @@
                 break;
         }
         TINT_ICE() << "invalid BuiltinFn: " << in;
-        return pb::BuiltinFn::abs;
     }
 };
 
diff --git a/src/tint/lang/core/ir/binary/roundtrip_fuzz.cc b/src/tint/lang/core/ir/binary/roundtrip_fuzz.cc
index 7378a3f..a7d753b 100644
--- a/src/tint/lang/core/ir/binary/roundtrip_fuzz.cc
+++ b/src/tint/lang/core/ir/binary/roundtrip_fuzz.cc
@@ -37,13 +37,11 @@
     auto encoded = Encode(module);
     if (encoded != Success) {
         TINT_ICE() << "Encode() failed\n" << encoded.Failure();
-        return;
     }
 
     auto decoded = Decode(encoded->Slice());
     if (decoded != Success) {
         TINT_ICE() << "Decode() failed\n" << decoded.Failure();
-        return;
     }
 
     auto in = Disassemble(module).Plain();
@@ -59,7 +57,6 @@
                    << "-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n"
                    << out << "\n"
                    << "-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n";
-        return;
     }
 }
 
diff --git a/src/tint/lang/core/ir/bitcast_test.cc b/src/tint/lang/core/ir/bitcast_test.cc
index 833f460..c585375 100644
--- a/src/tint/lang/core/ir/bitcast_test.cc
+++ b/src/tint/lang/core/ir/bitcast_test.cc
@@ -26,7 +26,6 @@
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include "gmock/gmock.h"
-#include "gtest/gtest-spi.h"
 #include "src/tint/lang/core/fluent_types.h"
 #include "src/tint/lang/core/ir/builder.h"
 #include "src/tint/lang/core/ir/constant.h"
@@ -73,7 +72,7 @@
 }
 
 TEST_F(IR_BitcastTest, Fail_NullType) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             Module mod;
             Builder b{mod};
diff --git a/src/tint/lang/core/ir/block.cc b/src/tint/lang/core/ir/block.cc
index 8597977..6d4a803 100644
--- a/src/tint/lang/core/ir/block.cc
+++ b/src/tint/lang/core/ir/block.cc
@@ -42,7 +42,6 @@
 
 Block* Block::Clone(CloneContext&) {
     TINT_UNREACHABLE() << "blocks must be cloned with CloneInto";
-    return nullptr;
 }
 
 void Block::CloneInto(CloneContext& ctx, Block* out) {
@@ -65,8 +64,8 @@
 }
 
 Instruction* Block::Prepend(Instruction* inst) {
-    TINT_ASSERT_OR_RETURN_VALUE(inst, inst);
-    TINT_ASSERT_OR_RETURN_VALUE(inst->Block() == nullptr, inst);
+    TINT_ASSERT(inst);
+    TINT_ASSERT(inst->Block() == nullptr);
 
     inst->SetBlock(this);
     instructions_.count += 1;
@@ -84,8 +83,8 @@
 }
 
 Instruction* Block::Append(Instruction* inst) {
-    TINT_ASSERT_OR_RETURN_VALUE(inst, inst);
-    TINT_ASSERT_OR_RETURN_VALUE(inst->Block() == nullptr, inst);
+    TINT_ASSERT(inst);
+    TINT_ASSERT(inst->Block() == nullptr);
 
     inst->SetBlock(this);
     instructions_.count += 1;
@@ -103,10 +102,10 @@
 }
 
 void Block::InsertBefore(Instruction* before, Instruction* inst) {
-    TINT_ASSERT_OR_RETURN(before);
-    TINT_ASSERT_OR_RETURN(inst);
-    TINT_ASSERT_OR_RETURN(before->Block() == this);
-    TINT_ASSERT_OR_RETURN(inst->Block() == nullptr);
+    TINT_ASSERT(before);
+    TINT_ASSERT(inst);
+    TINT_ASSERT(before->Block() == this);
+    TINT_ASSERT(inst->Block() == nullptr);
 
     inst->SetBlock(this);
     instructions_.count += 1;
@@ -125,10 +124,10 @@
 }
 
 void Block::InsertAfter(Instruction* after, Instruction* inst) {
-    TINT_ASSERT_OR_RETURN(after);
-    TINT_ASSERT_OR_RETURN(inst);
-    TINT_ASSERT_OR_RETURN(after->Block() == this);
-    TINT_ASSERT_OR_RETURN(inst->Block() == nullptr);
+    TINT_ASSERT(after);
+    TINT_ASSERT(inst);
+    TINT_ASSERT(after->Block() == this);
+    TINT_ASSERT(inst->Block() == nullptr);
 
     inst->SetBlock(this);
     instructions_.count += 1;
@@ -146,10 +145,10 @@
 }
 
 void Block::Replace(Instruction* target, Instruction* inst) {
-    TINT_ASSERT_OR_RETURN(target);
-    TINT_ASSERT_OR_RETURN(inst);
-    TINT_ASSERT_OR_RETURN(target->Block() == this);
-    TINT_ASSERT_OR_RETURN(inst->Block() == nullptr);
+    TINT_ASSERT(target);
+    TINT_ASSERT(inst);
+    TINT_ASSERT(target->Block() == this);
+    TINT_ASSERT(inst->Block() == nullptr);
 
     inst->SetBlock(this);
     target->SetBlock(nullptr);
@@ -176,8 +175,8 @@
 }
 
 void Block::Remove(Instruction* inst) {
-    TINT_ASSERT_OR_RETURN(inst);
-    TINT_ASSERT_OR_RETURN(inst->Block() == this);
+    TINT_ASSERT(inst);
+    TINT_ASSERT(inst->Block() == this);
 
     inst->SetBlock(nullptr);
     instructions_.count -= 1;
diff --git a/src/tint/lang/core/ir/block_param_test.cc b/src/tint/lang/core/ir/block_param_test.cc
index 3917745..96a8e02 100644
--- a/src/tint/lang/core/ir/block_param_test.cc
+++ b/src/tint/lang/core/ir/block_param_test.cc
@@ -27,7 +27,6 @@
 
 #include <string>
 
-#include "gtest/gtest-spi.h"
 #include "src/tint/lang/core/ir/block_param.h"
 #include "src/tint/lang/core/ir/ir_helper_test.h"
 
@@ -38,7 +37,7 @@
 using IR_BlockParamTest = IRTestHelper;
 
 TEST_F(IR_BlockParamTest, Fail_NullType) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             Module mod;
             Builder b{mod};
diff --git a/src/tint/lang/core/ir/block_test.cc b/src/tint/lang/core/ir/block_test.cc
index 8e2f3b6..ece2f28 100644
--- a/src/tint/lang/core/ir/block_test.cc
+++ b/src/tint/lang/core/ir/block_test.cc
@@ -26,7 +26,6 @@
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include "src/tint/lang/core/ir/block.h"
-#include "gtest/gtest-spi.h"
 #include "src/tint/lang/core/ir/ir_helper_test.h"
 
 namespace tint::core::ir {
@@ -435,262 +434,5 @@
     EXPECT_EQ(0u, blk->Length());
 }
 
-TEST_F(IR_BlockTest, Fail_PrependNullptr) {
-    EXPECT_FATAL_FAILURE(
-        {
-            Module mod;
-            Builder b{mod};
-
-            auto* blk = b.Block();
-            blk->Prepend(nullptr);
-        },
-        "internal compiler error");
-}
-
-TEST_F(IR_BlockTest, Fail_PrependAlreadyInserted) {
-    EXPECT_FATAL_FAILURE(
-        {
-            Module mod;
-            Builder b{mod};
-
-            auto* inst1 = b.Loop();
-            auto* blk = b.Block();
-            blk->Prepend(inst1);
-
-            blk->Prepend(inst1);
-        },
-        "internal compiler error");
-}
-
-TEST_F(IR_BlockTest, Fail_AppendNullptr) {
-    EXPECT_FATAL_FAILURE(
-        {
-            Module mod;
-            Builder b{mod};
-
-            auto* blk = b.Block();
-            blk->Append(nullptr);
-        },
-        "internal compiler error");
-}
-
-TEST_F(IR_BlockTest, Fail_AppendAlreadyInserted) {
-    EXPECT_FATAL_FAILURE(
-        {
-            Module mod;
-            Builder b{mod};
-
-            auto* inst1 = b.Loop();
-            auto* blk = b.Block();
-            blk->Append(inst1);
-            blk->Append(inst1);
-        },
-        "internal compiler error");
-}
-
-TEST_F(IR_BlockTest, Fail_InsertBeforeNullptrInst) {
-    EXPECT_FATAL_FAILURE(
-        {
-            Module mod;
-            Builder b{mod};
-
-            auto* inst1 = b.Loop();
-            auto* blk = b.Block();
-            blk->InsertBefore(nullptr, inst1);
-        },
-        "internal compiler error");
-}
-
-TEST_F(IR_BlockTest, Fail_InsertBeforeInstNullptr) {
-    EXPECT_FATAL_FAILURE(
-        {
-            Module mod;
-            Builder b{mod};
-
-            auto* inst1 = b.Loop();
-            auto* blk = b.Block();
-            blk->Append(inst1);
-            blk->InsertBefore(inst1, nullptr);
-        },
-        "internal compiler error");
-}
-
-TEST_F(IR_BlockTest, Fail_InsertBeforeDifferentBlock) {
-    EXPECT_FATAL_FAILURE(
-        {
-            Module mod;
-            Builder b{mod};
-
-            auto* inst1 = b.Loop();
-            auto* inst2 = b.Loop();
-            auto* blk1 = b.Block();
-            auto* blk2 = b.Block();
-            blk2->Append(inst1);
-            blk1->InsertBefore(inst1, inst2);
-        },
-        "internal compiler error");
-}
-
-TEST_F(IR_BlockTest, Fail_InsertBeforeAlreadyInserted) {
-    EXPECT_FATAL_FAILURE(
-        {
-            Module mod;
-            Builder b{mod};
-
-            auto* inst1 = b.Loop();
-            auto* inst2 = b.Loop();
-            auto* blk1 = b.Block();
-            blk1->Append(inst1);
-            blk1->Append(inst2);
-            blk1->InsertBefore(inst1, inst2);
-        },
-        "internal compiler error");
-}
-
-TEST_F(IR_BlockTest, Fail_InsertAfterNullptrInst) {
-    EXPECT_FATAL_FAILURE(
-        {
-            Module mod;
-            Builder b{mod};
-
-            auto* inst1 = b.Loop();
-            auto* blk = b.Block();
-            blk->InsertAfter(nullptr, inst1);
-        },
-        "internal compiler error");
-}
-
-TEST_F(IR_BlockTest, Fail_InsertAfterInstNullptr) {
-    EXPECT_FATAL_FAILURE(
-        {
-            Module mod;
-            Builder b{mod};
-
-            auto* inst1 = b.Loop();
-            auto* blk = b.Block();
-            blk->Append(inst1);
-            blk->InsertAfter(inst1, nullptr);
-        },
-        "internal compiler error");
-}
-
-TEST_F(IR_BlockTest, Fail_InsertAfterDifferentBlock) {
-    EXPECT_FATAL_FAILURE(
-        {
-            Module mod;
-            Builder b{mod};
-
-            auto* inst1 = b.Loop();
-            auto* inst2 = b.Loop();
-            auto* blk1 = b.Block();
-            auto* blk2 = b.Block();
-            blk2->Append(inst1);
-            blk1->InsertAfter(inst1, inst2);
-        },
-        "internal compiler error");
-}
-
-TEST_F(IR_BlockTest, Fail_InsertAfterAlreadyInserted) {
-    EXPECT_FATAL_FAILURE(
-        {
-            Module mod;
-            Builder b{mod};
-
-            auto* inst1 = b.Loop();
-            auto* inst2 = b.Loop();
-            auto* blk1 = b.Block();
-            blk1->Append(inst1);
-            blk1->Append(inst2);
-            blk1->InsertAfter(inst1, inst2);
-        },
-        "internal compiler error");
-}
-
-TEST_F(IR_BlockTest, Fail_ReplaceNullptrInst) {
-    EXPECT_FATAL_FAILURE(
-        {
-            Module mod;
-            Builder b{mod};
-
-            auto* inst1 = b.Loop();
-            auto* blk = b.Block();
-            blk->Replace(nullptr, inst1);
-        },
-        "internal compiler error");
-}
-
-TEST_F(IR_BlockTest, Fail_ReplaceInstNullptr) {
-    EXPECT_FATAL_FAILURE(
-        {
-            Module mod;
-            Builder b{mod};
-
-            auto* inst1 = b.Loop();
-            auto* blk = b.Block();
-            blk->Append(inst1);
-            blk->Replace(inst1, nullptr);
-        },
-        "internal compiler error");
-}
-
-TEST_F(IR_BlockTest, Fail_ReplaceDifferentBlock) {
-    EXPECT_FATAL_FAILURE(
-        {
-            Module mod;
-            Builder b{mod};
-
-            auto* inst1 = b.Loop();
-            auto* inst2 = b.Loop();
-            auto* blk1 = b.Block();
-            auto* blk2 = b.Block();
-            blk2->Append(inst1);
-            blk1->Replace(inst1, inst2);
-        },
-        "internal compiler error");
-}
-
-TEST_F(IR_BlockTest, Fail_ReplaceAlreadyInserted) {
-    EXPECT_FATAL_FAILURE(
-        {
-            Module mod;
-            Builder b{mod};
-
-            auto* inst1 = b.Loop();
-            auto* inst2 = b.Loop();
-            auto* blk1 = b.Block();
-            blk1->Append(inst1);
-            blk1->Append(inst2);
-            blk1->Replace(inst1, inst2);
-        },
-        "internal compiler error");
-}
-
-TEST_F(IR_BlockTest, Fail_RemoveNullptr) {
-    EXPECT_FATAL_FAILURE(
-        {
-            Module mod;
-            Builder b{mod};
-
-            auto* blk = b.Block();
-            blk->Remove(nullptr);
-        },
-        "internal compiler error");
-}
-
-TEST_F(IR_BlockTest, Fail_RemoveDifferentBlock) {
-    EXPECT_FATAL_FAILURE(
-        {
-            Module mod;
-            Builder b{mod};
-
-            auto* inst1 = b.Loop();
-            auto* blk1 = b.Block();
-            auto* blk2 = b.Block();
-            blk2->Append(inst1);
-            blk1->Remove(inst1);
-        },
-        "internal compiler error");
-}
-
 }  // namespace
 }  // namespace tint::core::ir
diff --git a/src/tint/lang/core/ir/break_if_test.cc b/src/tint/lang/core/ir/break_if_test.cc
index 9b36ad1..0e14900 100644
--- a/src/tint/lang/core/ir/break_if_test.cc
+++ b/src/tint/lang/core/ir/break_if_test.cc
@@ -28,7 +28,6 @@
 #include "src/tint/lang/core/ir/break_if.h"
 
 #include "gmock/gmock.h"
-#include "gtest/gtest-spi.h"
 #include "src/tint/lang/core/ir/ir_helper_test.h"
 
 namespace tint::core::ir {
@@ -61,7 +60,7 @@
 }
 
 TEST_F(IR_BreakIfTest, Fail_NullLoop) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             Module mod;
             Builder b{mod};
diff --git a/src/tint/lang/core/ir/constant_test.cc b/src/tint/lang/core/ir/constant_test.cc
index 972175e..c8b6ef1 100644
--- a/src/tint/lang/core/ir/constant_test.cc
+++ b/src/tint/lang/core/ir/constant_test.cc
@@ -25,7 +25,6 @@
 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-#include "gtest/gtest-spi.h"
 #include "src/tint/lang/core/fluent_types.h"
 #include "src/tint/lang/core/ir/builder.h"
 #include "src/tint/lang/core/ir/ir_helper_test.h"
@@ -113,11 +112,11 @@
 }
 
 TEST_F(IR_ConstantTest, Fail_NullValue) {
-    EXPECT_FATAL_FAILURE({ Constant c(nullptr); }, "");
+    EXPECT_DEATH({ Constant c(nullptr); }, "");
 }
 
 TEST_F(IR_ConstantTest, Fail_Builder_NullValue) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             Module mod;
             Builder b{mod};
diff --git a/src/tint/lang/core/ir/construct_test.cc b/src/tint/lang/core/ir/construct_test.cc
index 04c68dc..6e4b005 100644
--- a/src/tint/lang/core/ir/construct_test.cc
+++ b/src/tint/lang/core/ir/construct_test.cc
@@ -28,7 +28,6 @@
 #include "src/tint/lang/core/ir/construct.h"
 
 #include "gmock/gmock.h"
-#include "gtest/gtest-spi.h"
 #include "src/tint/lang/core/ir/ir_helper_test.h"
 
 namespace tint::core::ir {
@@ -57,7 +56,7 @@
 }
 
 TEST_F(IR_ConstructTest, Fail_NullType) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             Module mod;
             Builder b{mod};
diff --git a/src/tint/lang/core/ir/continue_test.cc b/src/tint/lang/core/ir/continue_test.cc
index 5346bde..79875cf 100644
--- a/src/tint/lang/core/ir/continue_test.cc
+++ b/src/tint/lang/core/ir/continue_test.cc
@@ -28,7 +28,6 @@
 #include "src/tint/lang/core/ir/continue.h"
 
 #include "gmock/gmock.h"
-#include "gtest/gtest-spi.h"
 #include "src/tint/lang/core/ir/ir_helper_test.h"
 
 namespace tint::core::ir {
@@ -59,7 +58,7 @@
 }
 
 TEST_F(IR_ContinueTest, Fail_NullLoop) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             Module mod;
             Builder b{mod};
diff --git a/src/tint/lang/core/ir/convert_test.cc b/src/tint/lang/core/ir/convert_test.cc
index ad5f53d..73c3076 100644
--- a/src/tint/lang/core/ir/convert_test.cc
+++ b/src/tint/lang/core/ir/convert_test.cc
@@ -26,7 +26,6 @@
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include "src/tint/lang/core/ir/convert.h"
-#include "gtest/gtest-spi.h"
 #include "src/tint/lang/core/ir/ir_helper_test.h"
 
 namespace tint::core::ir {
@@ -36,7 +35,7 @@
 using IR_ConvertTest = IRTestHelper;
 
 TEST_F(IR_ConvertTest, Fail_NullToType) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             Module mod;
             Builder b{mod};
diff --git a/src/tint/lang/core/ir/core_binary_test.cc b/src/tint/lang/core/ir/core_binary_test.cc
index d468a61..6fde891 100644
--- a/src/tint/lang/core/ir/core_binary_test.cc
+++ b/src/tint/lang/core/ir/core_binary_test.cc
@@ -26,7 +26,6 @@
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include "gmock/gmock.h"
-#include "gtest/gtest-spi.h"
 #include "src/tint/lang/core/fluent_types.h"
 #include "src/tint/lang/core/ir/builder.h"
 #include "src/tint/lang/core/ir/instruction.h"
@@ -41,7 +40,7 @@
 using IR_BinaryTest = IRTestHelper;
 
 TEST_F(IR_BinaryTest, Fail_NullType) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             Module mod;
             Builder b{mod};
diff --git a/src/tint/lang/core/ir/core_builtin_call_test.cc b/src/tint/lang/core/ir/core_builtin_call_test.cc
index 29c5913..7897862 100644
--- a/src/tint/lang/core/ir/core_builtin_call_test.cc
+++ b/src/tint/lang/core/ir/core_builtin_call_test.cc
@@ -26,7 +26,6 @@
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include "gmock/gmock.h"
-#include "gtest/gtest-spi.h"
 #include "src/tint/lang/core/ir/block_param.h"
 #include "src/tint/lang/core/ir/ir_helper_test.h"
 
@@ -56,7 +55,7 @@
 }
 
 TEST_F(IR_CoreBuiltinCallTest, Fail_NullType) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             Module mod;
             Builder b{mod};
@@ -66,7 +65,7 @@
 }
 
 TEST_F(IR_CoreBuiltinCallTest, Fail_NoneFunction) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             Module mod;
             Builder b{mod};
diff --git a/src/tint/lang/core/ir/core_unary_test.cc b/src/tint/lang/core/ir/core_unary_test.cc
index a984045..88de1c1 100644
--- a/src/tint/lang/core/ir/core_unary_test.cc
+++ b/src/tint/lang/core/ir/core_unary_test.cc
@@ -26,7 +26,6 @@
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include "gmock/gmock.h"
-#include "gtest/gtest-spi.h"
 #include "src/tint/lang/core/fluent_types.h"
 #include "src/tint/lang/core/ir/builder.h"
 #include "src/tint/lang/core/ir/instruction.h"
@@ -81,7 +80,7 @@
 }
 
 TEST_F(IR_UnaryTest, Fail_NullType) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             Module mod;
             Builder b{mod};
diff --git a/src/tint/lang/core/ir/discard_test.cc b/src/tint/lang/core/ir/discard_test.cc
index 098b99f..9c8efdb 100644
--- a/src/tint/lang/core/ir/discard_test.cc
+++ b/src/tint/lang/core/ir/discard_test.cc
@@ -25,7 +25,6 @@
 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-#include "gtest/gtest-spi.h"
 #include "src/tint/lang/core/ir/builder.h"
 #include "src/tint/lang/core/ir/instruction.h"
 #include "src/tint/lang/core/ir/ir_helper_test.h"
diff --git a/src/tint/lang/core/ir/function.cc b/src/tint/lang/core/ir/function.cc
index 1138fbf..f8a3e53 100644
--- a/src/tint/lang/core/ir/function.cc
+++ b/src/tint/lang/core/ir/function.cc
@@ -70,7 +70,7 @@
         param->SetFunction(nullptr);
     }
     params_ = std::move(params);
-    TINT_ASSERT_OR_RETURN(!params_.Any(IsNull));
+    TINT_ASSERT(!params_.Any(IsNull));
     for (auto* param : params_) {
         param->SetFunction(this);
     }
@@ -81,7 +81,7 @@
         param->SetFunction(nullptr);
     }
     params_ = params;
-    TINT_ASSERT_OR_RETURN(!params_.Any(IsNull));
+    TINT_ASSERT(!params_.Any(IsNull));
     for (auto* param : params_) {
         param->SetFunction(this);
     }
diff --git a/src/tint/lang/core/ir/function_param_test.cc b/src/tint/lang/core/ir/function_param_test.cc
index 375e8a8..49bc373 100644
--- a/src/tint/lang/core/ir/function_param_test.cc
+++ b/src/tint/lang/core/ir/function_param_test.cc
@@ -27,7 +27,6 @@
 
 #include <string>
 
-#include "gtest/gtest-spi.h"
 #include "src/tint/lang/core/ir/function_param.h"
 #include "src/tint/lang/core/ir/ir_helper_test.h"
 
@@ -38,7 +37,7 @@
 using IR_FunctionParamTest = IRTestHelper;
 
 TEST_F(IR_FunctionParamTest, Fail_NullType) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             Module mod;
             Builder b{mod};
@@ -48,7 +47,7 @@
 }
 
 TEST_F(IR_FunctionParamTest, Fail_SetDuplicateBuiltin) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             Module mod;
             Builder b{mod};
diff --git a/src/tint/lang/core/ir/function_test.cc b/src/tint/lang/core/ir/function_test.cc
index 65a61ba..19443f6 100644
--- a/src/tint/lang/core/ir/function_test.cc
+++ b/src/tint/lang/core/ir/function_test.cc
@@ -27,7 +27,6 @@
 
 #include <string>
 
-#include "gtest/gtest-spi.h"
 #include "src/tint/lang/core/ir/function.h"
 #include "src/tint/lang/core/ir/ir_helper_test.h"
 
@@ -38,7 +37,7 @@
 using IR_FunctionTest = IRTestHelper;
 
 TEST_F(IR_FunctionTest, Fail_NullReturnType) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             Module mod;
             Builder b{mod};
@@ -48,7 +47,7 @@
 }
 
 TEST_F(IR_FunctionTest, Fail_DoubleReturnBuiltin) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             Module mod;
             Builder b{mod};
@@ -60,7 +59,7 @@
 }
 
 TEST_F(IR_FunctionTest, Fail_NullParam) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             Module mod;
             Builder b{mod};
@@ -71,7 +70,7 @@
 }
 
 TEST_F(IR_FunctionTest, Fail_NullBlock) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             Module mod;
             Builder b{mod};
diff --git a/src/tint/lang/core/ir/if_test.cc b/src/tint/lang/core/ir/if_test.cc
index 6d609fd..cb02e52 100644
--- a/src/tint/lang/core/ir/if_test.cc
+++ b/src/tint/lang/core/ir/if_test.cc
@@ -27,7 +27,6 @@
 
 #include "src/tint/lang/core/ir/if.h"
 #include "gmock/gmock.h"
-#include "gtest/gtest-spi.h"
 #include "src/tint/lang/core/ir/ir_helper_test.h"
 
 namespace tint::core::ir {
@@ -56,7 +55,7 @@
 }
 
 TEST_F(IR_IfTest, Fail_NullTrueBlock) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             Module mod;
             Builder b{mod};
@@ -66,7 +65,7 @@
 }
 
 TEST_F(IR_IfTest, Fail_NullFalseBlock) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             Module mod;
             Builder b{mod};
diff --git a/src/tint/lang/core/ir/instruction.cc b/src/tint/lang/core/ir/instruction.cc
index 69d3f77..8d5218c 100644
--- a/src/tint/lang/core/ir/instruction.cc
+++ b/src/tint/lang/core/ir/instruction.cc
@@ -51,25 +51,25 @@
 }
 
 void Instruction::InsertBefore(Instruction* before) {
-    TINT_ASSERT_OR_RETURN(before);
-    TINT_ASSERT_OR_RETURN(before->Block() != nullptr);
+    TINT_ASSERT(before);
+    TINT_ASSERT(before->Block() != nullptr);
     before->Block()->InsertBefore(before, this);
 }
 
 void Instruction::InsertAfter(Instruction* after) {
-    TINT_ASSERT_OR_RETURN(after);
-    TINT_ASSERT_OR_RETURN(after->Block() != nullptr);
+    TINT_ASSERT(after);
+    TINT_ASSERT(after->Block() != nullptr);
     after->Block()->InsertAfter(after, this);
 }
 
 void Instruction::ReplaceWith(Instruction* replacement) {
-    TINT_ASSERT_OR_RETURN(replacement);
-    TINT_ASSERT_OR_RETURN(Block() != nullptr);
+    TINT_ASSERT(replacement);
+    TINT_ASSERT(Block() != nullptr);
     Block()->Replace(this, replacement);
 }
 
 void Instruction::Remove() {
-    TINT_ASSERT_OR_RETURN(Block() != nullptr);
+    TINT_ASSERT(Block() != nullptr);
     Block()->Remove(this);
 }
 
diff --git a/src/tint/lang/core/ir/instruction_result_test.cc b/src/tint/lang/core/ir/instruction_result_test.cc
index 534f347..665f17c 100644
--- a/src/tint/lang/core/ir/instruction_result_test.cc
+++ b/src/tint/lang/core/ir/instruction_result_test.cc
@@ -26,7 +26,6 @@
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include "gmock/gmock.h"
-#include "gtest/gtest-spi.h"
 #include "src/tint/lang/core/ir/ir_helper_test.h"
 
 using namespace tint::core::number_suffixes;  // NOLINT
@@ -38,7 +37,7 @@
 using IR_InstructionResultTest = IRTestHelper;
 
 TEST_F(IR_InstructionResultTest, Destroy_HasInstruction) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             Module mod;
             Builder b{mod};
diff --git a/src/tint/lang/core/ir/instruction_test.cc b/src/tint/lang/core/ir/instruction_test.cc
index 05e7b73..fa95ba5 100644
--- a/src/tint/lang/core/ir/instruction_test.cc
+++ b/src/tint/lang/core/ir/instruction_test.cc
@@ -25,7 +25,6 @@
 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-#include "gtest/gtest-spi.h"
 #include "src/tint/lang/core/ir/block.h"
 #include "src/tint/lang/core/ir/builder.h"
 #include "src/tint/lang/core/ir/ir_helper_test.h"
@@ -47,7 +46,7 @@
 }
 
 TEST_F(IR_InstructionTest, Fail_InsertBeforeNullptr) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             Module mod;
             Builder b{mod};
@@ -59,7 +58,7 @@
 }
 
 TEST_F(IR_InstructionTest, Fail_InsertBeforeNotInserted) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             Module mod;
             Builder b{mod};
@@ -82,7 +81,7 @@
 }
 
 TEST_F(IR_InstructionTest, Fail_InsertAfterNullptr) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             Module mod;
             Builder b{mod};
@@ -94,7 +93,7 @@
 }
 
 TEST_F(IR_InstructionTest, Fail_InsertAfterNotInserted) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             Module mod;
             Builder b{mod};
@@ -118,7 +117,7 @@
 }
 
 TEST_F(IR_InstructionTest, Fail_ReplaceWithNullptr) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             Module mod;
             Builder b{mod};
@@ -132,7 +131,7 @@
 }
 
 TEST_F(IR_InstructionTest, Fail_ReplaceWithNotInserted) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             Module mod;
             Builder b{mod};
@@ -156,7 +155,7 @@
 }
 
 TEST_F(IR_InstructionTest, Fail_RemoveNotInserted) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             Module mod;
             Builder b{mod};
diff --git a/src/tint/lang/core/ir/let_test.cc b/src/tint/lang/core/ir/let_test.cc
index 78b9d5e..218bd1e 100644
--- a/src/tint/lang/core/ir/let_test.cc
+++ b/src/tint/lang/core/ir/let_test.cc
@@ -28,7 +28,6 @@
 #include "src/tint/lang/core/ir/let.h"
 
 #include "gmock/gmock.h"
-#include "gtest/gtest-spi.h"
 #include "src/tint/lang/core/ir/builder.h"
 #include "src/tint/lang/core/ir/instruction.h"
 #include "src/tint/lang/core/ir/ir_helper_test.h"
@@ -42,7 +41,7 @@
 using IR_LetTest = IRTestHelper;
 
 TEST_F(IR_LetTest, Fail_NullValue) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             Module mod;
             Builder b{mod};
diff --git a/src/tint/lang/core/ir/load_test.cc b/src/tint/lang/core/ir/load_test.cc
index bccaa13..62977b3 100644
--- a/src/tint/lang/core/ir/load_test.cc
+++ b/src/tint/lang/core/ir/load_test.cc
@@ -26,7 +26,6 @@
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include "gmock/gmock.h"
-#include "gtest/gtest-spi.h"
 #include "src/tint/lang/core/ir/builder.h"
 #include "src/tint/lang/core/ir/instruction.h"
 #include "src/tint/lang/core/ir/ir_helper_test.h"
diff --git a/src/tint/lang/core/ir/load_vector_element_test.cc b/src/tint/lang/core/ir/load_vector_element_test.cc
index 0f69ec1..bcfe77f 100644
--- a/src/tint/lang/core/ir/load_vector_element_test.cc
+++ b/src/tint/lang/core/ir/load_vector_element_test.cc
@@ -26,7 +26,6 @@
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include "gmock/gmock.h"
-#include "gtest/gtest-spi.h"
 #include "src/tint/lang/core/ir/builder.h"
 #include "src/tint/lang/core/ir/instruction.h"
 #include "src/tint/lang/core/ir/ir_helper_test.h"
diff --git a/src/tint/lang/core/ir/loop_test.cc b/src/tint/lang/core/ir/loop_test.cc
index b8721e2..0f522a0 100644
--- a/src/tint/lang/core/ir/loop_test.cc
+++ b/src/tint/lang/core/ir/loop_test.cc
@@ -26,7 +26,6 @@
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include "src/tint/lang/core/ir/loop.h"
-#include "gtest/gtest-spi.h"
 #include "src/tint/lang/core/ir/ir_helper_test.h"
 
 namespace tint::core::ir {
@@ -48,7 +47,7 @@
 }
 
 TEST_F(IR_LoopTest, Fail_NullInitializerBlock) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             Module mod;
             Builder b{mod};
@@ -58,7 +57,7 @@
 }
 
 TEST_F(IR_LoopTest, Fail_NullBodyBlock) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             Module mod;
             Builder b{mod};
@@ -68,7 +67,7 @@
 }
 
 TEST_F(IR_LoopTest, Fail_NullContinuingBlock) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             Module mod;
             Builder b{mod};
diff --git a/src/tint/lang/core/ir/multi_in_block.cc b/src/tint/lang/core/ir/multi_in_block.cc
index 411d06c..a26ea2d 100644
--- a/src/tint/lang/core/ir/multi_in_block.cc
+++ b/src/tint/lang/core/ir/multi_in_block.cc
@@ -43,7 +43,6 @@
 
 MultiInBlock* MultiInBlock::Clone(CloneContext&) {
     TINT_UNREACHABLE() << "blocks must be cloned with CloneInto";
-    return nullptr;
 }
 
 void MultiInBlock::CloneInto(CloneContext& ctx, Block* out) {
@@ -59,7 +58,7 @@
         param->SetBlock(nullptr);
     }
     params_ = std::move(params);
-    TINT_ASSERT_OR_RETURN(!params_.Any(IsNull));
+    TINT_ASSERT(!params_.Any(IsNull));
     for (auto* param : params_) {
         param->SetBlock(this);
     }
@@ -70,19 +69,19 @@
         param->SetBlock(nullptr);
     }
     params_ = std::move(params);
-    TINT_ASSERT_OR_RETURN(!params_.Any(IsNull));
+    TINT_ASSERT(!params_.Any(IsNull));
     for (auto* param : params_) {
         param->SetBlock(this);
     }
 }
 
 void MultiInBlock::AddInboundSiblingBranch(ir::Terminator* node) {
-    TINT_ASSERT_OR_RETURN(node != nullptr);
+    TINT_ASSERT(node != nullptr);
     inbound_sibling_branches_.Push(node);
 }
 
 void MultiInBlock::RemoveInboundSiblingBranch(ir::Terminator* node) {
-    TINT_ASSERT_OR_RETURN(node != nullptr);
+    TINT_ASSERT(node != nullptr);
     inbound_sibling_branches_.EraseIf([node](ir::Terminator* i) { return i == node; });
 }
 
diff --git a/src/tint/lang/core/ir/multi_in_block_test.cc b/src/tint/lang/core/ir/multi_in_block_test.cc
index a377c44..5d4d459 100644
--- a/src/tint/lang/core/ir/multi_in_block_test.cc
+++ b/src/tint/lang/core/ir/multi_in_block_test.cc
@@ -26,7 +26,6 @@
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include "src/tint/lang/core/ir/multi_in_block.h"
-#include "gtest/gtest-spi.h"
 #include "src/tint/lang/core/ir/block_param.h"
 #include "src/tint/lang/core/ir/ir_helper_test.h"
 
@@ -37,7 +36,7 @@
 using IR_MultiInBlockTest = IRTestHelper;
 
 TEST_F(IR_MultiInBlockTest, Fail_NullInboundBranch) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             Module mod;
             Builder b{mod};
diff --git a/src/tint/lang/core/ir/next_iteration_test.cc b/src/tint/lang/core/ir/next_iteration_test.cc
index 249bd63..e1554cb 100644
--- a/src/tint/lang/core/ir/next_iteration_test.cc
+++ b/src/tint/lang/core/ir/next_iteration_test.cc
@@ -26,7 +26,6 @@
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include "src/tint/lang/core/ir/next_iteration.h"
-#include "gtest/gtest-spi.h"
 #include "src/tint/lang/core/ir/ir_helper_test.h"
 
 namespace tint::core::ir {
@@ -36,7 +35,7 @@
 using IR_NextIterationTest = IRTestHelper;
 
 TEST_F(IR_NextIterationTest, Fail_NullLoop) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             Module mod;
             Builder b{mod};
diff --git a/src/tint/lang/core/ir/return_test.cc b/src/tint/lang/core/ir/return_test.cc
index dfd088b..61a968d 100644
--- a/src/tint/lang/core/ir/return_test.cc
+++ b/src/tint/lang/core/ir/return_test.cc
@@ -28,7 +28,6 @@
 #include "src/tint/lang/core/ir/return.h"
 
 #include "gmock/gmock.h"
-#include "gtest/gtest-spi.h"
 #include "src/tint/lang/core/ir/ir_helper_test.h"
 
 namespace tint::core::ir {
diff --git a/src/tint/lang/core/ir/store_test.cc b/src/tint/lang/core/ir/store_test.cc
index 28e4d85..d3fbf9d 100644
--- a/src/tint/lang/core/ir/store_test.cc
+++ b/src/tint/lang/core/ir/store_test.cc
@@ -26,7 +26,6 @@
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include "gmock/gmock.h"
-#include "gtest/gtest-spi.h"
 #include "src/tint/lang/core/ir/builder.h"
 #include "src/tint/lang/core/ir/instruction.h"
 #include "src/tint/lang/core/ir/ir_helper_test.h"
diff --git a/src/tint/lang/core/ir/store_vector_element_test.cc b/src/tint/lang/core/ir/store_vector_element_test.cc
index 971b12b..788e3d7 100644
--- a/src/tint/lang/core/ir/store_vector_element_test.cc
+++ b/src/tint/lang/core/ir/store_vector_element_test.cc
@@ -26,7 +26,6 @@
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include "gmock/gmock.h"
-#include "gtest/gtest-spi.h"
 #include "src/tint/lang/core/ir/builder.h"
 #include "src/tint/lang/core/ir/instruction.h"
 #include "src/tint/lang/core/ir/ir_helper_test.h"
diff --git a/src/tint/lang/core/ir/switch_test.cc b/src/tint/lang/core/ir/switch_test.cc
index 7391458..1af4ae8 100644
--- a/src/tint/lang/core/ir/switch_test.cc
+++ b/src/tint/lang/core/ir/switch_test.cc
@@ -28,7 +28,6 @@
 #include "src/tint/lang/core/ir/switch.h"
 
 #include "gmock/gmock.h"
-#include "gtest/gtest-spi.h"
 #include "src/tint/lang/core/ir/ir_helper_test.h"
 
 namespace tint::core::ir {
diff --git a/src/tint/lang/core/ir/swizzle_test.cc b/src/tint/lang/core/ir/swizzle_test.cc
index e66a578..ba911f7 100644
--- a/src/tint/lang/core/ir/swizzle_test.cc
+++ b/src/tint/lang/core/ir/swizzle_test.cc
@@ -28,7 +28,6 @@
 #include "src/tint/lang/core/ir/swizzle.h"
 
 #include "gmock/gmock.h"
-#include "gtest/gtest-spi.h"
 #include "src/tint/lang/core/ir/ir_helper_test.h"
 
 using namespace tint::core::fluent_types;  // NOLINT
@@ -55,7 +54,7 @@
 }
 
 TEST_F(IR_SwizzleTest, Fail_NullType) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             Module mod;
             Builder b{mod};
@@ -66,7 +65,7 @@
 }
 
 TEST_F(IR_SwizzleTest, Fail_EmptyIndices) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             Module mod;
             Builder b{mod};
@@ -77,7 +76,7 @@
 }
 
 TEST_F(IR_SwizzleTest, Fail_TooManyIndices) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             Module mod;
             Builder b{mod};
@@ -88,7 +87,7 @@
 }
 
 TEST_F(IR_SwizzleTest, Fail_IndexOutOfRange) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             Module mod;
             Builder b{mod};
diff --git a/src/tint/lang/core/ir/transform/binary_polyfill.cc b/src/tint/lang/core/ir/transform/binary_polyfill.cc
index 47c6861..7d4a962 100644
--- a/src/tint/lang/core/ir/transform/binary_polyfill.cc
+++ b/src/tint/lang/core/ir/transform/binary_polyfill.cc
@@ -104,7 +104,7 @@
                 default:
                     break;
             }
-            TINT_ASSERT_OR_RETURN(replacement);
+            TINT_ASSERT(replacement);
 
             if (replacement != binary->Result(0)) {
                 // Replace the old binary instruction result with the new value.
diff --git a/src/tint/lang/core/ir/transform/builtin_polyfill.cc b/src/tint/lang/core/ir/transform/builtin_polyfill.cc
index 2e91f34..0eb45f8 100644
--- a/src/tint/lang/core/ir/transform/builtin_polyfill.cc
+++ b/src/tint/lang/core/ir/transform/builtin_polyfill.cc
@@ -203,7 +203,7 @@
                 default:
                     break;
             }
-            TINT_ASSERT_OR_RETURN(replacement);
+            TINT_ASSERT(replacement);
 
             if (replacement != builtin->Result(0)) {
                 // Replace the old builtin call result with the new value.
@@ -411,7 +411,6 @@
             default:
                 TINT_UNIMPLEMENTED() << "extractBits polyfill level";
         }
-        return nullptr;
     }
 
     /// Polyfill a `firstLeadingBit()` builtin call.
@@ -565,7 +564,6 @@
             default:
                 TINT_UNIMPLEMENTED() << "insertBits polyfill level";
         }
-        return nullptr;
     }
 
     /// Polyfill a `saturate()` builtin call.
diff --git a/src/tint/lang/core/ir/transform/robustness.cc b/src/tint/lang/core/ir/transform/robustness.cc
index 228b822..9284b9a 100644
--- a/src/tint/lang/core/ir/transform/robustness.cc
+++ b/src/tint/lang/core/ir/transform/robustness.cc
@@ -234,8 +234,7 @@
                     if (arr->ConstantCount()) {
                         return b.Constant(u32(arr->ConstantCount().value() - 1u));
                     }
-                    TINT_ASSERT_OR_RETURN_VALUE(arr->Count()->Is<type::RuntimeArrayCount>(),
-                                                nullptr);
+                    TINT_ASSERT(arr->Count()->Is<type::RuntimeArrayCount>());
 
                     // Skip clamping runtime-sized array indices if requested.
                     if (config.disable_runtime_sized_array_index_clamping) {
@@ -247,8 +246,8 @@
                         // Generate a pointer to the runtime-sized array if it isn't the base of
                         // this access instruction.
                         auto* base_ptr = object->Type()->As<type::Pointer>();
-                        TINT_ASSERT_OR_RETURN_VALUE(base_ptr != nullptr, nullptr);
-                        TINT_ASSERT_OR_RETURN_VALUE(i == 1, nullptr);
+                        TINT_ASSERT(base_ptr != nullptr);
+                        TINT_ASSERT(i == 1);
                         auto* arr_ptr = ty.ptr(base_ptr->AddressSpace(), arr, base_ptr->Access());
                         object = b.Access(arr_ptr, object, indices[0])->Result(0);
                     }
diff --git a/src/tint/lang/core/ir/transform/zero_init_workgroup_memory.cc b/src/tint/lang/core/ir/transform/zero_init_workgroup_memory.cc
index 8390ff6..26cbf76 100644
--- a/src/tint/lang/core/ir/transform/zero_init_workgroup_memory.cc
+++ b/src/tint/lang/core/ir/transform/zero_init_workgroup_memory.cc
@@ -35,6 +35,14 @@
 #include "src/tint/lang/core/ir/validator.h"
 #include "src/tint/utils/containers/reverse.h"
 
+#if TINT_BUILD_IS_MSVC
+#if _MSC_VER > 1930 && _MSC_VER < 1939
+// MSVC raises an internal compiler error in Vector::Sort(), when optimizations are enabled.
+// Later versions are fixed.
+TINT_BEGIN_DISABLE_OPTIMIZATIONS();
+#endif
+#endif
+
 using namespace tint::core::fluent_types;     // NOLINT
 using namespace tint::core::number_suffixes;  // NOLINT
 
diff --git a/src/tint/lang/core/ir/unreachable_test.cc b/src/tint/lang/core/ir/unreachable_test.cc
index 97a56dd..9c2302f 100644
--- a/src/tint/lang/core/ir/unreachable_test.cc
+++ b/src/tint/lang/core/ir/unreachable_test.cc
@@ -25,7 +25,6 @@
 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-#include "gtest/gtest-spi.h"
 #include "src/tint/lang/core/ir/builder.h"
 #include "src/tint/lang/core/ir/instruction.h"
 #include "src/tint/lang/core/ir/ir_helper_test.h"
diff --git a/src/tint/lang/core/ir/user_call_test.cc b/src/tint/lang/core/ir/user_call_test.cc
index a0d65ee..768fea3 100644
--- a/src/tint/lang/core/ir/user_call_test.cc
+++ b/src/tint/lang/core/ir/user_call_test.cc
@@ -28,7 +28,6 @@
 #include "src/tint/lang/core/ir/user_call.h"
 
 #include "gmock/gmock.h"
-#include "gtest/gtest-spi.h"
 #include "src/tint/lang/core/ir/ir_helper_test.h"
 
 namespace tint::core::ir {
@@ -59,7 +58,7 @@
 }
 
 TEST_F(IR_UserCallTest, Fail_NullType) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             Module mod;
             Builder b{mod};
diff --git a/src/tint/lang/core/ir/value_test.cc b/src/tint/lang/core/ir/value_test.cc
index a1adee2..43fd900 100644
--- a/src/tint/lang/core/ir/value_test.cc
+++ b/src/tint/lang/core/ir/value_test.cc
@@ -26,7 +26,6 @@
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include "gmock/gmock.h"
-#include "gtest/gtest-spi.h"
 #include "src/tint/lang/core/ir/ir_helper_test.h"
 
 using namespace tint::core::number_suffixes;  // NOLINT
@@ -67,7 +66,7 @@
 }
 
 TEST_F(IR_ValueTest, Destroy_HasSource) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             Module mod;
             Builder b{mod};
diff --git a/src/tint/lang/core/ir/var_test.cc b/src/tint/lang/core/ir/var_test.cc
index 5e41f29..e1759d9 100644
--- a/src/tint/lang/core/ir/var_test.cc
+++ b/src/tint/lang/core/ir/var_test.cc
@@ -28,7 +28,6 @@
 #include "src/tint/lang/core/ir/var.h"
 
 #include "gmock/gmock.h"
-#include "gtest/gtest-spi.h"
 #include "src/tint/lang/core/ir/builder.h"
 #include "src/tint/lang/core/ir/instruction.h"
 #include "src/tint/lang/core/ir/ir_helper_test.h"
@@ -42,7 +41,7 @@
 using IR_VarTest = IRTestHelper;
 
 TEST_F(IR_VarTest, Fail_NullType) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             Module mod;
             Builder b{mod};
diff --git a/src/tint/lang/core/number.cc b/src/tint/lang/core/number.cc
index 5768c25..e54098a 100644
--- a/src/tint/lang/core/number.cc
+++ b/src/tint/lang/core/number.cc
@@ -342,7 +342,6 @@
 
     // Neither zero, subnormal f16 or normal f16, shall never hit.
     TINT_UNREACHABLE();
-    return kF16Nan;
 }
 
 // static
diff --git a/src/tint/lang/core/type/manager.cc b/src/tint/lang/core/type/manager.cc
index bb39ed1..2b54e8d 100644
--- a/src/tint/lang/core/type/manager.cc
+++ b/src/tint/lang/core/type/manager.cc
@@ -213,7 +213,6 @@
 core::type::Struct* Manager::Struct(Symbol name, VectorRef<const StructMember*> members) {
     if (auto* existing = Find<type::Struct>(name); TINT_UNLIKELY(existing)) {
         TINT_ICE() << "attempting to construct two structs named " << name.NameView();
-        return existing;
     }
 
     uint32_t max_align = 0u;
@@ -228,7 +227,6 @@
 core::type::Struct* Manager::Struct(Symbol name, VectorRef<StructMemberDesc> md) {
     if (auto* existing = Find<type::Struct>(name); TINT_UNLIKELY(existing)) {
         TINT_ICE() << "attempting to construct two structs named " << name.NameView();
-        return existing;
     }
 
     tint::Vector<const StructMember*, 4> members;
diff --git a/src/tint/lang/glsl/validate/validate.cc b/src/tint/lang/glsl/validate/validate.cc
index bbeee23..eacb251 100644
--- a/src/tint/lang/glsl/validate/validate.cc
+++ b/src/tint/lang/glsl/validate/validate.cc
@@ -48,7 +48,9 @@
             return EShLangCompute;
         default:
             TINT_UNREACHABLE();
-            return EShLangVertex;
+            // MSVC considered the inlined call:
+            // `lang = PipelineStageToEshLanguage()` as potentially uninitialized
+            TINT_MSVC_ONLY(return EShLangCompute;)
     }
 }
 
diff --git a/src/tint/lang/glsl/writer/ast_printer/ast_printer.cc b/src/tint/lang/glsl/writer/ast_printer/ast_printer.cc
index 92b6cad..f03e863 100644
--- a/src/tint/lang/glsl/writer/ast_printer/ast_printer.cc
+++ b/src/tint/lang/glsl/writer/ast_printer/ast_printer.cc
@@ -612,7 +612,6 @@
         out << " | ";
     } else {
         TINT_ICE() << "unexpected binary op: " << expr->op;
-        return;
     }
 
     // Cast RHS to uint scalar or vector type.
@@ -738,7 +737,6 @@
         case core::BinaryOp::kLogicalOr: {
             // These are both handled above.
             TINT_UNREACHABLE();
-            return;
         }
         case core::BinaryOp::kEqual:
             out << "==";
@@ -1349,7 +1347,6 @@
     auto* texture = arg(Usage::kTexture);
     if (TINT_UNLIKELY(!texture)) {
         TINT_ICE() << "missing texture argument";
-        return;
     }
 
     auto* texture_type = TypeOf(texture)->UnwrapRef()->As<core::type::Texture>();
@@ -1522,7 +1519,6 @@
             break;
         default:
             TINT_ICE() << "Unhandled texture builtin '" << std::string(builtin->str()) << "'";
-            return;
     }
 
     if (builtin->Signature().IndexOf(core::ParameterUsage::kOffset) >= 0) {
@@ -1536,7 +1532,6 @@
     auto* param_coords = arg(Usage::kCoords);
     if (TINT_UNLIKELY(!param_coords)) {
         TINT_ICE() << "missing coords argument";
-        return;
     }
 
     if (auto* array_index = arg(Usage::kArrayIndex)) {
@@ -1628,7 +1623,6 @@
         TINT_ICE() << "WGSL return width (" << wgsl_ret_width
                    << ") is wider than GLSL return width (" << glsl_ret_width << ") for "
                    << builtin->Fn();
-        return;
     }
 }
 
@@ -1915,7 +1909,6 @@
                     return;
                 default: {
                     TINT_ICE() << "unhandled address space " << sem->AddressSpace();
-                    break;
                 }
             }
         },
@@ -1937,7 +1930,6 @@
     auto* str = type->As<core::type::Struct>();
     if (TINT_UNLIKELY(!str)) {
         TINT_ICE() << "storage variable must be of struct type";
-        return;
     }
     auto bp = *sem->As<sem::GlobalVariable>()->Attributes().binding_point;
     {
@@ -1956,7 +1948,6 @@
     auto* str = type->As<core::type::Struct>();
     if (TINT_UNLIKELY(!str)) {
         TINT_ICE() << "storage variable must be of struct type";
-        return;
     }
     auto bp = *sem->As<sem::GlobalVariable>()->Attributes().binding_point;
     Line() << "layout(binding = " << bp.binding << ", std430) buffer "
@@ -1982,7 +1973,6 @@
         switch (storage->texel_format()) {
             case core::TexelFormat::kBgra8Unorm:
                 TINT_ICE() << "bgra8unorm should have been polyfilled to rgba8unorm";
-                break;
             case core::TexelFormat::kR32Uint:
                 out << "r32ui";
                 break;
@@ -2036,7 +2026,6 @@
                 break;
             case core::TexelFormat::kUndefined:
                 TINT_ICE() << "invalid texel format";
-                return;
         }
         out << ") ";
     }
@@ -2732,7 +2721,6 @@
     } else if (auto* tex = type->As<core::type::Texture>()) {
         if (TINT_UNLIKELY(tex->Is<core::type::ExternalTexture>())) {
             TINT_ICE() << "Multiplanar external texture transform was not run.";
-            return;
         }
 
         auto* storage = tex->As<core::type::StorageTexture>();
@@ -2770,7 +2758,6 @@
                 } break;
                 default:
                     TINT_UNREACHABLE() << "unexpected storage texture access " << storage->access();
-                    return;
             }
         }
         auto* subtype = sampled   ? sampled->type()
@@ -2784,7 +2771,6 @@
             out << "u";
         } else {
             TINT_ICE() << "Unsupported texture type";
-            return;
         }
 
         out << (storage ? "image" : "sampler");
@@ -2810,7 +2796,6 @@
                 break;
             default:
                 TINT_UNREACHABLE() << "unexpected TextureDimension " << tex->dim();
-                return;
         }
         if (tex->Is<core::type::DepthTexture>()) {
             out << "Shadow";
diff --git a/src/tint/lang/glsl/writer/ast_raise/texture_builtins_from_uniform.cc b/src/tint/lang/glsl/writer/ast_raise/texture_builtins_from_uniform.cc
index d0e8c71..450499a 100644
--- a/src/tint/lang/glsl/writer/ast_raise/texture_builtins_from_uniform.cc
+++ b/src/tint/lang/glsl/writer/ast_raise/texture_builtins_from_uniform.cc
@@ -334,7 +334,6 @@
                     if (TINT_UNLIKELY(!str)) {
                         TINT_ICE()
                             << "existing ubo binding " << cfg->ubo_binding << " is not a struct.";
-                        return ctx.Clone(ubo->name->symbol);
                     }
 
                     for (auto new_member : new_members) {
diff --git a/src/tint/lang/hlsl/writer/ast_printer/ast_printer.cc b/src/tint/lang/hlsl/writer/ast_printer/ast_printer.cc
index 35a7140..28a5f6f 100644
--- a/src/tint/lang/hlsl/writer/ast_printer/ast_printer.cc
+++ b/src/tint/lang/hlsl/writer/ast_printer/ast_printer.cc
@@ -302,7 +302,6 @@
                     break;
                 default:
                     TINT_ICE() << "missing texel format for pixel local storage attachment";
-                    return SanitizedResult();
             }
             cfg.pls_member_to_rov_format.Add(it.first, format);
         }
@@ -501,7 +500,6 @@
                     break;
                 default:
                     TINT_UNREACHABLE() << "invalid vector size " << vec->Width();
-                    break;
             }
         }
         Line(&helpers_) << "}";
@@ -645,7 +643,6 @@
                                                     ->UnwrapPtrOrRef()
                                                     ->As<core::type::Vector>();
                                     TINT_UNREACHABLE() << "invalid vector size " << vec->Width();
-                                    break;
                                 }
                             }
                         }
@@ -904,7 +901,6 @@
                 TINT_ICE() << "lhs of index accessor should not be a pointer. These should have "
                               "been removed by transforms such as SimplifyPointers, "
                               "DecomposeMemoryAccess, and DirectVariableAccess";
-                return false;
             }
             return true;
         };
@@ -1036,7 +1032,6 @@
         case core::BinaryOp::kLogicalOr: {
             // These are both handled above.
             TINT_UNREACHABLE();
-            return false;
         }
         case core::BinaryOp::kEqual:
             out << "==";
@@ -1175,7 +1170,6 @@
             default:
                 TINT_UNREACHABLE() << "unsupported DecomposeMemoryAccess::Intrinsic address space:"
                                    << intrinsic->address_space;
-                return false;
         }
     }
 
@@ -1342,7 +1336,6 @@
         if (!ctor->Parameters()[0]->Type()->UnwrapRef()->is_float_matrix()) {
             TINT_UNREACHABLE()
                 << "found a single-parameter matrix initializer that is not identity initializer";
-            return false;
         }
     }
 
@@ -1663,14 +1656,12 @@
             }
             TINT_UNREACHABLE() << "unsupported DecomposeMemoryAccess::Intrinsic::DataType: "
                                << static_cast<int>(intrinsic->type);
-            return false;
         }
         default:
             break;
     }
     TINT_UNREACHABLE() << "unsupported DecomposeMemoryAccess::Intrinsic::Op: "
                        << static_cast<int>(intrinsic->op);
-    return false;
 }
 
 bool ASTPrinter::EmitStorageBufferAccess(StringStream& out,
@@ -1748,7 +1739,6 @@
             }
             TINT_UNREACHABLE() << "unsupported DecomposeMemoryAccess::Intrinsic::DataType: "
                                << static_cast<int>(intrinsic->type);
-            return false;
         }
 
         case Op::kStore: {
@@ -1819,7 +1809,6 @@
             }
             TINT_UNREACHABLE() << "unsupported DecomposeMemoryAccess::Intrinsic::DataType: "
                                << static_cast<int>(intrinsic->type);
-            return false;
         }
         default:
             // Break out to error case below
@@ -1829,7 +1818,6 @@
 
     TINT_UNREACHABLE() << "unsupported DecomposeMemoryAccess::Intrinsic::Op: "
                        << static_cast<int>(intrinsic->op);
-    return false;
 }
 
 bool ASTPrinter::EmitStorageAtomicIntrinsic(const ast::Function* func,
@@ -2035,7 +2023,6 @@
 
     TINT_UNREACHABLE() << "unsupported atomic DecomposeMemoryAccess::Intrinsic::Op: "
                        << static_cast<int>(intrinsic->op);
-    return false;
 }
 
 bool ASTPrinter::EmitWorkgroupAtomicCall(StringStream& out,
@@ -2233,7 +2220,6 @@
     }
 
     TINT_UNREACHABLE() << "unsupported atomic builtin: " << builtin->Fn();
-    return false;
 }
 
 bool ASTPrinter::EmitSelectCall(StringStream& out, const ast::CallExpression* expr) {
@@ -2458,7 +2444,6 @@
                 }
                 default:
                     TINT_ICE() << " unhandled data packing builtin";
-                    return false;
             }
 
             return true;
@@ -2524,7 +2509,6 @@
                     break;
                 default:
                     TINT_ICE() << "unhandled data packing builtin";
-                    return false;
             }
 
             return true;
@@ -2581,7 +2565,6 @@
         case wgsl::BuiltinFn::kPack4XU8Clamp:
         default:
             TINT_UNIMPLEMENTED() << builtin->Fn();
-            return false;
     }
 
     return CallBuiltinHelper(out, expr, builtin,
@@ -2598,7 +2581,6 @@
                                          break;
                                      default:
                                          TINT_ICE() << "Internal error: unhandled DP4a builtin";
-                                         return false;
                                  }
                                  Line(b) << "return " << functionName << "(" << params[0] << ", "
                                          << params[1] << ", accumulator);";
@@ -2618,7 +2600,6 @@
         out << "DeviceMemoryBarrierWithGroupSync()";
     } else {
         TINT_UNREACHABLE() << "unexpected barrier builtin type " << builtin->Fn();
-        return false;
     }
     return true;
 }
@@ -2631,7 +2612,6 @@
     } else {
         // subgroupBroadcast is already handled in the regular builtin flow.
         TINT_UNREACHABLE() << "unexpected subgroup builtin type " << builtin->Fn();
-        return false;
     }
     return true;
 }
@@ -2685,7 +2665,6 @@
     auto* texture = arg(Usage::kTexture);
     if (TINT_UNLIKELY(!texture)) {
         TINT_ICE() << "missing texture argument";
-        return false;
     }
 
     auto* texture_type = TypeOf(texture)->UnwrapRef()->As<core::type::Texture>();
@@ -2706,7 +2685,6 @@
                     switch (texture_type->dim()) {
                         case core::type::TextureDimension::kNone:
                             TINT_ICE() << "texture dimension is kNone";
-                            return false;
                         case core::type::TextureDimension::k1d:
                             num_dimensions = 1;
                             break;
@@ -2734,7 +2712,6 @@
                     switch (texture_type->dim()) {
                         default:
                             TINT_ICE() << "texture dimension is not arrayed";
-                            return false;
                         case core::type::TextureDimension::k2dArray:
                             num_dimensions = is_ms ? 4 : 3;
                             swizzle = ".z";
@@ -2749,7 +2726,6 @@
                     switch (texture_type->dim()) {
                         default:
                             TINT_ICE() << "texture dimension does not support mips";
-                            return false;
                         case core::type::TextureDimension::k1d:
                             num_dimensions = 2;
                             swizzle = ".y";
@@ -2771,7 +2747,6 @@
                     switch (texture_type->dim()) {
                         default:
                             TINT_ICE() << "texture dimension does not support multisampling";
-                            return false;
                         case core::type::TextureDimension::k2d:
                             num_dimensions = 3;
                             swizzle = ".z";
@@ -2784,7 +2759,6 @@
                     break;
                 default:
                     TINT_ICE() << "unexpected builtin";
-                    return false;
             }
 
             auto* level_arg = arg(Usage::kLevel);
@@ -2807,7 +2781,6 @@
             if (TINT_UNLIKELY(num_dimensions > 4)) {
                 TINT_ICE() << "Texture query builtin temporary vector has " << num_dimensions
                            << " dimensions";
-                return false;
             }
 
             // Declare a variable to hold the queried texture info
@@ -2840,7 +2813,6 @@
                     static constexpr char xyzw[] = {'x', 'y', 'z', 'w'};
                     if (TINT_UNLIKELY(num_dimensions < 0 || num_dimensions > 4)) {
                         TINT_ICE() << "vector dimensions are " << num_dimensions;
-                        return false;
                     }
                     for (int i = 0; i < num_dimensions; i++) {
                         if (i > 0) {
@@ -2937,7 +2909,6 @@
             break;
         default:
             TINT_ICE() << "Unhandled texture builtin '" << builtin << "'";
-            return false;
     }
 
     if (auto* sampler = arg(Usage::kSampler)) {
@@ -2950,7 +2921,6 @@
     auto* param_coords = arg(Usage::kCoords);
     if (TINT_UNLIKELY(!param_coords)) {
         TINT_ICE() << "missing coords argument";
-        return false;
     }
 
     auto emit_vector_appended_with_i32_zero = [&](const ast::Expression* vector) {
@@ -3038,7 +3008,6 @@
             TINT_ICE() << "WGSL return width (" << wgsl_ret_width
                        << ") is wider than HLSL return width (" << hlsl_ret_width << ") for "
                        << builtin->Fn();
-            return false;
         }
     }
 
@@ -3398,7 +3367,6 @@
                     return false;
                 default: {
                     TINT_ICE() << "unhandled address space " << sem->AddressSpace();
-                    return false;
                 }
             }
         },
@@ -3462,14 +3430,12 @@
         auto* storage = type->As<core::type::StorageTexture>();
         if (!storage) {
             TINT_ICE() << "Rasterizer Ordered View type isn't storage texture";
-            return false;
         }
         out << "RasterizerOrderedTexture2D";
         auto* component = ImageFormatToRWtextureType(storage->texel_format());
         if (TINT_UNLIKELY(!component)) {
             TINT_ICE() << "Unsupported StorageTexture TexelFormat: "
                        << static_cast<int>(storage->texel_format());
-            return false;
         }
         out << "<" << component << "> " << name;
     } else if (!EmitTypeAndName(out, type, sem->AddressSpace(), sem->Access(), name)) {
@@ -4341,7 +4307,6 @@
                     TINT_ICE()
                         << "runtime arrays may only exist in storage buffers, which should have "
                            "been transformed into a ByteAddressBuffer";
-                    return false;
                 }
                 const auto count = arr->ConstantCount();
                 if (!count) {
@@ -4405,10 +4370,9 @@
             out << mat->columns() << "x" << mat->rows();
             return true;
         },
-        [&](const core::type::Pointer*) {
-            TINT_ICE() << "Attempting to emit pointer type. These should have "
-                          "been removed with the SimplifyPointers transform";
-            return false;
+        [&](const core::type::Pointer*) -> bool {
+            TINT_ICE() << "Attempting to emit pointer type. These should have been removed with "
+                          "the SimplifyPointers transform";
         },
         [&](const core::type::Sampler* sampler) {
             out << "Sampler";
@@ -4425,7 +4389,6 @@
         [&](const core::type::Texture* tex) {
             if (TINT_UNLIKELY(tex->Is<core::type::ExternalTexture>())) {
                 TINT_ICE() << "Multiplanar external texture transform was not run.";
-                return false;
             }
 
             auto* storage = tex->As<core::type::StorageTexture>();
@@ -4459,7 +4422,6 @@
                     break;
                 default:
                     TINT_UNREACHABLE() << "unexpected TextureDimension " << tex->dim();
-                    return false;
             }
 
             if (storage) {
@@ -4467,7 +4429,6 @@
                 if (TINT_UNLIKELY(!component)) {
                     TINT_ICE() << "Unsupported StorageTexture TexelFormat: "
                                << static_cast<int>(storage->texel_format());
-                    return false;
                 }
                 out << "<" << component << ">";
             } else if (depth_ms) {
@@ -4483,7 +4444,6 @@
                     out << "uint4";
                 } else {
                     TINT_ICE() << "Unsupported multisampled texture type";
-                    return false;
                 }
                 out << ">";
             }
diff --git a/src/tint/lang/hlsl/writer/ast_raise/calculate_array_length.cc b/src/tint/lang/hlsl/writer/ast_raise/calculate_array_length.cc
index 25a23ea..f3763a8 100644
--- a/src/tint/lang/hlsl/writer/ast_raise/calculate_array_length.cc
+++ b/src/tint/lang/hlsl/writer/ast_raise/calculate_array_length.cc
@@ -176,13 +176,11 @@
                     if (TINT_UNLIKELY(!storage_buffer_sem)) {
                         TINT_ICE() << "expected form of arrayLength argument to be &array_var or "
                                       "&struct_var.array_member";
-                        break;
                     }
                     if (TINT_UNLIKELY(storage_buffer_sem->Type()->Is<core::type::Pointer>())) {
                         TINT_ICE()
                             << "storage buffer variable should not be a pointer. These should have "
                                "been removed by the SimplifyPointers transform";
-                        break;
                     }
                     auto* storage_buffer_var = storage_buffer_sem->Variable();
                     auto* storage_buffer_type =
@@ -234,7 +232,6 @@
                             if (TINT_UNLIKELY(!array_type)) {
                                 TINT_ICE() << "expected form of arrayLength argument to be "
                                               "&array_var or &struct_var.array_member";
-                                return name;
                             }
 
                             uint32_t array_stride = array_type->Size();
diff --git a/src/tint/lang/hlsl/writer/ast_raise/decompose_memory_access.cc b/src/tint/lang/hlsl/writer/ast_raise/decompose_memory_access.cc
index 91e67b5..0b2500a 100644
--- a/src/tint/lang/hlsl/writer/ast_raise/decompose_memory_access.cc
+++ b/src/tint/lang/hlsl/writer/ast_raise/decompose_memory_access.cc
@@ -308,7 +308,6 @@
         default:
             TINT_ICE() << "invalid IntrinsicType for DecomposeMemoryAccess::Intrinsic: "
                        << ty->TypeInfo().name;
-            break;
     }
 
     DecomposeMemoryAccess::Intrinsic::DataType type;
@@ -513,7 +512,6 @@
                     //   this method only handles storage and uniform.
                     // * Runtime-sized arrays are not loadable.
                     TINT_ICE() << "unexpected non-constant array count";
-                    arr_cnt = 1;
                 }
                 auto* for_cond = b.create<ast::BinaryExpression>(
                     core::BinaryOp::kLessThan, b.Expr(i), b.Expr(u32(arr_cnt.value())));
@@ -599,7 +597,6 @@
                             //   arrays, and this method only handles storage and uniform.
                             // * Runtime-sized arrays are not storable.
                             TINT_ICE() << "unexpected non-constant array count";
-                            arr_cnt = 1;
                         }
                         auto* for_cond = b.create<ast::BinaryExpression>(
                             core::BinaryOp::kLessThan, b.Expr(i), b.Expr(u32(arr_cnt.value())));
diff --git a/src/tint/lang/hlsl/writer/ast_raise/localize_struct_array_assignment.cc b/src/tint/lang/hlsl/writer/ast_raise/localize_struct_array_assignment.cc
index 84574c8..c01539c 100644
--- a/src/tint/lang/hlsl/writer/ast_raise/localize_struct_array_assignment.cc
+++ b/src/tint/lang/hlsl/writer/ast_raise/localize_struct_array_assignment.cc
@@ -188,7 +188,6 @@
                         TINT_ICE()
                             << "lhs of index accessor expression should not be a pointer. These "
                                "should have been removed by the SimplifyPointers transform";
-                        return ast::TraverseAction::Stop;
                     }
                     // That accesses an array?
                     if (ma_ty->UnwrapRef()->Is<core::type::Array>()) {
@@ -212,7 +211,6 @@
         if (TINT_UNLIKELY(!root_ident)) {
             TINT_ICE() << "Unable to determine originating variable for lhs of assignment "
                           "statement";
-            return {};
         }
 
         return Switch(
diff --git a/src/tint/lang/hlsl/writer/ast_raise/pixel_local.cc b/src/tint/lang/hlsl/writer/ast_raise/pixel_local.cc
index d193740..ab29724 100644
--- a/src/tint/lang/hlsl/writer/ast_raise/pixel_local.cc
+++ b/src/tint/lang/hlsl/writer/ast_raise/pixel_local.cc
@@ -103,7 +103,6 @@
                 if (entry_point != nullptr) {
                     TINT_ICE() << "PixelLocal transform requires that the SingleEntryPoint "
                                   "transform has already been run";
-                    return SkipTransform;
                 }
                 entry_point = sem.Get(fn);
 
@@ -380,7 +379,6 @@
                     break;
                 default:
                     TINT_UNREACHABLE();
-                    break;
             }
             auto pixel_local_var_member_access_in_store_call =
                 b.MemberAccessor(pixel_local_variable_name, ctx.Clone(member->Name()));
@@ -401,7 +399,6 @@
                         break;
                     default:
                         TINT_UNREACHABLE();
-                        break;
                 }
                 auto bitcast_to_rov_format_call =
                     b.Bitcast(rov_pixel_ast_type, pixel_local_var_member_access_in_store_call);
diff --git a/src/tint/lang/hlsl/writer/ast_raise/truncate_interstage_variables.cc b/src/tint/lang/hlsl/writer/ast_raise/truncate_interstage_variables.cc
index 07dd208..fc9e35c 100644
--- a/src/tint/lang/hlsl/writer/ast_raise/truncate_interstage_variables.cc
+++ b/src/tint/lang/hlsl/writer/ast_raise/truncate_interstage_variables.cc
@@ -104,7 +104,6 @@
             TINT_ICE() << "Entrypoint function return type is non-struct.\n"
                        << "TruncateInterstageVariables transform needs to run after "
                           "CanonicalizeEntryPointIO transform.";
-            continue;
         }
 
         // A prepass to check if any interstage variable locations in the entry point needs
diff --git a/src/tint/lang/msl/ir/builtin_call_test.cc b/src/tint/lang/msl/ir/builtin_call_test.cc
index cbe47ba..9e76938 100644
--- a/src/tint/lang/msl/ir/builtin_call_test.cc
+++ b/src/tint/lang/msl/ir/builtin_call_test.cc
@@ -27,7 +27,6 @@
 
 #include "src/tint/lang/msl/ir/builtin_call.h"
 #include "gmock/gmock.h"
-#include "gtest/gtest-spi.h"
 #include "src/tint/lang/core/ir/ir_helper_test.h"
 
 namespace tint::msl::ir {
diff --git a/src/tint/lang/msl/writer/ast_printer/ast_printer.cc b/src/tint/lang/msl/writer/ast_printer/ast_printer.cc
index 0ba01d6..292ed74 100644
--- a/src/tint/lang/msl/writer/ast_printer/ast_printer.cc
+++ b/src/tint/lang/msl/writer/ast_printer/ast_printer.cc
@@ -1020,7 +1020,6 @@
     }
 
     TINT_UNREACHABLE() << "unsupported atomic builtin: " << builtin->Fn();
-    return false;
 }
 
 bool ASTPrinter::EmitTextureCall(StringStream& out,
@@ -1041,7 +1040,6 @@
     auto* texture = arg(Usage::kTexture)->Declaration();
     if (TINT_UNLIKELY(!texture)) {
         TINT_ICE() << "missing texture arg";
-        return false;
     }
 
     auto* texture_type = TypeOf(texture)->UnwrapRef()->As<core::type::Texture>();
@@ -1178,7 +1176,6 @@
             break;
         default:
             TINT_UNREACHABLE() << "Unhandled texture builtin '" << builtin->str() << "'";
-            return false;
     }
 
     bool first_arg = true;
@@ -1211,7 +1208,6 @@
                         break;
                     default:
                         TINT_ICE() << "unhandled texture dimensionality";
-                        break;
                 }
             }
 
@@ -1324,7 +1320,6 @@
                 break;
             default:
                 TINT_ICE() << "invalid textureGather component: " << c;
-                break;
         }
     }
 
@@ -1976,13 +1971,11 @@
     auto get_binding_index = [&](const ast::Parameter* param) -> uint32_t {
         if (TINT_UNLIKELY(!param->HasBindingPoint())) {
             TINT_ICE() << "missing binding attributes for entry point parameter";
-            return kInvalidBindingIndex;
         }
         auto* param_sem = builder_.Sem().Get(param);
         auto bp = param_sem->Attributes().binding_point;
         if (TINT_UNLIKELY(bp->group != 0)) {
             TINT_ICE() << "encountered non-zero resource group index (use BindingRemapper to fix)";
-            return kInvalidBindingIndex;
         }
         return bp->binding;
     };
@@ -2057,7 +2050,6 @@
                             break;
                     }
                     TINT_ICE() << "invalid pointer address space for entry point parameter";
-                    return false;
                 },
                 [&](Default) {
                     auto& attrs = param->attributes;
@@ -2080,7 +2072,6 @@
                     }
                     if (TINT_UNLIKELY(!builtin_found)) {
                         TINT_ICE() << "Unsupported entry point parameter";
-                        return false;
                     }
                     return true;
                 });
@@ -2517,7 +2508,6 @@
                 return true;
             }
             TINT_ICE() << "unhandled atomic type " << atomic->Type()->FriendlyName();
-            return false;
         },
         [&](const core::type::Array* arr) {
             out << ArrayType() << "<";
@@ -2596,7 +2586,6 @@
         [&](const core::type::Texture* tex) {
             if (TINT_UNLIKELY(tex->Is<core::type::ExternalTexture>())) {
                 TINT_ICE() << "Multiplanar external texture transform was not run.";
-                return false;
             }
 
             if (tex->IsAnyOf<core::type::DepthTexture, core::type::DepthMultisampledTexture>()) {
@@ -2731,7 +2720,6 @@
             break;
     }
     TINT_ICE() << "unhandled address space: " << sc;
-    return false;
 }
 
 bool ASTPrinter::EmitStructType(TextBuffer* b, const core::type::Struct* str) {
@@ -2775,7 +2763,6 @@
                 // Unimplementable layout
                 TINT_ICE() << "Structure member WGSL offset (" << wgsl_offset
                            << ") is behind MSL offset (" << msl_offset << ")";
-                return false;
             }
 
             // Generate padding if required
@@ -2810,7 +2797,6 @@
             auto& pipeline_stage_uses = str->PipelineStageUses();
             if (TINT_UNLIKELY(pipeline_stage_uses.Count() != 1)) {
                 TINT_ICE() << "invalid entry point IO struct uses for " << str->Name().NameView();
-                return false;
             }
 
             if (pipeline_stage_uses.Contains(core::type::PipelineStageUsage::kVertexInput)) {
@@ -2831,7 +2817,6 @@
                 }
             } else {
                 TINT_ICE() << "invalid use of location decoration";
-                return false;
             }
         }
 
@@ -2861,7 +2846,6 @@
             if (TINT_UNLIKELY(msl_offset % size_align.align)) {
                 TINT_ICE() << "Misaligned MSL structure member " << ty->FriendlyName() << " "
                            << mem_name;
-                return false;
             }
             msl_offset += size_align.size;
         }
@@ -2968,7 +2952,6 @@
             break;
         default:
             TINT_ICE() << "unhandled variable address space";
-            return false;
     }
 
     if (!EmitType(out, type)) {
@@ -3013,7 +2996,6 @@
             break;
         default:
             TINT_ICE() << "unhandled variable address space";
-            return false;
     }
 
     if (!EmitType(out, type)) {
diff --git a/src/tint/lang/msl/writer/ast_raise/module_scope_var_to_entry_point_param.cc b/src/tint/lang/msl/writer/ast_raise/module_scope_var_to_entry_point_param.cc
index 370164a..946fa0a 100644
--- a/src/tint/lang/msl/writer/ast_raise/module_scope_var_to_entry_point_param.cc
+++ b/src/tint/lang/msl/writer/ast_raise/module_scope_var_to_entry_point_param.cc
@@ -216,7 +216,6 @@
                 break;  // Ignore
             default: {
                 TINT_ICE() << "unhandled module-scope address space (" << sc << ")";
-                break;
             }
         }
     }
diff --git a/src/tint/lang/msl/writer/ast_raise/packed_vec3.cc b/src/tint/lang/msl/writer/ast_raise/packed_vec3.cc
index a1f2321..816e014 100644
--- a/src/tint/lang/msl/writer/ast_raise/packed_vec3.cc
+++ b/src/tint/lang/msl/writer/ast_raise/packed_vec3.cc
@@ -174,7 +174,6 @@
                         return b.ty.array(new_type, u32(count.value()), std::move(attrs));
                     } else {
                         TINT_ICE() << core::type::Array::kErrExpectedConstantCount;
-                        return {};
                     }
                 }
                 return {};
diff --git a/src/tint/lang/msl/writer/ast_raise/pixel_local.cc b/src/tint/lang/msl/writer/ast_raise/pixel_local.cc
index a9a79d8..16d849b 100644
--- a/src/tint/lang/msl/writer/ast_raise/pixel_local.cc
+++ b/src/tint/lang/msl/writer/ast_raise/pixel_local.cc
@@ -96,7 +96,6 @@
                 if (entry_point != nullptr) {
                     TINT_ICE() << "PixelLocal transform requires that the SingleEntryPoint "
                                   "transform has already been run";
-                    return SkipTransform;
                 }
                 entry_point = sem.Get(fn);
 
diff --git a/src/tint/lang/msl/writer/common/printer_support.cc b/src/tint/lang/msl/writer/common/printer_support.cc
index 63a561c..2f9bfa0 100644
--- a/src/tint/lang/msl/writer/common/printer_support.cc
+++ b/src/tint/lang/msl/writer/common/printer_support.cc
@@ -156,7 +156,6 @@
                 }
             }
             TINT_UNREACHABLE() << "Unhandled vector element type " << el_ty->TypeInfo().name;
-            return SizeAndAlign{};
         },
 
         [&](const core::type::Matrix* mat) {
@@ -199,14 +198,12 @@
             }
 
             TINT_UNREACHABLE() << "Unhandled matrix element type " << el_ty->TypeInfo().name;
-            return SizeAndAlign{};
         },
 
         [&](const core::type::Array* arr) {
             if (TINT_UNLIKELY(!arr->IsStrideImplicit())) {
                 TINT_ICE()
                     << "arrays with explicit strides should not exist past the SPIR-V reader";
-                return SizeAndAlign{};
             }
             if (arr->Count()->Is<core::type::RuntimeArrayCount>()) {
                 return SizeAndAlign{arr->Stride(), arr->Align()};
@@ -215,7 +212,6 @@
                 return SizeAndAlign{arr->Stride() * count.value(), arr->Align()};
             }
             TINT_ICE() << core::type::Array::kErrExpectedConstantCount;
-            return SizeAndAlign{};
         },
 
         [&](const core::type::Struct* str) {
diff --git a/src/tint/lang/msl/writer/printer/printer.cc b/src/tint/lang/msl/writer/printer/printer.cc
index 3c34b32..c4fadc3 100644
--- a/src/tint/lang/msl/writer/printer/printer.cc
+++ b/src/tint/lang/msl/writer/printer/printer.cc
@@ -398,7 +398,6 @@
                 break;
             default:
                 TINT_UNIMPLEMENTED() << u->Op();
-                break;
         }
         out << "(";
         EmitValue(out, u->Val());
@@ -484,7 +483,7 @@
         auto out = Line();
 
         auto* ptr = v->Result(0)->Type()->As<core::type::Pointer>();
-        TINT_ASSERT_OR_RETURN(ptr);
+        TINT_ASSERT(ptr);
 
         auto space = ptr->AddressSpace();
         switch (space) {
@@ -499,7 +498,6 @@
                 break;
             default:
                 TINT_IR_ICE(ir_) << "unhandled variable address space";
-                return;
         }
 
         EmitType(out, ptr->UnwrapPtr());
@@ -791,7 +789,6 @@
             }
             default:
                 TINT_ICE() << "undefined MSL ir function";
-                return;
         }
     }
 
@@ -1011,7 +1008,6 @@
                 break;
             default:
                 TINT_IR_ICE(ir_) << "unhandled address space: " << sc;
-                break;
         }
     }
 
@@ -1084,7 +1080,6 @@
             auto count = arr->ConstantCount();
             if (!count) {
                 TINT_IR_ICE(ir_) << core::type::Array::kErrExpectedConstantCount;
-                return;
             }
             out << count.value();
         }
@@ -1116,7 +1111,6 @@
     void EmitTextureType(StringStream& out, const core::type::Texture* tex) {
         if (TINT_UNLIKELY(tex->Is<core::type::ExternalTexture>())) {
             TINT_IR_ICE(ir_) << "Multiplanar external texture transform was not run.";
-            return;
         }
 
         if (tex->IsAnyOf<core::type::DepthTexture, core::type::DepthMultisampledTexture>()) {
@@ -1146,7 +1140,6 @@
                 break;
             default:
                 TINT_IR_ICE(ir_) << "invalid texture dimensions";
-                return;
         }
         if (tex->IsAnyOf<core::type::MultisampledTexture, core::type::DepthMultisampledTexture>()) {
             out << "_ms";
@@ -1169,7 +1162,6 @@
                     out << "access::write";
                 } else {
                     TINT_IR_ICE(ir_) << "invalid access control for storage texture";
-                    return;
                 }
             },
             [&](const core::type::MultisampledTexture* ms) {
@@ -1232,7 +1224,6 @@
                     // Unimplementable layout
                     TINT_IR_ICE(ir_) << "Structure member offset (" << ir_offset
                                      << ") is behind MSL offset (" << msl_offset << ")";
-                    return;
                 }
 
                 // Generate padding if required
@@ -1256,7 +1247,6 @@
                 auto name = BuiltinToAttribute(builtin.value());
                 if (name.empty()) {
                     TINT_IR_ICE(ir_) << "unknown builtin";
-                    return;
                 }
                 out << " [[" << name << "]]";
             }
@@ -1265,7 +1255,6 @@
                 auto& pipeline_stage_uses = str->PipelineStageUses();
                 if (TINT_UNLIKELY(pipeline_stage_uses.Count() != 1)) {
                     TINT_IR_ICE(ir_) << "invalid entry point IO struct uses";
-                    return;
                 }
 
                 if (pipeline_stage_uses.Contains(core::type::PipelineStageUsage::kVertexInput)) {
@@ -1281,7 +1270,6 @@
                     out << " [[color(" + std::to_string(location.value()) + ")]]";
                 } else {
                     TINT_IR_ICE(ir_) << "invalid use of location decoration";
-                    return;
                 }
             }
 
@@ -1289,7 +1277,6 @@
                 auto name = InterpolationToAttribute(interpolation->type, interpolation->sampling);
                 if (name.empty()) {
                     TINT_IR_ICE(ir_) << "unknown interpolation attribute";
-                    return;
                 }
                 out << " [[" << name << "]]";
             }
@@ -1308,7 +1295,6 @@
                     TINT_IR_ICE(ir_) << "Misaligned MSL structure member " << mem_name << " : "
                                      << ty->FriendlyName() << " offset: " << msl_offset
                                      << " align: " << size_align.align;
-                    return;
                 }
                 msl_offset += size_align.size;
             }
@@ -1378,7 +1364,6 @@
                 auto count = a->ConstantCount();
                 if (!count) {
                     TINT_IR_ICE(ir_) << core::type::Array::kErrExpectedConstantCount;
-                    return;
                 }
                 emit_values(*count);
             },
diff --git a/src/tint/lang/msl/writer/raise/builtin_polyfill.cc b/src/tint/lang/msl/writer/raise/builtin_polyfill.cc
index 5887c3e..e41330f 100644
--- a/src/tint/lang/msl/writer/raise/builtin_polyfill.cc
+++ b/src/tint/lang/msl/writer/raise/builtin_polyfill.cc
@@ -87,7 +87,7 @@
                 default:
                     break;
             }
-            TINT_ASSERT_OR_RETURN(replacement);
+            TINT_ASSERT(replacement);
 
             // Replace the old builtin result with the new value.
             if (auto name = ir.NameOf(builtin->Result(0))) {
diff --git a/src/tint/lang/spirv/ir/builtin_call_test.cc b/src/tint/lang/spirv/ir/builtin_call_test.cc
index 4256f26..bd5ba07 100644
--- a/src/tint/lang/spirv/ir/builtin_call_test.cc
+++ b/src/tint/lang/spirv/ir/builtin_call_test.cc
@@ -27,7 +27,6 @@
 
 #include "src/tint/lang/spirv/ir/builtin_call.h"
 #include "gmock/gmock.h"
-#include "gtest/gtest-spi.h"
 #include "src/tint/lang/core/ir/ir_helper_test.h"
 
 namespace tint::spirv::ir {
diff --git a/src/tint/lang/spirv/reader/ast_lower/decompose_strided_array.cc b/src/tint/lang/spirv/reader/ast_lower/decompose_strided_array.cc
index bba5bb1..4262a41 100644
--- a/src/tint/lang/spirv/reader/ast_lower/decompose_strided_array.cc
+++ b/src/tint/lang/spirv/reader/ast_lower/decompose_strided_array.cc
@@ -146,7 +146,6 @@
             if (TINT_UNLIKELY(ty->Is<core::type::Pointer>())) {
                 TINT_ICE() << "lhs of index accessor expression should not be a pointer. These "
                               "should have been removed by the SimplifyPointers transform";
-                return nullptr;
             }
             if (auto* arr = ty->UnwrapRef()->As<core::type::Array>()) {
                 if (!arr->IsStrideImplicit()) {
diff --git a/src/tint/lang/spirv/reader/ast_lower/pass_workgroup_id_as_argument.cc b/src/tint/lang/spirv/reader/ast_lower/pass_workgroup_id_as_argument.cc
index 71f07ec..8424e0b 100644
--- a/src/tint/lang/spirv/reader/ast_lower/pass_workgroup_id_as_argument.cc
+++ b/src/tint/lang/spirv/reader/ast_lower/pass_workgroup_id_as_argument.cc
@@ -95,7 +95,7 @@
 
         // The reader should only produce a single use of the parameter which assigns to a global.
         const auto& users = sem.Get(builtin)->Users();
-        TINT_ASSERT_OR_RETURN(users.Length() == 1u);
+        TINT_ASSERT(users.Length() == 1u);
         auto* assign = users[0]->Stmt()->Declaration()->As<ast::AssignmentStatement>();
         auto& stmts =
             sem.Get(assign)->Parent()->Declaration()->As<ast::BlockStatement>()->statements;
@@ -112,10 +112,9 @@
                 }
             }
         }
-        TINT_ASSERT_OR_RETURN(assign && rhs == users[0]->Declaration());
+        TINT_ASSERT(assign && rhs == users[0]->Declaration());
         auto* lhs = sem.GetVal(assign->lhs)->As<sem::VariableUser>();
-        TINT_ASSERT_OR_RETURN(lhs &&
-                              lhs->Variable()->AddressSpace() == core::AddressSpace::kPrivate);
+        TINT_ASSERT(lhs && lhs->Variable()->AddressSpace() == core::AddressSpace::kPrivate);
 
         // Replace all references to the global variable with a function parameter.
         for (auto* user : lhs->Variable()->Users()) {
diff --git a/src/tint/lang/spirv/reader/ast_parser/function.cc b/src/tint/lang/spirv/reader/ast_parser/function.cc
index f459cdb..f9ea302 100644
--- a/src/tint/lang/spirv/reader/ast_parser/function.cc
+++ b/src/tint/lang/spirv/reader/ast_parser/function.cc
@@ -4919,7 +4919,6 @@
                 break;
         }
         TINT_UNREACHABLE() << "expected a memory object declaration";
-        return {};
     };
 
     auto where = def_info_.find(id);
diff --git a/src/tint/lang/spirv/reader/ast_parser/namer.cc b/src/tint/lang/spirv/reader/ast_parser/namer.cc
index e7461db..2482b4d 100644
--- a/src/tint/lang/spirv/reader/ast_parser/namer.cc
+++ b/src/tint/lang/spirv/reader/ast_parser/namer.cc
@@ -248,7 +248,6 @@
         i++;
     }
     TINT_UNREACHABLE() << "FindUnusedDerivedName() overflowed u32";
-    return "<u32 overflow>";
 }
 
 std::string Namer::MakeDerivedName(const std::string& base_name) {
diff --git a/src/tint/lang/spirv/reader/parser/parser.cc b/src/tint/lang/spirv/reader/parser/parser.cc
index 8fadddf..6dd8fb0 100644
--- a/src/tint/lang/spirv/reader/parser/parser.cc
+++ b/src/tint/lang/spirv/reader/parser/parser.cc
@@ -118,7 +118,6 @@
             default:
                 TINT_UNIMPLEMENTED()
                     << "unhandled SPIR-V storage class: " << static_cast<uint32_t>(sc);
-                return core::AddressSpace::kUndefined;
         }
     }
 
@@ -156,7 +155,6 @@
                 return core::BuiltinValue::kWorkgroupId;
             default:
                 TINT_UNIMPLEMENTED() << "unhandled SPIR-V BuiltIn: " << static_cast<uint32_t>(b);
-                return core::BuiltinValue::kUndefined;
         }
     }
 
@@ -173,7 +171,7 @@
                     return ty_.bool_();
                 case spvtools::opt::analysis::Type::kInteger: {
                     auto* int_ty = type->AsInteger();
-                    TINT_ASSERT_OR_RETURN_VALUE(int_ty->width() == 32, ty_.void_());
+                    TINT_ASSERT(int_ty->width() == 32);
                     if (int_ty->IsSigned()) {
                         return ty_.i32();
                     } else {
@@ -189,17 +187,16 @@
                     } else {
                         TINT_UNREACHABLE()
                             << "unsupported floating point type width: " << float_ty->width();
-                        return ty_.void_();
                     }
                 }
                 case spvtools::opt::analysis::Type::kVector: {
                     auto* vec_ty = type->AsVector();
-                    TINT_ASSERT_OR_RETURN_VALUE(vec_ty->element_count() <= 4, ty_.void_());
+                    TINT_ASSERT(vec_ty->element_count() <= 4);
                     return ty_.vec(Type(vec_ty->element_type()), vec_ty->element_count());
                 }
                 case spvtools::opt::analysis::Type::kMatrix: {
                     auto* mat_ty = type->AsMatrix();
-                    TINT_ASSERT_OR_RETURN_VALUE(mat_ty->element_count() <= 4, ty_.void_());
+                    TINT_ASSERT(mat_ty->element_count() <= 4);
                     return ty_.mat(As<core::type::Vector>(Type(mat_ty->element_type())),
                                    mat_ty->element_count());
                 }
@@ -214,7 +211,6 @@
                 }
                 default:
                     TINT_UNIMPLEMENTED() << "unhandled SPIR-V type: " << type->str();
-                    return ty_.void_();
             }
         });
     }
@@ -230,18 +226,17 @@
     /// @returns a Tint array object
     const core::type::Type* EmitArray(const spvtools::opt::analysis::Array* arr_ty) {
         const auto& length = arr_ty->length_info();
-        TINT_ASSERT_OR_RETURN_VALUE(!length.words.empty(), ty_.void_());
+        TINT_ASSERT(!length.words.empty());
         if (length.words[0] != spvtools::opt::analysis::Array::LengthInfo::kConstant) {
             TINT_UNIMPLEMENTED() << "specialized array lengths";
-            return ty_.void_();
         }
 
         // Get the value from the constant used for the element count.
         const auto* count_const =
             spirv_context_->get_constant_mgr()->FindDeclaredConstant(length.id);
-        TINT_ASSERT_OR_RETURN_VALUE(count_const, ty_.void_());
+        TINT_ASSERT(count_const);
         const uint64_t count_val = count_const->GetZeroExtendedValue();
-        TINT_ASSERT_OR_RETURN_VALUE(count_val <= UINT32_MAX, ty_.void_());
+        TINT_ASSERT(count_val <= UINT32_MAX);
 
         // TODO(crbug.com/1907): Handle decorations that affect the array layout.
 
@@ -253,7 +248,6 @@
     const core::type::Type* EmitStruct(const spvtools::opt::analysis::Struct* struct_ty) {
         if (struct_ty->NumberOfComponents() == 0) {
             TINT_ICE() << "empty structures are not supported";
-            return ty_.void_();
         }
 
         // Build a list of struct members.
@@ -305,7 +299,6 @@
 
                         default:
                             TINT_UNIMPLEMENTED() << "unhandled member decoration: " << deco[0];
-                            break;
                     }
                 }
             }
@@ -338,7 +331,6 @@
                 return b_.Constant(Constant(c));
             }
             TINT_UNREACHABLE() << "missing value for result ID " << id;
-            return nullptr;
         });
     }
 
@@ -355,7 +347,7 @@
         }
         if (auto* i = constant->AsIntConstant()) {
             auto* int_ty = i->type()->AsInteger();
-            TINT_ASSERT_OR_RETURN_VALUE(int_ty->width() == 32, nullptr);
+            TINT_ASSERT(int_ty->width() == 32);
             if (int_ty->IsSigned()) {
                 return b_.ConstantValue(i32(i->GetS32BitValue()));
             } else {
@@ -370,7 +362,6 @@
                 return b_.ConstantValue(f32(f->GetFloat()));
             } else {
                 TINT_UNREACHABLE() << "unsupported floating point type width";
-                return nullptr;
             }
         }
         if (auto* v = constant->AsVectorConstant()) {
@@ -402,7 +393,6 @@
             return ir_.constant_values.Composite(Type(s->type()), std::move(elements));
         }
         TINT_UNIMPLEMENTED() << "unhandled constant type";
-        return nullptr;
     }
 
     /// Register an IR value for a SPIR-V result ID.
@@ -416,7 +406,7 @@
     void Emit(core::ir::Instruction* inst, uint32_t result_id = 0) {
         current_block_->Append(inst);
         if (result_id != 0) {
-            TINT_ASSERT_OR_RETURN(inst->Results().Length() == 1u);
+            TINT_ASSERT(inst->Results().Length() == 1u);
             AddValue(result_id, inst->Result(0));
         }
     }
@@ -479,7 +469,7 @@
         for (auto& execution_mode : spirv_context_->module()->execution_modes()) {
             auto* func = functions_.GetOr(execution_mode.GetSingleWordInOperand(0), nullptr);
             auto mode = execution_mode.GetSingleWordInOperand(1);
-            TINT_ASSERT_OR_RETURN(func);
+            TINT_ASSERT(func);
 
             switch (spv::ExecutionMode(mode)) {
                 case spv::ExecutionMode::LocalSize:
@@ -658,7 +648,6 @@
                     break;
                 default:
                     TINT_UNIMPLEMENTED() << "unhandled decoration " << d;
-                    break;
             }
         }
 
diff --git a/src/tint/lang/spirv/reader/parser/struct_test.cc b/src/tint/lang/spirv/reader/parser/struct_test.cc
index 88d7349..7c85914 100644
--- a/src/tint/lang/spirv/reader/parser/struct_test.cc
+++ b/src/tint/lang/spirv/reader/parser/struct_test.cc
@@ -27,12 +27,10 @@
 
 #include "src/tint/lang/spirv/reader/parser/helper_test.h"
 
-#include "gtest/gtest-spi.h"
-
 namespace tint::spirv::reader {
 
 TEST_F(SpirvParserTest, Struct_Empty) {
-    EXPECT_FATAL_FAILURE(  //
+    EXPECT_DEATH(  //
         {
             auto assembly = Assemble(R"(
                OpCapability Shader
diff --git a/src/tint/lang/spirv/writer/ast_printer/assign_test.cc b/src/tint/lang/spirv/writer/ast_printer/assign_test.cc
index 67937aa..24ad65b 100644
--- a/src/tint/lang/spirv/writer/ast_printer/assign_test.cc
+++ b/src/tint/lang/spirv/writer/ast_printer/assign_test.cc
@@ -26,7 +26,6 @@
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include "gmock/gmock.h"
-#include "gtest/gtest-spi.h"
 #include "src/tint/lang/spirv/writer/ast_printer/helper_test.h"
 #include "src/tint/lang/spirv/writer/common/spv_dump_test.h"
 
@@ -67,7 +66,7 @@
 }
 
 TEST_F(SpirvASTPrinterTest, Assign_Var_OutsideFunction_IsError) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder pb;
 
diff --git a/src/tint/lang/spirv/writer/ast_printer/ast_if_test.cc b/src/tint/lang/spirv/writer/ast_printer/ast_if_test.cc
index 8933a35..2404561 100644
--- a/src/tint/lang/spirv/writer/ast_printer/ast_if_test.cc
+++ b/src/tint/lang/spirv/writer/ast_printer/ast_if_test.cc
@@ -26,7 +26,6 @@
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include "gmock/gmock.h"
-#include "gtest/gtest-spi.h"
 #include "src/tint/lang/spirv/writer/ast_printer/helper_test.h"
 #include "src/tint/lang/spirv/writer/common/spv_dump_test.h"
 
@@ -65,7 +64,7 @@
     // if (true) {
     // }
 
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder pb;
 
diff --git a/src/tint/lang/spirv/writer/ast_printer/builder.cc b/src/tint/lang/spirv/writer/ast_printer/builder.cc
index 4720efc..da7014c 100644
--- a/src/tint/lang/spirv/writer/ast_printer/builder.cc
+++ b/src/tint/lang/spirv/writer/ast_printer/builder.cc
@@ -327,7 +327,6 @@
     auto it = var_to_id_.find(var);
     if (it == var_to_id_.end()) {
         TINT_ICE() << "unable to find ID for variable: " + var->Declaration()->name->symbol.Name();
-        return 0;
     }
     return it->second;
 }
@@ -395,7 +394,6 @@
 bool Builder::GenerateBreakStatement(const ast::BreakStatement*) {
     if (merge_stack_.empty()) {
         TINT_ICE() << "Attempted to break without a merge block";
-        return false;
     }
     if (!push_function_inst(spv::Op::OpBranch, {Operand(merge_stack_.back())})) {
         return false;
@@ -419,7 +417,6 @@
 bool Builder::GenerateContinueStatement(const ast::ContinueStatement*) {
     if (continue_stack_.empty()) {
         TINT_ICE() << "Attempted to continue without a continue block";
-        return false;
     }
     if (!push_function_inst(spv::Op::OpBranch, {Operand(continue_stack_.back())})) {
         return false;
@@ -441,7 +438,6 @@
     auto stage = pipeline_stage_to_execution_model(func->PipelineStage());
     if (stage == SpvExecutionModelMax) {
         TINT_ICE() << "Unknown pipeline stage provided";
-        return false;
     }
 
     OperandList operands = {Operand(stage), Operand(id), Operand(func->name->symbol.Name())};
@@ -459,7 +455,6 @@
         if (var_id == 0) {
             TINT_ICE() << "unable to find ID for global variable: " +
                               var->Declaration()->name->symbol.Name();
-            return false;
         }
 
         operands.push_back(Operand(var_id));
@@ -484,7 +479,6 @@
             TINT_ICE()
                 << "override-expressions should have been removed with the SubstituteOverride "
                    "transform";
-            return false;
         }
         module_.PushExecutionMode(
             spv::Op::OpExecutionMode,
@@ -662,7 +656,6 @@
     if (v->Is<ast::Let>()) {
         if (!v->initializer) {
             TINT_ICE() << "missing initializer for let";
-            return false;
         }
         RegisterVariable(sem, init_id);
         return true;
@@ -713,7 +706,6 @@
     auto* sem = builder_.Sem().Get<sem::GlobalVariable>(v);
     if (TINT_UNLIKELY(!sem)) {
         TINT_ICE() << "attempted to generate a global from a non-global variable";
-        return false;
     }
     auto* type = sem->Type()->UnwrapRef();
 
@@ -876,7 +868,6 @@
     } else if (TINT_UNLIKELY(info->source_type->Is<core::type::Pointer>())) {
         TINT_ICE() << "lhs of index accesor expression should not be a pointer. These should have "
                       "been removed by the SimplifyPointers transform";
-        return false;
     }
 
     auto result_type_id = GenerateTypeIfNeeded(TypeOf(expr));
@@ -922,7 +913,6 @@
     }
 
     TINT_ICE() << "unsupported index accessor expression";
-    return false;
 }
 
 bool Builder::GenerateMemberAccessor(const ast::MemberAccessorExpression* expr,
@@ -1125,7 +1115,6 @@
     }
     TINT_ICE() << "identifier '" + expr->identifier->symbol.Name() +
                       "' does not resolve to a variable";
-    return 0;
 }
 
 uint32_t Builder::GenerateLoad(const core::type::Reference* type, uint32_t id) {
@@ -1219,7 +1208,6 @@
         }
     }
     TINT_ICE() << "unknown constructor expression";
-    return 0;
 }
 
 bool Builder::IsConstructorConst(const ast::CallExpression* expr) {
@@ -1386,7 +1374,6 @@
             }
         } else {
             TINT_ICE() << "Unhandled type cast value type";
-            return 0;
         }
     }
 
@@ -1430,7 +1417,6 @@
     if (TINT_UNLIKELY(is_global_init)) {
         TINT_ICE() << "Module-level conversions are not supported. Conversions should "
                       "have already been constant-folded by the FoldConstants transform.";
-        return 0;
     }
 
     auto elem_type_of = [](const core::type::Type* t) -> const core::type::Type* {
@@ -1526,7 +1512,6 @@
             one_id = GenerateConstantIfNeeded(ScalarConstant::I32(1));
         } else {
             TINT_ICE() << "invalid destination type for bool conversion";
-            return false;
         }
         if (auto* to_vec = to_type->As<core::type::Vector>()) {
             // Splat the scalars into vectors.
@@ -1563,7 +1548,6 @@
     if (op == spv::Op::OpNop) {
         TINT_ICE() << "unable to determine conversion type for cast, from: " +
                           from_type->FriendlyName() + " to: " + to_type->FriendlyName();
-        return 0;
     }
 
     if (!push_function_inst(op, {Operand(result_type_id), result, Operand(val_id)})) {
@@ -1679,9 +1663,8 @@
         [&](const core::type::Matrix* m) { return composite(m->columns()); },
         [&](const core::type::Array* a) {
             auto count = a->ConstantCount();
-            if (!count) {
+            if (TINT_UNLIKELY(!count)) {
                 TINT_ICE() << core::type::Array::kErrExpectedConstantCount;
-                return static_cast<uint32_t>(0);
             }
             return composite(count.value());
         },
@@ -1997,7 +1980,6 @@
         // This should already have been validated by resolver
         if (lhs_mat->rows() != rhs_mat->rows() || lhs_mat->columns() != rhs_mat->columns()) {
             TINT_ICE() << "matrices must have same dimensionality for add or subtract";
-            return 0;
         }
 
         return GenerateMatrixAddOrSub(lhs_id, rhs_id, lhs_mat,
@@ -2043,7 +2025,6 @@
             op = spv::Op::OpLogicalAnd;
         } else {
             TINT_ICE() << "invalid and expression";
-            return 0;
         }
     } else if (expr->IsAdd()) {
         op = lhs_is_float_or_vec ? spv::Op::OpFAdd : spv::Op::OpIAdd;
@@ -2064,7 +2045,6 @@
             op = spv::Op::OpIEqual;
         } else {
             TINT_ICE() << "invalid equal expression";
-            return 0;
         }
     } else if (expr->IsGreaterThan()) {
         if (lhs_is_float_or_vec) {
@@ -2144,7 +2124,6 @@
             op = spv::Op::OpMatrixTimesMatrix;
         } else {
             TINT_ICE() << "invalid multiply expression";
-            return 0;
         }
     } else if (expr->IsNotEqual()) {
         if (lhs_is_float_or_vec) {
@@ -2155,7 +2134,6 @@
             op = spv::Op::OpINotEqual;
         } else {
             TINT_ICE() << "invalid not-equal expression";
-            return 0;
         }
     } else if (expr->IsOr()) {
         if (lhs_is_integer_or_vec) {
@@ -2164,7 +2142,6 @@
             op = spv::Op::OpLogicalOr;
         } else {
             TINT_ICE() << "invalid and expression";
-            return 0;
         }
     } else if (expr->IsShiftLeft()) {
         op = spv::Op::OpShiftLeftLogical;
@@ -2179,7 +2156,6 @@
         op = spv::Op::OpBitwiseXor;
     } else {
         TINT_ICE() << "unknown binary expression";
-        return 0;
     }
 
     if (!push_function_inst(op, {Operand(type_id), result, Operand(lhs_id), Operand(rhs_id)})) {
@@ -2239,7 +2215,6 @@
     auto func_id = func_symbol_to_id_[ident->symbol];
     if (func_id == 0) {
         TINT_ICE() << "unable to find called function: " + ident->symbol.Name();
-        return 0;
     }
     ops.push_back(Operand(func_id));
 
@@ -2348,7 +2323,6 @@
             if (!address_of || address_of->op != core::UnaryOp::kAddressOf) {
                 TINT_ICE() << "arrayLength() expected pointer to member access, got " +
                                   std::string(address_of->TypeInfo().name);
-                return 0;
             }
             auto* array_expr = address_of->expr;
 
@@ -2356,7 +2330,6 @@
             if (!accessor) {
                 TINT_ICE() << "arrayLength() expected pointer to member access, got pointer to " +
                                   std::string(array_expr->TypeInfo().name);
-                return 0;
             }
 
             auto struct_id = GenerateExpression(accessor->object);
@@ -2369,7 +2342,6 @@
             if (!type->Is<core::type::Struct>()) {
                 TINT_ICE() << "invalid type (" + type->FriendlyName() +
                                   ") for runtime array length";
-                return 0;
             }
             // Runtime array must be the last member in the structure
             params.push_back(
@@ -2593,7 +2565,6 @@
             auto inst_id = builtin_to_glsl_method(builtin);
             if (inst_id == 0) {
                 TINT_ICE() << "unknown method " + std::string(builtin->str());
-                return 0;
             }
             glsl_std450(inst_id);
             break;
@@ -2602,7 +2573,6 @@
 
     if (op == spv::Op::OpNop) {
         TINT_ICE() << "unable to determine operator for: " + std::string(builtin->str());
-        return 0;
     }
 
     for (size_t i = 0; i < call->Arguments().Length(); i++) {
@@ -2793,7 +2763,6 @@
             switch (texture_type->dim()) {
                 case core::type::TextureDimension::kNone:
                     TINT_ICE() << "texture dimension is kNone";
-                    return false;
                 case core::type::TextureDimension::k1d:
                 case core::type::TextureDimension::k2d:
                 case core::type::TextureDimension::k3d:
@@ -2830,7 +2799,6 @@
             switch (texture_type->dim()) {
                 default:
                     TINT_ICE() << "texture is not arrayed";
-                    return false;
                 case core::type::TextureDimension::k2dArray:
                 case core::type::TextureDimension::kCubeArray:
                     spirv_dims = 3;
@@ -3001,7 +2969,6 @@
         }
         default:
             TINT_UNREACHABLE();
-            return false;
     }
 
     if (auto* offset = arg(Usage::kOffset)) {
@@ -3025,7 +2992,6 @@
 
     if (op == spv::Op::OpNop) {
         TINT_ICE() << "unable to determine operator for: " + std::string(builtin->str());
-        return false;
     }
 
     if (!push_function_inst(op, spirv_params)) {
@@ -3060,7 +3026,6 @@
                     static_cast<uint32_t>(spv::MemorySemanticsMask::ImageMemory);
     } else {
         TINT_ICE() << "unexpected barrier builtin type " << builtin->Fn();
-        return false;
     }
 
     auto execution_id = GenerateConstantIfNeeded(ScalarConstant::U32(execution));
@@ -3098,7 +3063,6 @@
             break;
         default:
             TINT_UNREACHABLE() << "unhandled atomic address space " << address_space;
-            return false;
     }
     if (memory_id == 0) {
         return false;
@@ -3280,7 +3244,6 @@
         }
         default:
             TINT_UNREACHABLE() << "unhandled atomic builtin " << builtin->Fn();
-            return false;
     }
 }
 
@@ -3643,7 +3606,6 @@
 uint32_t Builder::GenerateTypeIfNeeded(const core::type::Type* type) {
     if (type == nullptr) {
         TINT_ICE() << "attempting to generate type from null type";
-        return 0;
     }
 
     // Atomics are a type in WGSL, but aren't a distinct type in SPIR-V.
@@ -3771,7 +3733,6 @@
 bool Builder::GenerateTextureType(const core::type::Texture* texture, const Operand& result) {
     if (TINT_UNLIKELY(texture->Is<core::type::ExternalTexture>())) {
         TINT_ICE() << "Multiplanar external texture transform was not run.";
-        return false;
     }
 
     uint32_t array_literal = 0u;
@@ -3862,7 +3823,6 @@
         auto count = arr->ConstantCount();
         if (!count) {
             TINT_ICE() << core::type::Array::kErrExpectedConstantCount;
-            return static_cast<uint32_t>(0);
         }
 
         auto len_id = GenerateConstantIfNeeded(ScalarConstant::U32(count.value()));
@@ -3900,7 +3860,6 @@
     auto stg_class = ConvertAddressSpace(ptr->AddressSpace());
     if (stg_class == SpvStorageClassMax) {
         TINT_ICE() << "invalid address space for pointer";
-        return false;
     }
 
     module_.PushType(spv::Op::OpTypePointer, {result, U32Operand(stg_class), Operand(subtype_id)});
@@ -3917,7 +3876,6 @@
     auto stg_class = ConvertAddressSpace(ref->AddressSpace());
     if (stg_class == SpvStorageClassMax) {
         TINT_ICE() << "invalid address space for reference";
-        return false;
     }
 
     module_.PushType(spv::Op::OpTypePointer, {result, U32Operand(stg_class), Operand(subtype_id)});
@@ -4025,7 +3983,6 @@
             break;
     }
     TINT_UNREACHABLE() << "unhandled address space '" << address_space << "'";
-    return SpvStorageClassMax;
 }
 
 SpvBuiltIn Builder::ConvertBuiltin(core::BuiltinValue builtin, core::AddressSpace storage) {
@@ -4037,7 +3994,6 @@
                 return SpvBuiltInPosition;
             } else {
                 TINT_ICE() << "invalid address space for builtin";
-                break;
             }
         case core::BuiltinValue::kVertexIndex:
             return SpvBuiltInVertexIndex;
@@ -4110,7 +4066,6 @@
     switch (format) {
         case core::TexelFormat::kBgra8Unorm:
             TINT_ICE() << "bgra8unorm should have been polyfilled to rgba8unorm";
-            return SpvImageFormatUnknown;
         case core::TexelFormat::kR8Unorm:
             module_.PushCapability(SpvCapabilityStorageImageExtendedFormats);
             return SpvImageFormatR8;
@@ -4161,7 +4116,6 @@
         ss << "Internal error: trying to add SPIR-V instruction " << int(op)
            << " outside a function";
         TINT_ICE() << ss.str();
-        return false;
     }
     current_function_.push_inst(op, operands);
     return true;
diff --git a/src/tint/lang/spirv/writer/ast_printer/builtin_texture_test.cc b/src/tint/lang/spirv/writer/ast_printer/builtin_texture_test.cc
index cddad69..4e6f84b 100644
--- a/src/tint/lang/spirv/writer/ast_printer/builtin_texture_test.cc
+++ b/src/tint/lang/spirv/writer/ast_printer/builtin_texture_test.cc
@@ -26,7 +26,6 @@
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include "gmock/gmock.h"
-#include "gtest/gtest-spi.h"
 #include "src/tint/lang/spirv/writer/ast_printer/helper_test.h"
 #include "src/tint/lang/spirv/writer/common/spv_dump_test.h"
 #include "src/tint/lang/wgsl/ast/builtin_texture_helper_test.h"
@@ -3775,9 +3774,9 @@
     Validate(b);
 }
 
-// TODO(dsinclair): This generates two fatal errors, but expect_fatal_failure can only handle 1
+// TODO(dsinclair): This generates two fatal errors, but EXPECT_DEATH can only handle 1
 TEST_P(BuiltinTextureTest, DISABLED_OutsideFunction_IsError) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             auto param = GetParam();
 
diff --git a/src/tint/lang/spirv/writer/ast_printer/function_attribute_test.cc b/src/tint/lang/spirv/writer/ast_printer/function_attribute_test.cc
index 784aefe..27e9a6e 100644
--- a/src/tint/lang/spirv/writer/ast_printer/function_attribute_test.cc
+++ b/src/tint/lang/spirv/writer/ast_printer/function_attribute_test.cc
@@ -26,7 +26,6 @@
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include "gmock/gmock.h"
-#include "gtest/gtest-spi.h"
 #include "src/tint/lang/spirv/writer/ast_printer/helper_test.h"
 #include "src/tint/lang/spirv/writer/common/spv_dump_test.h"
 #include "src/tint/lang/wgsl/ast/stage_attribute.h"
@@ -166,7 +165,7 @@
 }
 
 TEST_F(SpirvASTPrinterTest, Decoration_ExecutionMode_WorkgroupSize_OverridableConst) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder pb;
             pb.Override("width", pb.ty.i32(), pb.Call<i32>(2_i), pb.Id(7_u));
@@ -186,7 +185,7 @@
 }
 
 TEST_F(SpirvASTPrinterTest, Decoration_ExecutionMode_WorkgroupSize_LiteralAndConst) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder pb;
 
diff --git a/src/tint/lang/spirv/writer/ast_printer/ident_expression_test.cc b/src/tint/lang/spirv/writer/ast_printer/ident_expression_test.cc
index aaf3023..e65e8c9 100644
--- a/src/tint/lang/spirv/writer/ast_printer/ident_expression_test.cc
+++ b/src/tint/lang/spirv/writer/ast_printer/ident_expression_test.cc
@@ -25,7 +25,6 @@
 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-#include "gtest/gtest-spi.h"
 #include "src/tint/lang/spirv/writer/ast_printer/helper_test.h"
 #include "src/tint/lang/spirv/writer/common/spv_dump_test.h"
 
@@ -38,7 +37,7 @@
 using SpirvASTPrinterTest = TestHelper;
 
 TEST_F(SpirvASTPrinterTest, IdentifierExpression_GlobalConst) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder pb;
 
diff --git a/src/tint/lang/spirv/writer/ast_raise/vectorize_matrix_conversions.cc b/src/tint/lang/spirv/writer/ast_raise/vectorize_matrix_conversions.cc
index 31505a0..16bf7a2 100644
--- a/src/tint/lang/spirv/writer/ast_raise/vectorize_matrix_conversions.cc
+++ b/src/tint/lang/spirv/writer/ast_raise/vectorize_matrix_conversions.cc
@@ -115,7 +115,6 @@
         if (TINT_UNLIKELY(!(src_type->rows() == dst_type->rows() &&
                             src_type->columns() == dst_type->columns()))) {
             TINT_ICE() << "source and destination matrix has different shape in matrix conversion";
-            return nullptr;
         }
 
         auto build_vectorized_conversion_expression = [&](auto&& src_expression_builder) {
diff --git a/src/tint/lang/spirv/writer/printer/printer.cc b/src/tint/lang/spirv/writer/printer/printer.cc
index c38f018..73066a6 100644
--- a/src/tint/lang/spirv/writer/printer/printer.cc
+++ b/src/tint/lang/spirv/writer/printer/printer.cc
@@ -764,7 +764,6 @@
             }
             case core::ir::Function::PipelineStage::kUndefined:
                 TINT_ICE() << "undefined pipeline stage for entry point";
-                return;
         }
 
         OperandList operands = {U32Operand(stage), id, ir_.NameOf(func).Name()};
@@ -1198,7 +1197,6 @@
             }
             default:
                 TINT_UNIMPLEMENTED() << binary->Op();
-                break;
         }
 
         // Emit the instruction.
@@ -1339,7 +1337,6 @@
                 break;
             case spirv::BuiltinFn::kNone:
                 TINT_ICE() << "undefined spirv ir function";
-                return;
         }
 
         OperandList operands;
@@ -1790,7 +1787,7 @@
                     one = b_.Constant(1_u);
                     zero = b_.Constant(0_u);
                 });
-            TINT_ASSERT_OR_RETURN(one && zero);
+            TINT_ASSERT(one && zero);
 
             if (auto* vec = res_ty->As<core::type::Vector>()) {
                 // Splat the scalars into vectors.
@@ -1976,7 +1973,6 @@
                 break;
             default:
                 TINT_UNIMPLEMENTED() << unary->Op();
-                break;
         }
         current_function_.push_inst(op, {Type(ty), id, Value(unary->Val())});
     }
@@ -2227,7 +2223,6 @@
         switch (format) {
             case core::TexelFormat::kBgra8Unorm:
                 TINT_ICE() << "bgra8unorm should have been polyfilled to rgba8unorm";
-                return SpvImageFormatUnknown;
             case core::TexelFormat::kR8Unorm:
                 module_.PushCapability(SpvCapabilityStorageImageExtendedFormats);
                 return SpvImageFormatR8;
diff --git a/src/tint/lang/spirv/writer/raise/builtin_polyfill.cc b/src/tint/lang/spirv/writer/raise/builtin_polyfill.cc
index 9af1437..b45beac 100644
--- a/src/tint/lang/spirv/writer/raise/builtin_polyfill.cc
+++ b/src/tint/lang/spirv/writer/raise/builtin_polyfill.cc
@@ -172,7 +172,7 @@
                 default:
                     break;
             }
-            TINT_ASSERT_OR_RETURN(replacement);
+            TINT_ASSERT(replacement);
 
             // Replace the old builtin result with the new value.
             if (auto name = ir.NameOf(builtin->Result(0))) {
@@ -199,13 +199,12 @@
         while (auto* let = tint::As<core::ir::Let>(ptr->Instruction())) {
             ptr = let->Value()->As<core::ir::InstructionResult>();
         }
-        TINT_ASSERT_OR_RETURN_VALUE(ptr, nullptr);
+        TINT_ASSERT(ptr);
 
         auto* access = ptr->Instruction()->As<core::ir::Access>();
-        TINT_ASSERT_OR_RETURN_VALUE(access, nullptr);
-        TINT_ASSERT_OR_RETURN_VALUE(access->Indices().Length() == 1u, nullptr);
-        TINT_ASSERT_OR_RETURN_VALUE(access->Object()->Type()->UnwrapPtr()->Is<core::type::Struct>(),
-                                    nullptr);
+        TINT_ASSERT(access);
+        TINT_ASSERT(access->Indices().Length() == 1u);
+        TINT_ASSERT(access->Object()->Type()->UnwrapPtr()->Is<core::type::Struct>());
         auto* const_idx = access->Indices()[0]->As<core::ir::Constant>();
 
         // Replace the builtin call with a call to the spirv.array_length intrinsic.
@@ -231,7 +230,6 @@
                     return b.Constant(u32(SpvScopeDevice));
                 default:
                     TINT_UNREACHABLE() << "unhandled atomic address space";
-                    return nullptr;
             }
         }();
         auto* memory_semantics = b.Constant(u32(SpvMemorySemanticsMaskNone));
diff --git a/src/tint/lang/spirv/writer/raise/handle_matrix_arithmetic.cc b/src/tint/lang/spirv/writer/raise/handle_matrix_arithmetic.cc
index 44237c9..487bac0 100644
--- a/src/tint/lang/spirv/writer/raise/handle_matrix_arithmetic.cc
+++ b/src/tint/lang/spirv/writer/raise/handle_matrix_arithmetic.cc
@@ -135,7 +135,6 @@
 
             default:
                 TINT_UNREACHABLE() << "unhandled matrix arithmetic instruction";
-                break;
         }
     }
 
diff --git a/src/tint/lang/spirv/writer/writer_bench.cc b/src/tint/lang/spirv/writer/writer_bench.cc
index fca650a..11a1c7a 100644
--- a/src/tint/lang/spirv/writer/writer_bench.cc
+++ b/src/tint/lang/spirv/writer/writer_bench.cc
@@ -34,6 +34,14 @@
 #include "src/tint/lang/wgsl/reader/reader.h"
 #endif  // TINT_BUILD_WGSL_READER
 
+#if TINT_BUILD_IS_MSVC
+#if _MSC_VER > 1930 && _MSC_VER < 1939
+#define BUGGY_COMPILER  // MSVC can ICE
+#endif
+#endif
+
+#ifndef BUGGY_COMPILER
+
 namespace tint::spirv::writer {
 namespace {
 
@@ -81,3 +89,5 @@
 
 }  // namespace
 }  // namespace tint::spirv::writer
+
+#endif
diff --git a/src/tint/lang/wgsl/BUILD.cmake b/src/tint/lang/wgsl/BUILD.cmake
index 2b40c72..704e42a 100644
--- a/src/tint/lang/wgsl/BUILD.cmake
+++ b/src/tint/lang/wgsl/BUILD.cmake
@@ -186,8 +186,6 @@
   tint_lang_wgsl_common
   tint_lang_wgsl_features
   tint_lang_wgsl_program
-  tint_lang_wgsl_reader_lower
-  tint_lang_wgsl_resolver
   tint_lang_wgsl_sem
   tint_lang_wgsl_writer_ir_to_program
   tint_lang_wgsl_writer_raise
@@ -209,7 +207,6 @@
 
 if(TINT_BUILD_WGSL_READER)
   tint_target_add_dependencies(tint_lang_wgsl_fuzz fuzz
-    tint_lang_wgsl_reader_parser
     tint_lang_wgsl_reader_program_to_ir
   )
 endif(TINT_BUILD_WGSL_READER)
diff --git a/src/tint/lang/wgsl/BUILD.gn b/src/tint/lang/wgsl/BUILD.gn
index c63b21c..d46ee4c 100644
--- a/src/tint/lang/wgsl/BUILD.gn
+++ b/src/tint/lang/wgsl/BUILD.gn
@@ -158,8 +158,6 @@
     "${tint_src_dir}/lang/wgsl/common",
     "${tint_src_dir}/lang/wgsl/features",
     "${tint_src_dir}/lang/wgsl/program",
-    "${tint_src_dir}/lang/wgsl/reader/lower",
-    "${tint_src_dir}/lang/wgsl/resolver",
     "${tint_src_dir}/lang/wgsl/sem",
     "${tint_src_dir}/lang/wgsl/writer/ir_to_program",
     "${tint_src_dir}/lang/wgsl/writer/raise",
@@ -180,10 +178,7 @@
   ]
 
   if (tint_build_wgsl_reader) {
-    deps += [
-      "${tint_src_dir}/lang/wgsl/reader/parser",
-      "${tint_src_dir}/lang/wgsl/reader/program_to_ir",
-    ]
+    deps += [ "${tint_src_dir}/lang/wgsl/reader/program_to_ir" ]
   }
 
   if (tint_build_wgsl_reader && tint_build_wgsl_writer) {
diff --git a/src/tint/lang/wgsl/ast/assignment_statement_test.cc b/src/tint/lang/wgsl/ast/assignment_statement_test.cc
index aa2a49c..6c51920 100644
--- a/src/tint/lang/wgsl/ast/assignment_statement_test.cc
+++ b/src/tint/lang/wgsl/ast/assignment_statement_test.cc
@@ -27,7 +27,6 @@
 
 #include "src/tint/lang/wgsl/ast/assignment_statement.h"
 
-#include "gtest/gtest-spi.h"
 #include "src/tint/lang/wgsl/ast/helper_test.h"
 
 using namespace tint::core::number_suffixes;  // NOLINT
@@ -65,7 +64,7 @@
 }
 
 TEST_F(AssignmentStatementTest, Assert_Null_LHS) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b;
             b.create<AssignmentStatement>(nullptr, b.Expr(1_i));
@@ -74,7 +73,7 @@
 }
 
 TEST_F(AssignmentStatementTest, Assert_Null_RHS) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b;
             b.create<AssignmentStatement>(b.Expr(1_i), nullptr);
@@ -83,7 +82,7 @@
 }
 
 TEST_F(AssignmentStatementTest, Assert_DifferentGenerationID_LHS) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b1;
             ProgramBuilder b2;
@@ -93,7 +92,7 @@
 }
 
 TEST_F(AssignmentStatementTest, Assert_DifferentGenerationID_RHS) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b1;
             ProgramBuilder b2;
diff --git a/src/tint/lang/wgsl/ast/binary_expression_test.cc b/src/tint/lang/wgsl/ast/binary_expression_test.cc
index f656eb5..34e6e58 100644
--- a/src/tint/lang/wgsl/ast/binary_expression_test.cc
+++ b/src/tint/lang/wgsl/ast/binary_expression_test.cc
@@ -25,7 +25,6 @@
 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-#include "gtest/gtest-spi.h"
 #include "src/tint/lang/wgsl/ast/helper_test.h"
 
 namespace tint::ast {
@@ -63,7 +62,7 @@
 }
 
 TEST_F(BinaryExpressionTest, Assert_Null_LHS) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b;
             b.create<BinaryExpression>(core::BinaryOp::kEqual, nullptr, b.Expr("rhs"));
@@ -72,7 +71,7 @@
 }
 
 TEST_F(BinaryExpressionTest, Assert_Null_RHS) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b;
             b.create<BinaryExpression>(core::BinaryOp::kEqual, b.Expr("lhs"), nullptr);
@@ -81,7 +80,7 @@
 }
 
 TEST_F(BinaryExpressionTest, Assert_DifferentGenerationID_LHS) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b1;
             ProgramBuilder b2;
@@ -91,7 +90,7 @@
 }
 
 TEST_F(BinaryExpressionTest, Assert_DifferentGenerationID_RHS) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b1;
             ProgramBuilder b2;
diff --git a/src/tint/lang/wgsl/ast/block_statement_test.cc b/src/tint/lang/wgsl/ast/block_statement_test.cc
index 0ad214f..6e00eaa 100644
--- a/src/tint/lang/wgsl/ast/block_statement_test.cc
+++ b/src/tint/lang/wgsl/ast/block_statement_test.cc
@@ -26,7 +26,6 @@
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include "gmock/gmock.h"
-#include "gtest/gtest-spi.h"
 #include "src/tint/lang/wgsl/ast/discard_statement.h"
 #include "src/tint/lang/wgsl/ast/helper_test.h"
 #include "src/tint/lang/wgsl/ast/if_statement.h"
@@ -73,7 +72,7 @@
 }
 
 TEST_F(BlockStatementTest, Assert_Null_Statement) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b;
             b.create<BlockStatement>(tint::Vector<const Statement*, 1>{nullptr}, tint::Empty);
@@ -82,7 +81,7 @@
 }
 
 TEST_F(BlockStatementTest, Assert_DifferentGenerationID_Statement) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b1;
             ProgramBuilder b2;
diff --git a/src/tint/lang/wgsl/ast/break_if_statement_test.cc b/src/tint/lang/wgsl/ast/break_if_statement_test.cc
index ee81f31..4c59976 100644
--- a/src/tint/lang/wgsl/ast/break_if_statement_test.cc
+++ b/src/tint/lang/wgsl/ast/break_if_statement_test.cc
@@ -27,7 +27,6 @@
 
 #include "src/tint/lang/wgsl/ast/break_if_statement.h"
 
-#include "gtest/gtest-spi.h"
 #include "src/tint/lang/wgsl/ast/helper_test.h"
 
 namespace tint::ast {
@@ -49,7 +48,7 @@
 }
 
 TEST_F(BreakIfStatementTest, Assert_Null_Condition) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b;
             b.BreakIf(nullptr);
@@ -58,7 +57,7 @@
 }
 
 TEST_F(BreakIfStatementTest, Assert_DifferentGenerationID_Cond) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b1;
             ProgramBuilder b2;
diff --git a/src/tint/lang/wgsl/ast/builtin_attribute_test.cc b/src/tint/lang/wgsl/ast/builtin_attribute_test.cc
index 9cd7779..4bd547b 100644
--- a/src/tint/lang/wgsl/ast/builtin_attribute_test.cc
+++ b/src/tint/lang/wgsl/ast/builtin_attribute_test.cc
@@ -25,8 +25,6 @@
 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-#include "gtest/gtest-spi.h"
-
 #include "src/tint/lang/core/builtin_value.h"
 #include "src/tint/lang/wgsl/ast/helper_test.h"
 
@@ -41,7 +39,7 @@
 }
 
 TEST_F(BuiltinAttributeTest, Assert_Null_Builtin) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b;
             b.Builtin(nullptr);
@@ -50,7 +48,7 @@
 }
 
 TEST_F(BuiltinAttributeTest, Assert_DifferentGenerationID_Builtin) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b1;
             ProgramBuilder b2;
diff --git a/src/tint/lang/wgsl/ast/builtin_texture_helper_test.cc b/src/tint/lang/wgsl/ast/builtin_texture_helper_test.cc
index bff2caf..1a716d0 100644
--- a/src/tint/lang/wgsl/ast/builtin_texture_helper_test.cc
+++ b/src/tint/lang/wgsl/ast/builtin_texture_helper_test.cc
@@ -166,7 +166,6 @@
     }
 
     TINT_UNREACHABLE();
-    return {};
 }
 
 const Variable* TextureOverloadCase::BuildTextureVariable(ProgramBuilder* b) const {
@@ -200,7 +199,6 @@
     }
 
     TINT_UNREACHABLE();
-    return nullptr;
 }
 
 const Variable* TextureOverloadCase::BuildSamplerVariable(ProgramBuilder* b) const {
diff --git a/src/tint/lang/wgsl/ast/call_expression_test.cc b/src/tint/lang/wgsl/ast/call_expression_test.cc
index 928d78f..7e6cab8 100644
--- a/src/tint/lang/wgsl/ast/call_expression_test.cc
+++ b/src/tint/lang/wgsl/ast/call_expression_test.cc
@@ -25,7 +25,6 @@
 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-#include "gtest/gtest-spi.h"
 #include "src/tint/lang/wgsl/ast/helper_test.h"
 
 namespace tint::ast {
@@ -92,7 +91,7 @@
 }
 
 TEST_F(CallExpressionTest, Assert_Null_Identifier) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b;
             b.Call(static_cast<Identifier*>(nullptr));
@@ -101,7 +100,7 @@
 }
 
 TEST_F(CallExpressionTest, Assert_Null_Param) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b;
             b.Call(b.Ident("func"), tint::Vector{
@@ -114,7 +113,7 @@
 }
 
 TEST_F(CallExpressionTest, Assert_DifferentGenerationID_Identifier) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b1;
             ProgramBuilder b2;
@@ -124,7 +123,7 @@
 }
 
 TEST_F(CallExpressionTest, Assert_DifferentGenerationID_Type) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b1;
             ProgramBuilder b2;
@@ -134,7 +133,7 @@
 }
 
 TEST_F(CallExpressionTest, Assert_DifferentGenerationID_Param) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b1;
             ProgramBuilder b2;
diff --git a/src/tint/lang/wgsl/ast/call_statement_test.cc b/src/tint/lang/wgsl/ast/call_statement_test.cc
index c22fec3..e9e8169 100644
--- a/src/tint/lang/wgsl/ast/call_statement_test.cc
+++ b/src/tint/lang/wgsl/ast/call_statement_test.cc
@@ -27,7 +27,6 @@
 
 #include "src/tint/lang/wgsl/ast/call_statement.h"
 
-#include "gtest/gtest-spi.h"
 #include "src/tint/lang/wgsl/ast/helper_test.h"
 
 namespace tint::ast {
@@ -48,7 +47,7 @@
 }
 
 TEST_F(CallStatementTest, Assert_Null_Call) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b;
             b.CallStmt(nullptr);
@@ -57,7 +56,7 @@
 }
 
 TEST_F(CallStatementTest, Assert_DifferentGenerationID_Call) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b1;
             ProgramBuilder b2;
diff --git a/src/tint/lang/wgsl/ast/case_selector_test.cc b/src/tint/lang/wgsl/ast/case_selector_test.cc
index da76c9b..043eee7 100644
--- a/src/tint/lang/wgsl/ast/case_selector_test.cc
+++ b/src/tint/lang/wgsl/ast/case_selector_test.cc
@@ -27,7 +27,6 @@
 
 #include "src/tint/lang/wgsl/ast/case_selector.h"
 
-#include "gtest/gtest-spi.h"
 #include "src/tint/lang/wgsl/ast/helper_test.h"
 
 using namespace tint::core::number_suffixes;  // NOLINT
diff --git a/src/tint/lang/wgsl/ast/case_statement_test.cc b/src/tint/lang/wgsl/ast/case_statement_test.cc
index a125371..60df861 100644
--- a/src/tint/lang/wgsl/ast/case_statement_test.cc
+++ b/src/tint/lang/wgsl/ast/case_statement_test.cc
@@ -27,7 +27,6 @@
 
 #include "src/tint/lang/wgsl/ast/case_statement.h"
 
-#include "gtest/gtest-spi.h"
 #include "src/tint/lang/wgsl/ast/discard_statement.h"
 #include "src/tint/lang/wgsl/ast/helper_test.h"
 #include "src/tint/lang/wgsl/ast/if_statement.h"
@@ -100,7 +99,7 @@
 }
 
 TEST_F(CaseStatementTest, Assert_Null_Body) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b;
             b.create<CaseStatement>(tint::Vector{b.DefaultCaseSelector()}, nullptr);
@@ -109,7 +108,7 @@
 }
 
 TEST_F(CaseStatementTest, Assert_Null_Selector) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b;
             b.create<CaseStatement>(tint::Vector<const ast::CaseSelector*, 1>{nullptr},
@@ -119,7 +118,7 @@
 }
 
 TEST_F(CaseStatementTest, Assert_DifferentGenerationID_Call) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b1;
             ProgramBuilder b2;
@@ -130,7 +129,7 @@
 }
 
 TEST_F(CaseStatementTest, Assert_DifferentGenerationID_Selector) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b1;
             ProgramBuilder b2;
diff --git a/src/tint/lang/wgsl/ast/clone_context.h b/src/tint/lang/wgsl/ast/clone_context.h
index 07d5de7..deb1012 100644
--- a/src/tint/lang/wgsl/ast/clone_context.h
+++ b/src/tint/lang/wgsl/ast/clone_context.h
@@ -317,7 +317,6 @@
         if (TINT_UNLIKELY(symbol_transform_)) {
             TINT_ICE() << "ReplaceAll(const SymbolTransform&) called multiple times on the same "
                           "CloneContext";
-            return *this;
         }
         symbol_transform_ = replacer;
         return *this;
@@ -568,16 +567,14 @@
             return cast;
         }
         CheckedCastFailure(obj, tint::TypeInfo::Of<TO>());
-        return nullptr;
     }
 
     /// Clones a Node object, using any replacements or transforms that have
     /// been configured.
     const ast::Node* CloneNode(const ast::Node* object);
 
-    /// Adds an error diagnostic to Diagnostics() that the cloned object was not
-    /// of the expected type.
-    void CheckedCastFailure(const ast::Node* got, const TypeInfo& expected);
+    /// Aborts with an ICE describing that the cloned object type was not as required.
+    [[noreturn]] void CheckedCastFailure(const ast::Node* got, const TypeInfo& expected);
 
     /// @returns the diagnostic list of #dst
     diag::List& Diagnostics() const;
diff --git a/src/tint/lang/wgsl/ast/clone_context_test.cc b/src/tint/lang/wgsl/ast/clone_context_test.cc
index 9152292..6bc1e6e 100644
--- a/src/tint/lang/wgsl/ast/clone_context_test.cc
+++ b/src/tint/lang/wgsl/ast/clone_context_test.cc
@@ -26,9 +26,10 @@
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include <string>
-#include <unordered_set>
 
-#include "gtest/gtest-spi.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
 #include "src/tint/lang/wgsl/ast/clone_context.h"
 #include "src/tint/lang/wgsl/program/program_builder.h"
 #include "src/tint/lang/wgsl/resolver/resolve.h"
@@ -1052,7 +1053,7 @@
 TEST_F(ASTCloneContextTestNodeTest, CloneWithReplaceAll_SameTypeTwice) {
     std::string Testnode_name = TypeInfo::Of<TestNode>().name;
 
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder cloned;
             Program original;
@@ -1060,15 +1061,16 @@
             ctx.ReplaceAll([](const TestNode*) { return nullptr; });
             ctx.ReplaceAll([](const TestNode*) { return nullptr; });
         },
-        "internal compiler error: ReplaceAll() called with a handler for type " + Testnode_name +
-            " that is already handled by a handler for type " + Testnode_name);
+        testing::HasSubstr("internal compiler error: ReplaceAll() called with a handler for type " +
+                           Testnode_name + " that is already handled by a handler for type " +
+                           Testnode_name));
 }
 
 TEST_F(ASTCloneContextTestNodeTest, CloneWithReplaceAll_BaseThenDerived) {
     std::string Testnode_name = TypeInfo::Of<TestNode>().name;
     std::string replaceable_name = TypeInfo::Of<Replaceable>().name;
 
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder cloned;
             Program original;
@@ -1076,15 +1078,16 @@
             ctx.ReplaceAll([](const TestNode*) { return nullptr; });
             ctx.ReplaceAll([](const Replaceable*) { return nullptr; });
         },
-        "internal compiler error: ReplaceAll() called with a handler for type " + replaceable_name +
-            " that is already handled by a handler for type " + Testnode_name);
+        testing::HasSubstr("internal compiler error: ReplaceAll() called with a handler for type " +
+                           replaceable_name + " that is already handled by a handler for type " +
+                           Testnode_name));
 }
 
 TEST_F(ASTCloneContextTestNodeTest, CloneWithReplaceAll_DerivedThenBase) {
     std::string Testnode_name = TypeInfo::Of<TestNode>().name;
     std::string replaceable_name = TypeInfo::Of<Replaceable>().name;
 
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder cloned;
             Program original;
@@ -1092,14 +1095,15 @@
             ctx.ReplaceAll([](const Replaceable*) { return nullptr; });
             ctx.ReplaceAll([](const TestNode*) { return nullptr; });
         },
-        "internal compiler error: ReplaceAll() called with a handler for type " + Testnode_name +
-            " that is already handled by a handler for type " + replaceable_name);
+        testing::HasSubstr("internal compiler error: ReplaceAll() called with a handler for type " +
+                           Testnode_name + " that is already handled by a handler for type " +
+                           replaceable_name));
 }
 
 using ASTCloneContextTest = ::testing::Test;
 
 TEST_F(ASTCloneContextTest, CloneWithReplaceAll_SymbolsTwice) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder cloned;
             Program original;
@@ -1107,8 +1111,8 @@
             ctx.ReplaceAll([](const Symbol s) { return s; });
             ctx.ReplaceAll([](const Symbol s) { return s; });
         },
-        "internal compiler error: ReplaceAll(const SymbolTransform&) called "
-        "multiple times on the same CloneContext");
+        testing::HasSubstr("internal compiler error: ReplaceAll(const SymbolTransform&) called "
+                           "multiple times on the same CloneContext"));
 }
 
 TEST_F(ASTCloneContextTest, CloneNewUnnamedSymbols) {
@@ -1177,7 +1181,7 @@
 }
 
 TEST_F(ASTCloneContextTest, GenerationIDs_Clone_ObjectNotOwnedBySrc) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder dst;
             Program src(ProgramBuilder{});
@@ -1185,11 +1189,12 @@
             Allocator allocator;
             ctx.Clone(allocator.Create<IDTestNode>(GenerationID::New(), dst.ID()));
         },
-        R"(internal compiler error: TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(src_id, object))");
+        testing::HasSubstr(
+            R"(internal compiler error: TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(src_id, object))"));
 }
 
 TEST_F(ASTCloneContextTest, GenerationIDs_Clone_ObjectNotOwnedByDst) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder dst;
             Program src(ProgramBuilder{});
@@ -1197,7 +1202,8 @@
             Allocator allocator;
             ctx.Clone(allocator.Create<IDTestNode>(src.ID(), GenerationID::New()));
         },
-        R"(internal compiler error: TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(dst, out))");
+        testing::HasSubstr(
+            R"(internal compiler error: TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(dst, out))"));
 }
 
 }  // namespace
diff --git a/src/tint/lang/wgsl/ast/color_attribute_test.cc b/src/tint/lang/wgsl/ast/color_attribute_test.cc
index 9afba5f..c8dd840 100644
--- a/src/tint/lang/wgsl/ast/color_attribute_test.cc
+++ b/src/tint/lang/wgsl/ast/color_attribute_test.cc
@@ -25,8 +25,6 @@
 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-#include "gtest/gtest-spi.h"
-
 #include "src/tint/lang/wgsl/ast/color_attribute.h"
 #include "src/tint/lang/wgsl/ast/helper_test.h"
 
@@ -44,7 +42,7 @@
 }
 
 TEST_F(ColorAttributeTest, Assert_Null_Builtin) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b;
             b.Color(nullptr);
@@ -53,7 +51,7 @@
 }
 
 TEST_F(ColorAttributeTest, Assert_DifferentGenerationID_Color) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b1;
             ProgramBuilder b2;
diff --git a/src/tint/lang/wgsl/ast/compound_assignment_statement_test.cc b/src/tint/lang/wgsl/ast/compound_assignment_statement_test.cc
index 5712767..36e302d 100644
--- a/src/tint/lang/wgsl/ast/compound_assignment_statement_test.cc
+++ b/src/tint/lang/wgsl/ast/compound_assignment_statement_test.cc
@@ -27,7 +27,6 @@
 
 #include "src/tint/lang/wgsl/ast/compound_assignment_statement.h"
 
-#include "gtest/gtest-spi.h"
 #include "src/tint/lang/wgsl/ast/helper_test.h"
 
 using namespace tint::core::number_suffixes;  // NOLINT
@@ -69,7 +68,7 @@
 }
 
 TEST_F(CompoundAssignmentStatementTest, Assert_Null_LHS) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b;
             b.create<CompoundAssignmentStatement>(nullptr, b.Expr(1_i), core::BinaryOp::kAdd);
@@ -78,7 +77,7 @@
 }
 
 TEST_F(CompoundAssignmentStatementTest, Assert_Null_RHS) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b;
             b.create<CompoundAssignmentStatement>(b.Expr(1_i), nullptr, core::BinaryOp::kAdd);
@@ -87,7 +86,7 @@
 }
 
 TEST_F(CompoundAssignmentStatementTest, Assert_DifferentGenerationID_LHS) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b1;
             ProgramBuilder b2;
@@ -98,7 +97,7 @@
 }
 
 TEST_F(CompoundAssignmentStatementTest, Assert_DifferentGenerationID_RHS) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b1;
             ProgramBuilder b2;
diff --git a/src/tint/lang/wgsl/ast/const_assert_test.cc b/src/tint/lang/wgsl/ast/const_assert_test.cc
index a0c7f27..70e9dfd 100644
--- a/src/tint/lang/wgsl/ast/const_assert_test.cc
+++ b/src/tint/lang/wgsl/ast/const_assert_test.cc
@@ -27,7 +27,6 @@
 
 #include "src/tint/lang/wgsl/ast/const_assert.h"
 
-#include "gtest/gtest-spi.h"
 #include "src/tint/lang/core/fluent_types.h"
 #include "src/tint/lang/wgsl/ast/helper_test.h"
 
@@ -60,7 +59,7 @@
 }
 
 TEST_F(ConstAssertTest, Assert_Null_Condition) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b;
             b.ConstAssert(nullptr);
@@ -69,7 +68,7 @@
 }
 
 TEST_F(ConstAssertTest, Assert_DifferentGenerationID_Condition) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b1;
             ProgramBuilder b2;
diff --git a/src/tint/lang/wgsl/ast/diagnostic_control_test.cc b/src/tint/lang/wgsl/ast/diagnostic_control_test.cc
index 7c28451..514b9ef 100644
--- a/src/tint/lang/wgsl/ast/diagnostic_control_test.cc
+++ b/src/tint/lang/wgsl/ast/diagnostic_control_test.cc
@@ -27,7 +27,6 @@
 
 #include <string>
 
-#include "gtest/gtest-spi.h"
 #include "src/tint/lang/wgsl/ast/diagnostic_control.h"
 #include "src/tint/lang/wgsl/ast/helper_test.h"
 #include "src/tint/lang/wgsl/diagnostic_severity.h"
@@ -38,7 +37,7 @@
 using DiagnosticControlTest = TestHelper;
 
 TEST_F(DiagnosticControlTest, Assert_RuleNotNull) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b;
             DiagnosticControl control(wgsl::DiagnosticSeverity::kWarning, nullptr);
diff --git a/src/tint/lang/wgsl/ast/diagnostic_rule_name_test.cc b/src/tint/lang/wgsl/ast/diagnostic_rule_name_test.cc
index a827d37..94ccc9c 100644
--- a/src/tint/lang/wgsl/ast/diagnostic_rule_name_test.cc
+++ b/src/tint/lang/wgsl/ast/diagnostic_rule_name_test.cc
@@ -27,7 +27,6 @@
 
 #include <string>
 
-#include "gtest/gtest-spi.h"
 #include "src/tint/lang/wgsl/ast/diagnostic_rule_name.h"
 #include "src/tint/lang/wgsl/ast/helper_test.h"
 
@@ -42,7 +41,7 @@
 }
 
 TEST_F(DiagnosticRuleNameTest, Assert_NameNotTemplated) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b;
             b.create<ast::DiagnosticRuleName>(b.Ident("name", "a", "b", "c"));
@@ -51,7 +50,7 @@
 }
 
 TEST_F(DiagnosticRuleNameTest, Assert_CategoryNotTemplated) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b;
             b.create<ast::DiagnosticRuleName>(b.Ident("name"), b.Ident("category", "a", "b", "c"));
diff --git a/src/tint/lang/wgsl/ast/for_loop_statement_test.cc b/src/tint/lang/wgsl/ast/for_loop_statement_test.cc
index fc3675e..a284597 100644
--- a/src/tint/lang/wgsl/ast/for_loop_statement_test.cc
+++ b/src/tint/lang/wgsl/ast/for_loop_statement_test.cc
@@ -26,7 +26,6 @@
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include "gmock/gmock.h"
-#include "gtest/gtest-spi.h"
 #include "src/tint/lang/wgsl/ast/binary_expression.h"
 #include "src/tint/lang/wgsl/ast/helper_test.h"
 
@@ -74,7 +73,7 @@
 }
 
 TEST_F(ForLoopStatementTest, Assert_Null_Body) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b;
             b.For(nullptr, nullptr, nullptr, nullptr);
@@ -83,7 +82,7 @@
 }
 
 TEST_F(ForLoopStatementTest, Assert_DifferentGenerationID_Initializer) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b1;
             ProgramBuilder b2;
@@ -93,7 +92,7 @@
 }
 
 TEST_F(ForLoopStatementTest, Assert_DifferentGenerationID_Condition) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b1;
             ProgramBuilder b2;
@@ -103,7 +102,7 @@
 }
 
 TEST_F(ForLoopStatementTest, Assert_DifferentGenerationID_Continuing) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b1;
             ProgramBuilder b2;
@@ -113,7 +112,7 @@
 }
 
 TEST_F(ForLoopStatementTest, Assert_DifferentGenerationID_Body) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b1;
             ProgramBuilder b2;
diff --git a/src/tint/lang/wgsl/ast/function_test.cc b/src/tint/lang/wgsl/ast/function_test.cc
index 7b658bc..96f7aa5 100644
--- a/src/tint/lang/wgsl/ast/function_test.cc
+++ b/src/tint/lang/wgsl/ast/function_test.cc
@@ -25,7 +25,6 @@
 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-#include "gtest/gtest-spi.h"
 #include "src/tint/lang/core/fluent_types.h"
 #include "src/tint/lang/wgsl/ast/discard_statement.h"
 #include "src/tint/lang/wgsl/ast/helper_test.h"
@@ -114,7 +113,7 @@
 }
 
 TEST_F(FunctionTest, Assert_NullName) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b;
             b.Func(static_cast<Identifier*>(nullptr), tint::Empty, b.ty.void_(), tint::Empty);
@@ -123,7 +122,7 @@
 }
 
 TEST_F(FunctionTest, Assert_TemplatedName) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b;
             b.Func(b.Ident("a", "b"), tint::Empty, b.ty.void_(), tint::Empty);
@@ -133,7 +132,7 @@
 
 TEST_F(FunctionTest, Assert_NullParam) {
     using ParamList = tint::Vector<const Parameter*, 2>;
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b;
             ParamList params;
@@ -145,7 +144,7 @@
 }
 
 TEST_F(FunctionTest, Assert_DifferentGenerationID_Symbol) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b1;
             ProgramBuilder b2;
@@ -155,7 +154,7 @@
 }
 
 TEST_F(FunctionTest, Assert_DifferentGenerationID_Param) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b1;
             ProgramBuilder b2;
@@ -169,7 +168,7 @@
 }
 
 TEST_F(FunctionTest, Assert_DifferentGenerationID_Attr) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b1;
             ProgramBuilder b2;
@@ -182,7 +181,7 @@
 }
 
 TEST_F(FunctionTest, Assert_DifferentGenerationID_ReturnType) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b1;
             ProgramBuilder b2;
@@ -192,7 +191,7 @@
 }
 
 TEST_F(FunctionTest, Assert_DifferentGenerationID_ReturnAttr) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b1;
             ProgramBuilder b2;
diff --git a/src/tint/lang/wgsl/ast/identifier_expression_test.cc b/src/tint/lang/wgsl/ast/identifier_expression_test.cc
index a044a85..ebf1916 100644
--- a/src/tint/lang/wgsl/ast/identifier_expression_test.cc
+++ b/src/tint/lang/wgsl/ast/identifier_expression_test.cc
@@ -25,7 +25,6 @@
 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-#include "gtest/gtest-spi.h"
 #include "src/tint/lang/wgsl/ast/helper_test.h"
 
 namespace tint::ast {
@@ -58,7 +57,7 @@
 }
 
 TEST_F(IdentifierExpressionTest, Assert_InvalidSymbol) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b;
             b.Expr("");
@@ -67,7 +66,7 @@
 }
 
 TEST_F(IdentifierExpressionTest, Assert_DifferentGenerationID_Symbol) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b1;
             ProgramBuilder b2;
diff --git a/src/tint/lang/wgsl/ast/identifier_test.cc b/src/tint/lang/wgsl/ast/identifier_test.cc
index 958f036..8f238e7 100644
--- a/src/tint/lang/wgsl/ast/identifier_test.cc
+++ b/src/tint/lang/wgsl/ast/identifier_test.cc
@@ -25,7 +25,6 @@
 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-#include "gtest/gtest-spi.h"
 #include "src/tint/lang/wgsl/ast/helper_test.h"
 
 namespace tint::ast {
@@ -53,7 +52,7 @@
 }
 
 TEST_F(IdentifierTest, Assert_InvalidSymbol) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b;
             b.Ident("");
@@ -62,7 +61,7 @@
 }
 
 TEST_F(IdentifierTest, Assert_DifferentGenerationID_Symbol) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b1;
             ProgramBuilder b2;
diff --git a/src/tint/lang/wgsl/ast/if_statement_test.cc b/src/tint/lang/wgsl/ast/if_statement_test.cc
index ffe28a4..4c738ad 100644
--- a/src/tint/lang/wgsl/ast/if_statement_test.cc
+++ b/src/tint/lang/wgsl/ast/if_statement_test.cc
@@ -28,7 +28,6 @@
 #include "src/tint/lang/wgsl/ast/if_statement.h"
 
 #include "gmock/gmock.h"
-#include "gtest/gtest-spi.h"
 #include "src/tint/lang/wgsl/ast/discard_statement.h"
 #include "src/tint/lang/wgsl/ast/helper_test.h"
 
@@ -60,7 +59,7 @@
 }
 
 TEST_F(IfStatementTest, Assert_Null_Condition) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b;
             b.If(nullptr, b.Block());
@@ -69,7 +68,7 @@
 }
 
 TEST_F(IfStatementTest, Assert_Null_Body) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b;
             b.If(b.Expr(true), nullptr);
@@ -78,7 +77,7 @@
 }
 
 TEST_F(IfStatementTest, Assert_InvalidElse) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b;
             b.If(b.Expr(true), b.Block(), b.Else(b.CallStmt(b.Call("foo"))));
@@ -87,7 +86,7 @@
 }
 
 TEST_F(IfStatementTest, Assert_DifferentGenerationID_Cond) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b1;
             ProgramBuilder b2;
@@ -97,7 +96,7 @@
 }
 
 TEST_F(IfStatementTest, Assert_DifferentGenerationID_Body) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b1;
             ProgramBuilder b2;
@@ -107,7 +106,7 @@
 }
 
 TEST_F(IfStatementTest, Assert_DifferentGenerationID_ElseStatement) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b1;
             ProgramBuilder b2;
diff --git a/src/tint/lang/wgsl/ast/increment_decrement_statement_test.cc b/src/tint/lang/wgsl/ast/increment_decrement_statement_test.cc
index c2924d0..869b522 100644
--- a/src/tint/lang/wgsl/ast/increment_decrement_statement_test.cc
+++ b/src/tint/lang/wgsl/ast/increment_decrement_statement_test.cc
@@ -27,7 +27,6 @@
 
 #include "src/tint/lang/wgsl/ast/increment_decrement_statement.h"
 
-#include "gtest/gtest-spi.h"
 #include "src/tint/lang/wgsl/ast/helper_test.h"
 
 namespace tint::ast {
@@ -67,7 +66,7 @@
 }
 
 TEST_F(IncrementDecrementStatementTest, Assert_DifferentGenerationID_Expr) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b1;
             ProgramBuilder b2;
diff --git a/src/tint/lang/wgsl/ast/index_accessor_expression_test.cc b/src/tint/lang/wgsl/ast/index_accessor_expression_test.cc
index 35d40ff..ff96f2a 100644
--- a/src/tint/lang/wgsl/ast/index_accessor_expression_test.cc
+++ b/src/tint/lang/wgsl/ast/index_accessor_expression_test.cc
@@ -25,7 +25,6 @@
 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-#include "gtest/gtest-spi.h"
 #include "src/tint/lang/wgsl/ast/helper_test.h"
 
 namespace tint::ast {
@@ -61,7 +60,7 @@
 }
 
 TEST_F(IndexAccessorExpressionTest, Assert_Null_Array) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b;
             b.IndexAccessor(nullptr, b.Expr("idx"));
@@ -70,7 +69,7 @@
 }
 
 TEST_F(IndexAccessorExpressionTest, Assert_Null_Index) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b;
             b.IndexAccessor(b.Expr("arr"), nullptr);
@@ -79,7 +78,7 @@
 }
 
 TEST_F(IndexAccessorExpressionTest, Assert_DifferentGenerationID_Array) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b1;
             ProgramBuilder b2;
@@ -89,7 +88,7 @@
 }
 
 TEST_F(IndexAccessorExpressionTest, Assert_DifferentGenerationID_Index) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b1;
             ProgramBuilder b2;
diff --git a/src/tint/lang/wgsl/ast/loop_statement_test.cc b/src/tint/lang/wgsl/ast/loop_statement_test.cc
index 1a52aae..fc43b31 100644
--- a/src/tint/lang/wgsl/ast/loop_statement_test.cc
+++ b/src/tint/lang/wgsl/ast/loop_statement_test.cc
@@ -28,7 +28,6 @@
 #include "src/tint/lang/wgsl/ast/loop_statement.h"
 
 #include "gmock/gmock.h"
-#include "gtest/gtest-spi.h"
 #include "src/tint/lang/wgsl/ast/discard_statement.h"
 #include "src/tint/lang/wgsl/ast/helper_test.h"
 #include "src/tint/lang/wgsl/ast/if_statement.h"
@@ -94,7 +93,7 @@
 }
 
 TEST_F(LoopStatementTest, Assert_Null_Body) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b;
             b.create<LoopStatement>(nullptr, nullptr, tint::Empty);
@@ -103,7 +102,7 @@
 }
 
 TEST_F(LoopStatementTest, Assert_DifferentGenerationID_Body) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b1;
             ProgramBuilder b2;
@@ -113,7 +112,7 @@
 }
 
 TEST_F(LoopStatementTest, Assert_DifferentGenerationID_Continuing) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b1;
             ProgramBuilder b2;
diff --git a/src/tint/lang/wgsl/ast/member_accessor_expression_test.cc b/src/tint/lang/wgsl/ast/member_accessor_expression_test.cc
index ce339cd..22b1c38 100644
--- a/src/tint/lang/wgsl/ast/member_accessor_expression_test.cc
+++ b/src/tint/lang/wgsl/ast/member_accessor_expression_test.cc
@@ -25,7 +25,6 @@
 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-#include "gtest/gtest-spi.h"
 #include "src/tint/lang/wgsl/ast/helper_test.h"
 
 namespace tint::ast {
@@ -56,7 +55,7 @@
 }
 
 TEST_F(MemberAccessorExpressionTest, Assert_Null_Struct) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b;
             b.create<MemberAccessorExpression>(nullptr, b.Ident("member"));
@@ -65,7 +64,7 @@
 }
 
 TEST_F(MemberAccessorExpressionTest, Assert_Null_Member) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b;
             b.create<MemberAccessorExpression>(b.Expr("struct"), nullptr);
@@ -74,7 +73,7 @@
 }
 
 TEST_F(MemberAccessorExpressionTest, Assert_DifferentGenerationID_Struct) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b1;
             ProgramBuilder b2;
@@ -84,7 +83,7 @@
 }
 
 TEST_F(MemberAccessorExpressionTest, Assert_DifferentGenerationID_Member) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b1;
             ProgramBuilder b2;
@@ -94,7 +93,7 @@
 }
 
 TEST_F(MemberAccessorExpressionTest, Assert_MemberNotTemplated) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b;
             b.create<MemberAccessorExpression>(b.Expr("structure"),
diff --git a/src/tint/lang/wgsl/ast/module.cc b/src/tint/lang/wgsl/ast/module.cc
index 974abad..269bdc0 100644
--- a/src/tint/lang/wgsl/ast/module.cc
+++ b/src/tint/lang/wgsl/ast/module.cc
@@ -178,7 +178,6 @@
     for (auto* decl : global_declarations_) {
         if (TINT_UNLIKELY(!decl)) {
             TINT_ICE() << "src global declaration was nullptr";
-            continue;
         }
         BinGlobalDeclaration(decl);
     }
diff --git a/src/tint/lang/wgsl/ast/module_test.cc b/src/tint/lang/wgsl/ast/module_test.cc
index 8e5f629..e5949a6 100644
--- a/src/tint/lang/wgsl/ast/module_test.cc
+++ b/src/tint/lang/wgsl/ast/module_test.cc
@@ -26,7 +26,6 @@
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include "gmock/gmock.h"
-#include "gtest/gtest-spi.h"
 #include "src/tint/lang/wgsl/ast/helper_test.h"
 #include "src/tint/lang/wgsl/program/clone_context.h"
 #include "src/tint/lang/wgsl/resolver/resolve.h"
@@ -53,7 +52,7 @@
 }
 
 TEST_F(ModuleTest, Assert_Null_GlobalVariable) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder builder;
             builder.AST().AddGlobalVariable(nullptr);
@@ -62,7 +61,7 @@
 }
 
 TEST_F(ModuleTest, Assert_Null_TypeDecl) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder builder;
             builder.AST().AddTypeDecl(nullptr);
@@ -71,7 +70,7 @@
 }
 
 TEST_F(ModuleTest, Assert_DifferentGenerationID_Function) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b1;
             ProgramBuilder b2;
@@ -82,7 +81,7 @@
 }
 
 TEST_F(ModuleTest, Assert_DifferentGenerationID_GlobalVariable) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b1;
             ProgramBuilder b2;
@@ -92,7 +91,7 @@
 }
 
 TEST_F(ModuleTest, Assert_Null_Function) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder builder;
             builder.AST().AddFunction(nullptr);
diff --git a/src/tint/lang/wgsl/ast/return_statement_test.cc b/src/tint/lang/wgsl/ast/return_statement_test.cc
index 6cd1818..ed7c9e0 100644
--- a/src/tint/lang/wgsl/ast/return_statement_test.cc
+++ b/src/tint/lang/wgsl/ast/return_statement_test.cc
@@ -27,7 +27,6 @@
 
 #include "src/tint/lang/wgsl/ast/return_statement.h"
 
-#include "gtest/gtest-spi.h"
 #include "src/tint/lang/wgsl/ast/helper_test.h"
 
 namespace tint::ast {
@@ -66,7 +65,7 @@
 }
 
 TEST_F(ReturnStatementTest, Assert_DifferentGenerationID_Expr) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b1;
             ProgramBuilder b2;
diff --git a/src/tint/lang/wgsl/ast/struct_member_test.cc b/src/tint/lang/wgsl/ast/struct_member_test.cc
index 99341cc..c1e429b 100644
--- a/src/tint/lang/wgsl/ast/struct_member_test.cc
+++ b/src/tint/lang/wgsl/ast/struct_member_test.cc
@@ -25,7 +25,6 @@
 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-#include "gtest/gtest-spi.h"
 #include "src/tint/lang/wgsl/ast/helper_test.h"
 
 namespace tint::ast {
@@ -59,7 +58,7 @@
 }
 
 TEST_F(StructMemberTest, Assert_Null_Name) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b;
             b.Member(static_cast<Identifier*>(nullptr), b.ty.i32());
@@ -68,7 +67,7 @@
 }
 
 TEST_F(StructMemberTest, Assert_Null_Type) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b;
             b.Member("a", Type{});
@@ -77,7 +76,7 @@
 }
 
 TEST_F(StructMemberTest, Assert_Null_Attribute) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b;
             b.Member("a", b.ty.i32(), tint::Vector{b.MemberSize(4_a), nullptr});
@@ -86,7 +85,7 @@
 }
 
 TEST_F(StructMemberTest, Assert_DifferentGenerationID_Symbol) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b1;
             ProgramBuilder b2;
@@ -96,7 +95,7 @@
 }
 
 TEST_F(StructMemberTest, Assert_DifferentGenerationID_Attribute) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b1;
             ProgramBuilder b2;
diff --git a/src/tint/lang/wgsl/ast/struct_test.cc b/src/tint/lang/wgsl/ast/struct_test.cc
index b4b7081..d0e78de 100644
--- a/src/tint/lang/wgsl/ast/struct_test.cc
+++ b/src/tint/lang/wgsl/ast/struct_test.cc
@@ -26,7 +26,6 @@
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include "src/tint/lang/wgsl/ast/struct.h"
-#include "gtest/gtest-spi.h"
 #include "src/tint/lang/wgsl/ast/alias.h"
 #include "src/tint/lang/wgsl/ast/helper_test.h"
 #include "src/tint/lang/wgsl/ast/transform/add_block_attribute.h"
@@ -82,7 +81,7 @@
 }
 
 TEST_F(AstStructTest, Assert_Null_StructMember) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b;
             b.Structure(b.Sym("S"), tint::Vector{b.Member("a", b.ty.i32()), nullptr}, tint::Empty);
@@ -91,7 +90,7 @@
 }
 
 TEST_F(AstStructTest, Assert_Null_Attribute) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b;
             b.Structure(b.Sym("S"), tint::Vector{b.Member("a", b.ty.i32())},
@@ -101,7 +100,7 @@
 }
 
 TEST_F(AstStructTest, Assert_DifferentGenerationID_StructMember) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b1;
             ProgramBuilder b2;
@@ -111,7 +110,7 @@
 }
 
 TEST_F(AstStructTest, Assert_DifferentGenerationID_Attribute) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b1;
             ProgramBuilder b2;
diff --git a/src/tint/lang/wgsl/ast/switch_statement_test.cc b/src/tint/lang/wgsl/ast/switch_statement_test.cc
index 2cafb1c..fa1fc40 100644
--- a/src/tint/lang/wgsl/ast/switch_statement_test.cc
+++ b/src/tint/lang/wgsl/ast/switch_statement_test.cc
@@ -28,7 +28,6 @@
 #include "src/tint/lang/wgsl/ast/switch_statement.h"
 
 #include "gmock/gmock.h"
-#include "gtest/gtest-spi.h"
 #include "src/tint/lang/wgsl/ast/helper_test.h"
 
 using namespace tint::core::number_suffixes;  // NOLINT
@@ -89,7 +88,7 @@
 
 TEST_F(SwitchStatementTest, Assert_Null_Condition) {
     using CaseStatementList = tint::Vector<const CaseStatement*, 2>;
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b;
             CaseStatementList cases;
@@ -102,7 +101,7 @@
 
 TEST_F(SwitchStatementTest, Assert_Null_CaseStatement) {
     using CaseStatementList = tint::Vector<const CaseStatement*, 2>;
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b;
             b.create<SwitchStatement>(b.Expr(true), CaseStatementList{nullptr}, tint::Empty,
@@ -112,7 +111,7 @@
 }
 
 TEST_F(SwitchStatementTest, Assert_DifferentGenerationID_Condition) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b1;
             ProgramBuilder b2;
@@ -130,7 +129,7 @@
 }
 
 TEST_F(SwitchStatementTest, Assert_DifferentGenerationID_CaseStatement) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b1;
             ProgramBuilder b2;
diff --git a/src/tint/lang/wgsl/ast/templated_identifier_test.cc b/src/tint/lang/wgsl/ast/templated_identifier_test.cc
index e09edf4..ded0e81 100644
--- a/src/tint/lang/wgsl/ast/templated_identifier_test.cc
+++ b/src/tint/lang/wgsl/ast/templated_identifier_test.cc
@@ -25,8 +25,6 @@
 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-#include "gtest/gtest-spi.h"
-
 #include "src/tint/lang/wgsl/ast/helper_test.h"
 
 namespace tint::ast {
@@ -65,7 +63,7 @@
 }
 
 TEST_F(TemplatedIdentifierTest, Assert_InvalidSymbol) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b;
             b.Expr("");
@@ -74,7 +72,7 @@
 }
 
 TEST_F(TemplatedIdentifierTest, Assert_DifferentGenerationID_Symbol) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b1;
             ProgramBuilder b2;
@@ -84,7 +82,7 @@
 }
 
 TEST_F(TemplatedIdentifierTest, Assert_DifferentGenerationID_TemplateArg) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b1;
             ProgramBuilder b2;
diff --git a/src/tint/lang/wgsl/ast/transform/array_length_from_uniform.cc b/src/tint/lang/wgsl/ast/transform/array_length_from_uniform.cc
index 40c7fc2..c95cec9 100644
--- a/src/tint/lang/wgsl/ast/transform/array_length_from_uniform.cc
+++ b/src/tint/lang/wgsl/ast/transform/array_length_from_uniform.cc
@@ -171,7 +171,6 @@
                                     return sem.Get(unary->expr);  // Follow the object
                                 default:
                                     TINT_ICE() << "unexpected unary op: " << unary->op;
-                                    return nullptr;
                             }
                         },
                         TINT_ICE_ON_NO_MATCH);
@@ -197,7 +196,7 @@
     /// the Config::bindpoint_to_size_index map.
     const ast::Expression* ArrayLengthOf(const sem::GlobalVariable* global) {
         auto binding = global->Attributes().binding_point;
-        TINT_ASSERT_OR_RETURN_VALUE(binding, nullptr);
+        TINT_ASSERT(binding);
 
         auto idx_it = cfg->bindpoint_to_size_index.find(*binding);
         if (idx_it == cfg->bindpoint_to_size_index.end()) {
@@ -224,7 +223,6 @@
         if (TINT_UNLIKELY(global->Type()->Is<core::type::Pointer>())) {
             TINT_ICE() << "storage buffer variable should not be a pointer. "
                           "These should have been removed by the SimplifyPointers transform";
-            return nullptr;
         }
         auto* storage_buffer_type = global->Type()->UnwrapRef();
         const core::type::Array* array_type = nullptr;
@@ -239,7 +237,6 @@
         } else {
             TINT_ICE() << "expected form of arrayLength argument to be &array_var or "
                           "&struct_var.array_member";
-            return nullptr;
         }
         return b.Div(total_size, u32(array_type->Stride()));
     }
diff --git a/src/tint/lang/wgsl/ast/transform/builtin_polyfill.cc b/src/tint/lang/wgsl/ast/transform/builtin_polyfill.cc
index 640af4d..3bb5320 100644
--- a/src/tint/lang/wgsl/ast/transform/builtin_polyfill.cc
+++ b/src/tint/lang/wgsl/ast/transform/builtin_polyfill.cc
@@ -200,7 +200,6 @@
             }
             default:
                 TINT_ICE() << "unhandled polyfill level: " << static_cast<int>(cfg.builtins.acosh);
-                return {};
         }
 
         b.Func(name, tint::Vector{b.Param("x", T(ty))}, T(ty), body);
@@ -252,7 +251,6 @@
                 break;
             default:
                 TINT_ICE() << "unhandled polyfill level: " << static_cast<int>(cfg.builtins.acosh);
-                return {};
         }
 
         b.Func(name, tint::Vector{b.Param("x", T(ty))}, T(ty), body);
@@ -442,7 +440,6 @@
             default:
                 TINT_ICE() << "unhandled polyfill level: "
                            << static_cast<int>(cfg.builtins.extract_bits);
-                return {};
         }
 
         b.Func(name,
@@ -620,7 +617,6 @@
             TINT_ICE()
                 << "insertBits polyfill only support i32, u32, and vector of i32 or u32, got "
                 << ty->FriendlyName();
-            return {};
         }
 
         constexpr uint32_t W = 32u;  // 32-bit
@@ -701,7 +697,6 @@
             default:
                 TINT_ICE() << "unhandled polyfill level: "
                            << static_cast<int>(cfg.builtins.insert_bits);
-                return {};
         }
 
         b.Func(name,
diff --git a/src/tint/lang/wgsl/ast/transform/canonicalize_entry_point_io.cc b/src/tint/lang/wgsl/ast/transform/canonicalize_entry_point_io.cc
index 206a8d3..2bf58ec 100644
--- a/src/tint/lang/wgsl/ast/transform/canonicalize_entry_point_io.cc
+++ b/src/tint/lang/wgsl/ast/transform/canonicalize_entry_point_io.cc
@@ -103,7 +103,6 @@
             break;
     }
     TINT_UNREACHABLE();
-    return 0;
 }
 
 // Returns true if `attr` is a shader IO attribute.
@@ -224,7 +223,6 @@
             return ctx.src->Sem().Get(attr)->Value();
         }
         TINT_ICE() << "could not obtain builtin value from attribute";
-        return core::BuiltinValue::kUndefined;
     }
 
     /// @param attrs the input attribute list
@@ -496,7 +494,6 @@
         for (auto* member : str->Members()) {
             if (TINT_UNLIKELY(member->Type()->Is<core::type::Struct>())) {
                 TINT_ICE() << "nested IO struct";
-                continue;
             }
 
             if (auto* wave_intrinsic_call = CallWaveIntrinsic(member->Declaration()->attributes)) {
@@ -530,7 +527,6 @@
             for (auto* member : str->Members()) {
                 if (TINT_UNLIKELY(member->Type()->Is<core::type::Struct>())) {
                     TINT_ICE() << "nested IO struct";
-                    continue;
                 }
 
                 auto name = member->Name().Name();
diff --git a/src/tint/lang/wgsl/ast/transform/direct_variable_access.cc b/src/tint/lang/wgsl/ast/transform/direct_variable_access.cc
index 44fc79b..dac33c7 100644
--- a/src/tint/lang/wgsl/ast/transform/direct_variable_access.cc
+++ b/src/tint/lang/wgsl/ast/transform/direct_variable_access.cc
@@ -1110,7 +1110,6 @@
             }
 
             TINT_ICE() << "unhandled variant for access chain";
-            break;
         }
         return ss.str();
     }
@@ -1158,7 +1157,6 @@
         }
 
         TINT_ICE() << "unhandled variant type for access chain";
-        return nullptr;
     }
 
     /// @returns a new Symbol starting with @p symbol concatenated with @p suffix, and possibly an
diff --git a/src/tint/lang/wgsl/ast/transform/get_insertion_point_test.cc b/src/tint/lang/wgsl/ast/transform/get_insertion_point_test.cc
index ae22228..4c20059 100644
--- a/src/tint/lang/wgsl/ast/transform/get_insertion_point_test.cc
+++ b/src/tint/lang/wgsl/ast/transform/get_insertion_point_test.cc
@@ -27,7 +27,6 @@
 
 #include <utility>
 
-#include "gtest/gtest-spi.h"
 #include "src/tint/lang/wgsl/ast/transform/get_insertion_point.h"
 #include "src/tint/lang/wgsl/ast/transform/helper_test.h"
 #include "src/tint/lang/wgsl/program/clone_context.h"
diff --git a/src/tint/lang/wgsl/ast/transform/hoist_to_decl_before_test.cc b/src/tint/lang/wgsl/ast/transform/hoist_to_decl_before_test.cc
index 129275a..36f03a9 100644
--- a/src/tint/lang/wgsl/ast/transform/hoist_to_decl_before_test.cc
+++ b/src/tint/lang/wgsl/ast/transform/hoist_to_decl_before_test.cc
@@ -27,7 +27,6 @@
 
 #include <utility>
 
-#include "gtest/gtest-spi.h"
 #include "src/tint/lang/core/fluent_types.h"
 #include "src/tint/lang/wgsl/ast/transform/helper_test.h"
 #include "src/tint/lang/wgsl/ast/transform/hoist_to_decl_before.h"
diff --git a/src/tint/lang/wgsl/ast/transform/robustness.cc b/src/tint/lang/wgsl/ast/transform/robustness.cc
index fa00dc9..671c697 100644
--- a/src/tint/lang/wgsl/ast/transform/robustness.cc
+++ b/src/tint/lang/wgsl/ast/transform/robustness.cc
@@ -650,7 +650,6 @@
                 break;
         }
         TINT_UNREACHABLE() << "unhandled address space" << address_space;
-        return Action::kDefault;
     }
 
     /// @returns the vector width of @p ty, or 1 if @p ty is not a vector
diff --git a/src/tint/lang/wgsl/ast/transform/std140.cc b/src/tint/lang/wgsl/ast/transform/std140.cc
index 42fb0f9..7307b6d 100644
--- a/src/tint/lang/wgsl/ast/transform/std140.cc
+++ b/src/tint/lang/wgsl/ast/transform/std140.cc
@@ -436,7 +436,6 @@
                         //   this method only handles types transitively used as uniform buffers.
                         // * Runtime-sized arrays cannot be used in uniform buffers.
                         TINT_ICE() << "unexpected non-constant array count";
-                        count = 1;
                     }
                     return b.ty.array(std140, b.Expr(u32(count.value())), std::move(attrs));
                 }
@@ -527,7 +526,6 @@
                     }
                     TINT_ICE() << "unexpected variable found walking access chain: "
                                << user->Variable()->Declaration()->name->symbol.Name();
-                    return Action::kError;
                 },
                 [&](const sem::StructMemberAccess* a) {
                     // Is this a std140 decomposed matrix?
@@ -583,15 +581,13 @@
                                           default:
                                               TINT_ICE() << "unhandled unary op for access chain: "
                                                          << u->op;
-                                              return Action::kError;
                                       }
                                   });
                 },
-                [&](Default) {
+                [&](Default) -> Action {
                     TINT_ICE() << "unhandled expression type for access chain\n"
                                << "AST: " << expr->Declaration()->TypeInfo().name << "\n"
                                << "SEM: " << expr->TypeInfo().name;
-                    return Action::kError;
                 });
 
             switch (action) {
@@ -636,7 +632,6 @@
                     //   this method only handles types transitively used as uniform buffers.
                     // * Runtime-sized arrays cannot be used in uniform buffers.
                     TINT_ICE() << "unexpected non-constant array count";
-                    count = 1;
                 }
                 return "arr" + std::to_string(count.value()) + "_" + ConvertSuffix(arr->ElemType());
             },
@@ -738,7 +733,6 @@
                         //   this method only handles types transitively used as uniform buffers.
                         // * Runtime-sized arrays cannot be used in uniform buffers.
                         TINT_ICE() << "unexpected non-constant array count";
-                        count = 1;
                     }
                     stmts.Push(b.Decl(var));
                     stmts.Push(b.For(b.Decl(i),                          //
diff --git a/src/tint/lang/wgsl/ast/transform/transform.cc b/src/tint/lang/wgsl/ast/transform/transform.cc
index d5ea76f..9d9a22a 100644
--- a/src/tint/lang/wgsl/ast/transform/transform.cc
+++ b/src/tint/lang/wgsl/ast/transform/transform.cc
@@ -145,7 +145,6 @@
         auto count = a->ConstantCount();
         if (TINT_UNLIKELY(!count)) {
             TINT_ICE() << core::type::Array::kErrExpectedConstantCount;
-            return ctx.dst->ty.array(el, u32(1), std::move(attrs));
         }
         return ctx.dst->ty.array(el, u32(count.value()), std::move(attrs));
     }
@@ -188,7 +187,6 @@
         return ctx.dst->ty.ptr(address_space, CreateASTTypeFor(ctx, p->StoreType()), access);
     }
     TINT_UNREACHABLE() << "Unhandled type: " << ty->TypeInfo().name;
-    return Type{};
 }
 
 }  // namespace tint::ast::transform
diff --git a/src/tint/lang/wgsl/ast/transform/vectorize_scalar_matrix_initializers.cc b/src/tint/lang/wgsl/ast/transform/vectorize_scalar_matrix_initializers.cc
index e75deaa..bef4c62 100644
--- a/src/tint/lang/wgsl/ast/transform/vectorize_scalar_matrix_initializers.cc
+++ b/src/tint/lang/wgsl/ast/transform/vectorize_scalar_matrix_initializers.cc
@@ -151,7 +151,6 @@
         }
 
         TINT_ICE() << "matrix initializer has unexpected number of arguments";
-        return nullptr;
     });
 
     ctx.Clone();
diff --git a/src/tint/lang/wgsl/ast/transform/vertex_pulling.cc b/src/tint/lang/wgsl/ast/transform/vertex_pulling.cc
index 4c2145d..3e34b10 100644
--- a/src/tint/lang/wgsl/ast/transform/vertex_pulling.cc
+++ b/src/tint/lang/wgsl/ast/transform/vertex_pulling.cc
@@ -437,7 +437,6 @@
                             break;
                         default:
                             TINT_UNREACHABLE() << var_dt.width;
-                            return nullptr;
                     }
                 } else if (var_dt.width > fmt_dt.width) {
                     // WGSL variable vector width is wider than the loaded vector width, do padding.
@@ -688,7 +687,6 @@
         }
 
         TINT_UNREACHABLE() << "format " << static_cast<int>(format);
-        return nullptr;
     }
 
     /// Generates an expression reading an aligned basic type (u32, i32, f32) from
@@ -741,7 +739,6 @@
                 break;
         }
         TINT_UNREACHABLE() << "invalid format for LoadPrimitive" << static_cast<int>(format);
-        return nullptr;
     }
 
     /// Generates an expression reading a vec2/3/4 from a vertex buffer.
@@ -791,14 +788,12 @@
 
             if (TINT_UNLIKELY(!sem->Attributes().location.has_value())) {
                 TINT_ICE() << "Location missing value";
-                return;
             }
             location_info[sem->Attributes().location.value()] = info;
         } else {
             auto* builtin_attr = GetAttribute<BuiltinAttribute>(param->attributes);
             if (TINT_UNLIKELY(!builtin_attr)) {
                 TINT_ICE() << "Invalid entry point parameter";
-                return;
             }
             auto builtin = src.Sem().Get(builtin_attr)->Value();
             // Check for existing vertex_index and instance_index builtins.
@@ -852,7 +847,6 @@
                 auto* builtin_attr = GetAttribute<BuiltinAttribute>(member->attributes);
                 if (TINT_UNLIKELY(!builtin_attr)) {
                     TINT_ICE() << "Invalid entry point parameter";
-                    return;
                 }
                 auto builtin = src.Sem().Get(builtin_attr)->Value();
                 // Check for existing vertex_index and instance_index builtins.
diff --git a/src/tint/lang/wgsl/ast/transform/zero_init_workgroup_memory.cc b/src/tint/lang/wgsl/ast/transform/zero_init_workgroup_memory.cc
index 8807cb4..0dbbc5b 100644
--- a/src/tint/lang/wgsl/ast/transform/zero_init_workgroup_memory.cc
+++ b/src/tint/lang/wgsl/ast/transform/zero_init_workgroup_memory.cc
@@ -405,7 +405,6 @@
         }
 
         TINT_UNREACHABLE() << "could not zero workgroup type: " << ty->FriendlyName();
-        return false;
     }
 
     /// DeclareArrayIndices returns a list of statements that contain the `let`
diff --git a/src/tint/lang/wgsl/ast/unary_op_expression_test.cc b/src/tint/lang/wgsl/ast/unary_op_expression_test.cc
index aaf13df..3ce46c9 100644
--- a/src/tint/lang/wgsl/ast/unary_op_expression_test.cc
+++ b/src/tint/lang/wgsl/ast/unary_op_expression_test.cc
@@ -27,7 +27,6 @@
 
 #include "src/tint/lang/wgsl/ast/unary_op_expression.h"
 
-#include "gtest/gtest-spi.h"
 #include "src/tint/lang/wgsl/ast/helper_test.h"
 
 namespace tint::ast {
@@ -59,7 +58,7 @@
 }
 
 TEST_F(UnaryOpExpressionTest, Assert_Null_Expression) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b;
             b.create<UnaryOpExpression>(core::UnaryOp::kNot, nullptr);
@@ -68,7 +67,7 @@
 }
 
 TEST_F(UnaryOpExpressionTest, Assert_DifferentGenerationID_Expression) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b1;
             ProgramBuilder b2;
diff --git a/src/tint/lang/wgsl/ast/variable_decl_statement_test.cc b/src/tint/lang/wgsl/ast/variable_decl_statement_test.cc
index c3b7467..1e3588d 100644
--- a/src/tint/lang/wgsl/ast/variable_decl_statement_test.cc
+++ b/src/tint/lang/wgsl/ast/variable_decl_statement_test.cc
@@ -27,7 +27,6 @@
 
 #include "src/tint/lang/wgsl/ast/variable_decl_statement.h"
 
-#include "gtest/gtest-spi.h"
 #include "src/tint/lang/wgsl/ast/helper_test.h"
 
 namespace tint::ast {
@@ -59,7 +58,7 @@
 }
 
 TEST_F(VariableDeclStatementTest, Assert_Null_Variable) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b;
             b.create<VariableDeclStatement>(nullptr);
@@ -68,7 +67,7 @@
 }
 
 TEST_F(VariableDeclStatementTest, Assert_DifferentGenerationID_Variable) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b1;
             ProgramBuilder b2;
diff --git a/src/tint/lang/wgsl/ast/variable_test.cc b/src/tint/lang/wgsl/ast/variable_test.cc
index 6b5443b..c85ec93 100644
--- a/src/tint/lang/wgsl/ast/variable_test.cc
+++ b/src/tint/lang/wgsl/ast/variable_test.cc
@@ -25,8 +25,6 @@
 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-#include "gtest/gtest-spi.h"
-
 #include "src/tint/lang/core/builtin_value.h"
 #include "src/tint/lang/wgsl/ast/helper_test.h"
 #include "src/tint/lang/wgsl/ast/id_attribute.h"
@@ -78,7 +76,7 @@
 }
 
 TEST_F(VariableTest, Assert_Null_Name) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b;
             b.Var(static_cast<Identifier*>(nullptr), b.ty.i32());
@@ -87,7 +85,7 @@
 }
 
 TEST_F(VariableTest, Assert_DifferentGenerationID_Symbol) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b1;
             ProgramBuilder b2;
@@ -97,7 +95,7 @@
 }
 
 TEST_F(VariableTest, Assert_DifferentGenerationID_Initializer) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b1;
             ProgramBuilder b2;
diff --git a/src/tint/lang/wgsl/ast/while_statement_test.cc b/src/tint/lang/wgsl/ast/while_statement_test.cc
index c87da67..e678d12 100644
--- a/src/tint/lang/wgsl/ast/while_statement_test.cc
+++ b/src/tint/lang/wgsl/ast/while_statement_test.cc
@@ -26,7 +26,6 @@
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include "gmock/gmock.h"
-#include "gtest/gtest-spi.h"
 #include "src/tint/lang/wgsl/ast/binary_expression.h"
 #include "src/tint/lang/wgsl/ast/helper_test.h"
 
@@ -66,7 +65,7 @@
 }
 
 TEST_F(WhileStatementTest, Assert_Null_Cond) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b;
             auto* body = b.Block();
@@ -76,7 +75,7 @@
 }
 
 TEST_F(WhileStatementTest, Assert_Null_Body) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b;
             auto* cond =
@@ -87,7 +86,7 @@
 }
 
 TEST_F(WhileStatementTest, Assert_DifferentGenerationID_Condition) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b1;
             ProgramBuilder b2;
@@ -97,7 +96,7 @@
 }
 
 TEST_F(WhileStatementTest, Assert_DifferentGenerationID_Body) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b1;
             ProgramBuilder b2;
diff --git a/src/tint/lang/wgsl/diagnostic_rule_test.cc b/src/tint/lang/wgsl/diagnostic_rule_test.cc
index 85eccfe..472e5a8 100644
--- a/src/tint/lang/wgsl/diagnostic_rule_test.cc
+++ b/src/tint/lang/wgsl/diagnostic_rule_test.cc
@@ -36,7 +36,8 @@
 
 #include <string>
 
-#include "gtest/gtest-spi.h"
+#include "gtest/gtest.h"
+
 #include "src/tint/lang/wgsl/diagnostic_rule.h"
 #include "src/tint/utils/text/string.h"
 
diff --git a/src/tint/lang/wgsl/diagnostic_rule_test.cc.tmpl b/src/tint/lang/wgsl/diagnostic_rule_test.cc.tmpl
index d34cd75..47793d1 100644
--- a/src/tint/lang/wgsl/diagnostic_rule_test.cc.tmpl
+++ b/src/tint/lang/wgsl/diagnostic_rule_test.cc.tmpl
@@ -13,7 +13,8 @@
 
 #include <string>
 
-#include "gtest/gtest-spi.h"
+#include "gtest/gtest.h"
+
 #include "src/tint/lang/wgsl/diagnostic_rule.h"
 #include "src/tint/utils/text/string.h"
 
diff --git a/src/tint/lang/wgsl/diagnostic_severity_test.cc b/src/tint/lang/wgsl/diagnostic_severity_test.cc
index 88e2b7a..024b477 100644
--- a/src/tint/lang/wgsl/diagnostic_severity_test.cc
+++ b/src/tint/lang/wgsl/diagnostic_severity_test.cc
@@ -36,7 +36,8 @@
 
 #include <string>
 
-#include "gtest/gtest-spi.h"
+#include "gtest/gtest.h"
+
 #include "src/tint/lang/wgsl/diagnostic_severity.h"
 #include "src/tint/utils/text/string.h"
 
diff --git a/src/tint/lang/wgsl/diagnostic_severity_test.cc.tmpl b/src/tint/lang/wgsl/diagnostic_severity_test.cc.tmpl
index 48a7542..f8a29aa 100644
--- a/src/tint/lang/wgsl/diagnostic_severity_test.cc.tmpl
+++ b/src/tint/lang/wgsl/diagnostic_severity_test.cc.tmpl
@@ -13,7 +13,8 @@
 
 #include <string>
 
-#include "gtest/gtest-spi.h"
+#include "gtest/gtest.h"
+
 #include "src/tint/lang/wgsl/diagnostic_severity.h"
 #include "src/tint/utils/text/string.h"
 
diff --git a/src/tint/lang/wgsl/helpers/append_vector.cc b/src/tint/lang/wgsl/helpers/append_vector.cc
index f0bce9b..dab1506 100644
--- a/src/tint/lang/wgsl/helpers/append_vector.cc
+++ b/src/tint/lang/wgsl/helpers/append_vector.cc
@@ -72,7 +72,6 @@
         expr = b.Expr(false);
     } else {
         TINT_UNREACHABLE() << "unsupported vector element type: " << ty->TypeInfo().name;
-        return nullptr;
     }
     auto* sem = b.create<sem::ValueExpression>(expr, ty, core::EvaluationStage::kRuntime, stmt,
                                                /* constant_value */ nullptr,
diff --git a/src/tint/lang/wgsl/inspector/inspector.cc b/src/tint/lang/wgsl/inspector/inspector.cc
index 34700c8..d98ada7 100644
--- a/src/tint/lang/wgsl/inspector/inspector.cc
+++ b/src/tint/lang/wgsl/inspector/inspector.cc
@@ -119,8 +119,6 @@
             }
             default: {
                 TINT_UNREACHABLE() << "unhandled composition type";
-                compositionType = CompositionType::kUnknown;
-                break;
             }
         }
     } else {
@@ -170,7 +168,6 @@
         default: {
             TINT_UNREACHABLE() << "invalid pipeline stage for entry point '" << entry_point.name
                                << "'";
-            break;
         }
     }
 
diff --git a/src/tint/lang/wgsl/ir_roundtrip_fuzz.cc b/src/tint/lang/wgsl/ir_roundtrip_fuzz.cc
index 47af44a..0dfc83d 100644
--- a/src/tint/lang/wgsl/ir_roundtrip_fuzz.cc
+++ b/src/tint/lang/wgsl/ir_roundtrip_fuzz.cc
@@ -31,8 +31,6 @@
 
 #include "src/tint/cmd/fuzz/ir/fuzz.h"
 #include "src/tint/lang/core/ir/disassembly.h"
-#include "src/tint/lang/wgsl/reader/lower/lower.h"
-#include "src/tint/lang/wgsl/reader/parser/parser.h"
 #include "src/tint/lang/wgsl/reader/program_to_ir/program_to_ir.h"
 #include "src/tint/lang/wgsl/writer/ir_to_program/ir_to_program.h"
 #include "src/tint/lang/wgsl/writer/raise/raise.h"
@@ -43,7 +41,6 @@
 void IRRoundtripFuzzer(core::ir::Module& ir) {
     if (auto res = tint::wgsl::writer::Raise(ir); res != Success) {
         TINT_ICE() << res.Failure();
-        return;
     }
 
     writer::ProgramOptions program_options;
@@ -55,7 +52,6 @@
             std::cerr << "WGSL:\n" << result->wgsl << std::endl << std::endl;
         }
         TINT_ICE() << dst.Diagnostics();
-        return;
     }
 
     return;
diff --git a/src/tint/lang/wgsl/program/clone_context_test.cc b/src/tint/lang/wgsl/program/clone_context_test.cc
index 829a910..936cb6b 100644
--- a/src/tint/lang/wgsl/program/clone_context_test.cc
+++ b/src/tint/lang/wgsl/program/clone_context_test.cc
@@ -26,10 +26,11 @@
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include <string>
-#include <unordered_set>
 #include <utility>
 
-#include "gtest/gtest-spi.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
 #include "src/tint/lang/wgsl/program/clone_context.h"
 #include "src/tint/lang/wgsl/program/program_builder.h"
 #include "src/tint/lang/wgsl/resolver/resolve.h"
@@ -1050,7 +1051,7 @@
 TEST_F(ProgramCloneContextNodeTest, CloneWithReplaceAll_SameTypeTwice) {
     std::string node_name = TypeInfo::Of<Node>().name;
 
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder cloned;
             Program original;
@@ -1058,15 +1059,16 @@
             ctx.ReplaceAll([](const Node*) { return nullptr; });
             ctx.ReplaceAll([](const Node*) { return nullptr; });
         },
-        "internal compiler error: ReplaceAll() called with a handler for type " + node_name +
-            " that is already handled by a handler for type " + node_name);
+        testing::HasSubstr("internal compiler error: ReplaceAll() called with a handler for type " +
+                           node_name + " that is already handled by a handler for type " +
+                           node_name));
 }
 
 TEST_F(ProgramCloneContextNodeTest, CloneWithReplaceAll_BaseThenDerived) {
     std::string node_name = TypeInfo::Of<Node>().name;
     std::string replaceable_name = TypeInfo::Of<Replaceable>().name;
 
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder cloned;
             Program original;
@@ -1074,15 +1076,16 @@
             ctx.ReplaceAll([](const Node*) { return nullptr; });
             ctx.ReplaceAll([](const Replaceable*) { return nullptr; });
         },
-        "internal compiler error: ReplaceAll() called with a handler for type " + replaceable_name +
-            " that is already handled by a handler for type " + node_name);
+        testing::HasSubstr("internal compiler error: ReplaceAll() called with a handler for type " +
+                           replaceable_name + " that is already handled by a handler for type " +
+                           node_name));
 }
 
 TEST_F(ProgramCloneContextNodeTest, CloneWithReplaceAll_DerivedThenBase) {
     std::string node_name = TypeInfo::Of<Node>().name;
     std::string replaceable_name = TypeInfo::Of<Replaceable>().name;
 
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder cloned;
             Program original;
@@ -1090,14 +1093,15 @@
             ctx.ReplaceAll([](const Replaceable*) { return nullptr; });
             ctx.ReplaceAll([](const Node*) { return nullptr; });
         },
-        "internal compiler error: ReplaceAll() called with a handler for type " + node_name +
-            " that is already handled by a handler for type " + replaceable_name);
+        testing::HasSubstr("internal compiler error: ReplaceAll() called with a handler for type " +
+                           node_name + " that is already handled by a handler for type " +
+                           replaceable_name));
 }
 
 using ProgramCloneContextTest = ::testing::Test;
 
 TEST_F(ProgramCloneContextTest, CloneWithReplaceAll_SymbolsTwice) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder cloned;
             Program original;
@@ -1105,8 +1109,8 @@
             ctx.ReplaceAll([](const Symbol s) { return s; });
             ctx.ReplaceAll([](const Symbol s) { return s; });
         },
-        "internal compiler error: ReplaceAll(const SymbolTransform&) called "
-        "multiple times on the same CloneContext");
+        testing::HasSubstr("internal compiler error: ReplaceAll(const SymbolTransform&) called "
+                           "multiple times on the same CloneContext"));
 }
 
 TEST_F(ProgramCloneContextTest, CloneNewUnnamedSymbols) {
@@ -1203,7 +1207,7 @@
 }
 
 TEST_F(ProgramCloneContextTest, GenerationIDs_Clone_ObjectNotOwnedBySrc) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder dst;
             Program src(ProgramBuilder{});
@@ -1211,11 +1215,12 @@
             Allocator allocator;
             ctx.Clone(allocator.Create<IDNode>(GenerationID::New(), dst.ID()));
         },
-        R"(internal compiler error: TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(src_id, object))");
+        testing::HasSubstr(
+            R"(internal compiler error: TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(src_id, object))"));
 }
 
 TEST_F(ProgramCloneContextTest, GenerationIDs_Clone_ObjectNotOwnedByDst) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder dst;
             Program src(ProgramBuilder{});
@@ -1223,7 +1228,8 @@
             Allocator allocator;
             ctx.Clone(allocator.Create<IDNode>(src.ID(), GenerationID::New()));
         },
-        R"(internal compiler error: TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(dst, out))");
+        testing::HasSubstr(
+            R"(internal compiler error: TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(dst, out))"));
 }
 
 }  // namespace
diff --git a/src/tint/lang/wgsl/program/program_test.cc b/src/tint/lang/wgsl/program/program_test.cc
index d5f2bb3..dff5b23 100644
--- a/src/tint/lang/wgsl/program/program_test.cc
+++ b/src/tint/lang/wgsl/program/program_test.cc
@@ -25,7 +25,6 @@
 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-#include "gtest/gtest-spi.h"
 #include "src/tint/lang/wgsl/ast/helper_test.h"
 #include "src/tint/lang/wgsl/ast/return_statement.h"
 
@@ -66,7 +65,7 @@
 }
 
 TEST_F(ProgramTest, Assert_NullGlobalVariable) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b;
             b.AST().AddGlobalVariable(nullptr);
@@ -75,7 +74,7 @@
 }
 
 TEST_F(ProgramTest, Assert_NullTypeDecl) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b;
             b.AST().AddTypeDecl(nullptr);
@@ -84,7 +83,7 @@
 }
 
 TEST_F(ProgramTest, Assert_Null_Function) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b;
             b.AST().AddFunction(nullptr);
diff --git a/src/tint/lang/wgsl/reader/lower/lower.cc b/src/tint/lang/wgsl/reader/lower/lower.cc
index 94f2bac..0752652 100644
--- a/src/tint/lang/wgsl/reader/lower/lower.cc
+++ b/src/tint/lang/wgsl/reader/lower/lower.cc
@@ -175,7 +175,6 @@
             break;
     }
     TINT_ICE() << "unhandled builtin function: " << fn;
-    return core::BuiltinFn::kNone;
 }
 
 }  // namespace
diff --git a/src/tint/lang/wgsl/reader/program_to_ir/program_to_ir.cc b/src/tint/lang/wgsl/reader/program_to_ir/program_to_ir.cc
index 9933ed1..34d17d7 100644
--- a/src/tint/lang/wgsl/reader/program_to_ir/program_to_ir.cc
+++ b/src/tint/lang/wgsl/reader/program_to_ir/program_to_ir.cc
@@ -318,7 +318,6 @@
                 }
                 default: {
                     TINT_ICE() << "Invalid pipeline stage";
-                    return;
                 }
             }
 
@@ -340,7 +339,6 @@
                             ir_func->SetReturnBuiltin(ident_sem->Value());
                         } else {
                             TINT_ICE() << "Builtin attribute sem invalid";
-                            return;
                         }
                     });
             }
@@ -376,7 +374,6 @@
                             param->SetBuiltin(ident_sem->Value());
                         } else {
                             TINT_ICE() << "Builtin attribute sem invalid";
-                            return;
                         }
                     });
 
@@ -852,7 +849,6 @@
                     return *val;
                 }
                 TINT_ICE() << "expression did not resolve to a value";
-                return nullptr;
             }
 
             void PushBlock(core::ir::Block* block) {
@@ -884,7 +880,6 @@
                 auto* obj = GetValue(expr->object);
                 if (!obj) {
                     TINT_UNREACHABLE() << "no object result";
-                    return;
                 }
 
                 auto* sem = impl.program_.Sem().Get(expr)->Unwrap();
@@ -906,7 +901,6 @@
                                 return impl.builder_.Constant(cv);
                             }
                             TINT_UNREACHABLE() << "constant clone failed";
-                            return nullptr;
                         }
                         return GetValue(idx->Index()->Declaration());
                     },
@@ -1053,7 +1047,6 @@
                     inst = impl.builder_.Convert(ty, args[0]);
                 } else if (expr->target->identifier->Is<ast::TemplatedIdentifier>()) {
                     TINT_UNIMPLEMENTED() << "missing templated ident support";
-                    return;
                 } else {
                     // Not a builtin and not a templated call, so this is a user function.
                     inst = impl.builder_.Call(ty,
@@ -1164,7 +1157,7 @@
                 auto res = GetValue(b);
                 auto* src = res->As<core::ir::InstructionResult>()->Instruction();
                 auto* if_ = src->As<core::ir::If>();
-                TINT_ASSERT_OR_RETURN(if_);
+                TINT_ASSERT(if_);
                 auto rhs = GetValue(b->rhs);
                 if (!rhs) {
                     return;
@@ -1229,7 +1222,6 @@
             return *val;
         }
         TINT_ICE() << "expression did not resolve to a value";
-        return nullptr;
     }
 
     void EmitCall(const ast::CallStatement* stmt) { (void)EmitValueExpression(stmt->expr); }
@@ -1333,10 +1325,8 @@
             case core::BinaryOp::kLogicalAnd:
             case core::BinaryOp::kLogicalOr:
                 TINT_ICE() << "short circuit op should have already been handled";
-                return nullptr;
         }
         TINT_UNREACHABLE();
-        return nullptr;
     }
 };
 
diff --git a/src/tint/lang/wgsl/resolver/alias_analysis_test.cc b/src/tint/lang/wgsl/resolver/alias_analysis_test.cc
index e7bd78f..e545670 100644
--- a/src/tint/lang/wgsl/resolver/alias_analysis_test.cc
+++ b/src/tint/lang/wgsl/resolver/alias_analysis_test.cc
@@ -1012,7 +1012,6 @@
                 return CallStmt(Call(fn, ptr, 10_a, 42_a));
             default:
                 TINT_UNIMPLEMENTED() << fn;
-                return nullptr;
         }
     }
 
diff --git a/src/tint/lang/wgsl/resolver/attribute_validation_test.cc b/src/tint/lang/wgsl/resolver/attribute_validation_test.cc
index 0554f9a..e94ebbe 100644
--- a/src/tint/lang/wgsl/resolver/attribute_validation_test.cc
+++ b/src/tint/lang/wgsl/resolver/attribute_validation_test.cc
@@ -113,7 +113,6 @@
             return o << "@workgroup_size";
     }
     TINT_UNREACHABLE();
-    return o << "<unknown>";
 }
 
 static bool IsBindingAttribute(AttributeKind kind) {
@@ -254,7 +253,6 @@
             return builder.create<ast::WorkgroupAttribute>(source, builder.Expr(1_i));
     }
     TINT_UNREACHABLE() << kind;
-    return nullptr;
 }
 
 struct TestWithParams : ResolverTestWithParam<TestParams> {
diff --git a/src/tint/lang/wgsl/resolver/dependency_graph.cc b/src/tint/lang/wgsl/resolver/dependency_graph.cc
index 36f97ba..4838cde 100644
--- a/src/tint/lang/wgsl/resolver/dependency_graph.cc
+++ b/src/tint/lang/wgsl/resolver/dependency_graph.cc
@@ -760,7 +760,6 @@
         }
         TINT_ICE() << "failed to find dependency info for edge: '" << NameOf(from->node) << "' -> '"
                    << NameOf(to->node) << "'";
-        return {};
     }
 
     /// CyclicDependencyFound() emits an error diagnostic for a cyclic dependency.
@@ -907,7 +906,6 @@
     }
 
     TINT_UNREACHABLE() << "unhandled ResolvedIdentifier";
-    return "<unknown>";
 }
 
 }  // namespace tint::resolver
diff --git a/src/tint/lang/wgsl/resolver/incomplete_type.cc b/src/tint/lang/wgsl/resolver/incomplete_type.cc
index 47e2e67..72113d6 100644
--- a/src/tint/lang/wgsl/resolver/incomplete_type.cc
+++ b/src/tint/lang/wgsl/resolver/incomplete_type.cc
@@ -51,7 +51,6 @@
 
 core::type::Type* IncompleteType::Clone(core::type::CloneContext&) const {
     TINT_ICE() << "IncompleteType does not support cloning";
-    return nullptr;
 }
 
 bool IncompleteType::Equals(const core::type::UniqueNode& other) const {
diff --git a/src/tint/lang/wgsl/resolver/resolver.cc b/src/tint/lang/wgsl/resolver/resolver.cc
index fad6159..a400979 100644
--- a/src/tint/lang/wgsl/resolver/resolver.cc
+++ b/src/tint/lang/wgsl/resolver/resolver.cc
@@ -118,6 +118,9 @@
 namespace tint::resolver {
 namespace {
 
+/// ICE() is a wrapper around TINT_ICE() that includes a prefixed source location
+#define ICE(SOURCE) TINT_ICE() << SOURCE << (SOURCE.file ? ": " : "")
+
 using CtorConvIntrinsic = wgsl::intrinsic::CtorConv;
 using OverloadFlag = core::intrinsic::OverloadFlag;
 
@@ -160,8 +163,7 @@
     bool result = ResolveInternal();
 
     if (TINT_UNLIKELY(!result && !diagnostics_.ContainsErrors())) {
-        AddICE("resolving failed, but no error was raised", {});
-        return false;
+        TINT_ICE() << "resolving failed, but no error was raised";
     }
 
     if (!validator_.Enables(b.AST().Enables())) {
@@ -230,11 +232,9 @@
     bool result = true;
     for (auto* node : b.ASTNodes().Objects()) {
         if (TINT_UNLIKELY(!marked_[node->node_id.value])) {
-            StringStream err;
-            err << "AST node '" << node->TypeInfo().name << "' was not reached by the resolver\n"
-                << "Pointer: " << node;
-            AddICE(err.str(), node->source);
-            result = false;
+            ICE(node->source) << "AST node '" << node->TypeInfo().name
+                              << "' was not reached by the resolver\n"
+                              << "Pointer: " << node;
         }
     }
 
@@ -929,10 +929,9 @@
     for (auto& it : dependencies_.shadows) {
         CastableBase* shadowed = sem_.Get(it.value);
         if (TINT_UNLIKELY(!shadowed)) {
-            StringStream err;
-            err << "AST node '" << it.value->TypeInfo().name << "' had no semantic info\n"
-                << "Pointer: " << it.value;
-            AddICE(err.str(), it.value->source);
+            ICE(it.value->source) << "AST node '" << it.value->TypeInfo().name
+                                  << "' had no semantic info\n"
+                                  << "Pointer: " << it.value;
         }
 
         Switch(
@@ -1187,9 +1186,8 @@
     if (decl->body) {
         Mark(decl->body);
         if (TINT_UNLIKELY(current_compound_statement_)) {
-            AddICE("Resolver::Function() called with a current compound statement",
-                   decl->body->source);
-            return nullptr;
+            ICE(decl->body->source)
+                << "Resolver::Function() called with a current compound statement";
         }
         auto* body = StatementScope(decl->body, b.create<sem::FunctionBlockStatement>(func),
                                     [&] { return Statements(decl->body->statements); });
@@ -1594,8 +1592,7 @@
         }
     }
 
-    AddICE("Expression() did not find root node", root->source);
-    return nullptr;
+    ICE(root->source) << "Expression() did not find root node";
 }
 
 sem::ValueExpression* Resolver::ValueExpression(const ast::Expression* expr) {
@@ -1901,11 +1898,8 @@
     if (!skip_const_eval_.Contains(decl)) {
         auto expr_val = expr->ConstantValue();
         if (TINT_UNLIKELY(!expr_val)) {
-            StringStream err;
-            err << decl->source << "Materialize(" << decl->TypeInfo().name
-                << ") called on expression with no constant value";
-            AddICE(err.str(), expr->Declaration()->source);
-            return nullptr;
+            ICE(decl->source) << "Materialize(" << decl->TypeInfo().name
+                              << ") called on expression with no constant value";
         }
 
         auto val = const_eval_.Convert(concrete_ty, expr_val, decl->source);
@@ -1915,11 +1909,8 @@
         }
         materialized_val = val.Get();
         if (TINT_UNLIKELY(!materialized_val)) {
-            StringStream err;
-            err << decl->source << "ConvertValue(" << expr_val->Type()->FriendlyName() << " -> "
-                << concrete_ty->FriendlyName() << ") returned invalid value";
-            AddICE(err.str(), expr->Declaration()->source);
-            return nullptr;
+            ICE(decl->source) << "ConvertValue(" << expr_val->Type()->FriendlyName() << " -> "
+                              << concrete_ty->FriendlyName() << ") returned invalid value";
         }
     }
 
@@ -2319,7 +2310,6 @@
             }
             default: {
                 TINT_ICE() << "unhandled IncompleteType builtin: " << t->builtin;
-                return nullptr;
             }
         }
     };
@@ -2722,11 +2712,7 @@
             break;
     }
 
-    auto name = ident->symbol.NameView();
-    StringStream err;
-    err << " unhandled builtin type '" << name << "'";
-    AddICE(err.str(), ident->source);
-    return nullptr;
+    ICE(ident->source) << " unhandled builtin type '" << ident->symbol.NameView() << "'";
 }
 
 core::type::AbstractFloat* Resolver::AF() {
@@ -3059,8 +3045,7 @@
     const auto& signature = builtin->Signature();
     int texture_index = signature.IndexOf(core::ParameterUsage::kTexture);
     if (TINT_UNLIKELY(texture_index == -1)) {
-        AddICE("texture builtin without texture parameter", {});
-        return;
+        TINT_ICE() << "texture builtin without texture parameter";
     }
     if (auto* user =
             args[static_cast<size_t>(texture_index)]->UnwrapLoad()->As<sem::VariableUser>()) {
@@ -3192,7 +3177,6 @@
                     return b.create<core::type::U32>();
             }
             TINT_UNREACHABLE() << "Unhandled integer literal suffix: " << i->suffix;
-            return nullptr;
         },
         [&](const ast::FloatLiteralExpression* f) -> core::type::Type* {
             switch (f->suffix) {
@@ -3205,7 +3189,6 @@
                                                                        : nullptr;
             }
             TINT_UNREACHABLE() << "Unhandled float literal suffix: " << f->suffix;
-            return nullptr;
         },
         [&](const ast::BoolLiteralExpression*) { return b.create<core::type::Bool>(); },  //
         TINT_ICE_ON_NO_MATCH);
@@ -3256,10 +3239,7 @@
 
     auto resolved = dependencies_.resolved_identifiers.Get(ident);
     if (!resolved) {
-        StringStream err;
-        err << "identifier '" << ident->symbol.NameView() << "' was not resolved";
-        AddICE(err.str(), expr->source);
-        return nullptr;
+        ICE(expr->source) << "identifier '" << ident->symbol.NameView() << "' was not resolved";
     }
 
     if (auto* ast_node = resolved->Node()) {
@@ -3415,7 +3395,6 @@
     }
 
     TINT_UNREACHABLE() << "unhandled resolved identifier: " << resolved->String();
-    return nullptr;
 }
 
 sem::ValueExpression* Resolver::MemberAccessor(const ast::MemberAccessorExpression* expr) {
@@ -4536,8 +4515,7 @@
         return nullptr;
     }
     if (TINT_UNLIKELY(struct_align > std::numeric_limits<uint32_t>::max())) {
-        AddICE("calculated struct stride exceeds uint32", str->source);
-        return nullptr;
+        ICE(str->source) << "calculated struct stride exceeds uint32";
     }
 
     auto* out = b.create<sem::Struct>(
@@ -5001,20 +4979,16 @@
 
 bool Resolver::Mark(const ast::Node* node) {
     if (TINT_UNLIKELY(node == nullptr)) {
-        AddICE("Resolver::Mark() called with nullptr", {});
-        return false;
+        TINT_ICE() << "Resolver::Mark() called with nullptr";
     }
     auto marked_bit_ref = marked_[node->node_id.value];
     if (TINT_LIKELY(!marked_bit_ref)) {
         marked_bit_ref = true;
         return true;
     }
-    StringStream err;
-    err << "AST node '" << node->TypeInfo().name
-        << "' was encountered twice in the same AST of a Program\n"
-        << "Pointer: " << node;
-    AddICE(err.str(), node->source);
-    return false;
+    ICE(node->source) << "AST node '" << node->TypeInfo().name
+                      << "' was encountered twice in the same AST of a Program\n"
+                      << "Pointer: " << node;
 }
 
 template <typename NODE>
@@ -5042,18 +5016,6 @@
     AddError(attr->source) << style::Attribute("@", attr->Name()) << " is not valid for " << use;
 }
 
-void Resolver::AddICE(std::string_view msg, const Source& source) const {
-    if (source.file) {
-        TINT_ICE() << source << ": " << msg;
-    } else {
-        TINT_ICE() << msg;
-    }
-    diag::Diagnostic err{};
-    err.severity = diag::Severity::Error;
-    err.source = source;
-    diagnostics_.Add(std::move(err)) << msg;
-}
-
 diag::Diagnostic& Resolver::AddError(const Source& source) const {
     return diagnostics_.AddError(source);
 }
diff --git a/src/tint/lang/wgsl/resolver/resolver.h b/src/tint/lang/wgsl/resolver/resolver.h
index 5dcab43..715d62a 100644
--- a/src/tint/lang/wgsl/resolver/resolver.h
+++ b/src/tint/lang/wgsl/resolver/resolver.h
@@ -638,9 +638,6 @@
     /// @param use the thing that the attribute was applied to
     void ErrorInvalidAttribute(const ast::Attribute* attr, StyledText use);
 
-    /// Adds the given internal compiler error message to the diagnostics
-    void AddICE(std::string_view msg, const Source& source) const;
-
     /// @returns a new error message added to the program's diagnostics
     diag::Diagnostic& AddError(const Source& source) const;
 
diff --git a/src/tint/lang/wgsl/resolver/resolver_test.cc b/src/tint/lang/wgsl/resolver/resolver_test.cc
index 58c6f8f..152cbbe 100644
--- a/src/tint/lang/wgsl/resolver/resolver_test.cc
+++ b/src/tint/lang/wgsl/resolver/resolver_test.cc
@@ -30,7 +30,6 @@
 #include <tuple>
 
 #include "gmock/gmock.h"
-#include "gtest/gtest-spi.h"
 #include "src/tint/lang/core/address_space.h"
 #include "src/tint/lang/core/builtin_value.h"
 #include "src/tint/lang/core/type/reference.h"
@@ -2088,7 +2087,7 @@
 }
 
 TEST_F(ResolverTest, ASTNodeNotReached) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b;
             b.Ident("ident");
@@ -2099,7 +2098,7 @@
 }
 
 TEST_F(ResolverTest, ASTNodeReachedTwice) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b;
             auto* expr = b.Expr(1_i);
diff --git a/src/tint/lang/wgsl/resolver/uniformity.cc b/src/tint/lang/wgsl/resolver/uniformity.cc
index 776d424..d6a5307 100644
--- a/src/tint/lang/wgsl/resolver/uniformity.cc
+++ b/src/tint/lang/wgsl/resolver/uniformity.cc
@@ -290,7 +290,6 @@
                 return required_to_be_uniform_info;
             default:
                 TINT_UNREACHABLE() << "unhandled severity";
-                return nullptr;
         }
     }
 
@@ -1478,10 +1477,9 @@
 
                         return LValue{cf, value, param};
                     },
-                    [&](Default) {
+                    [&](Default) -> LValue {
                         TINT_ICE() << "unknown lvalue identifier expression type: "
                                    << std::string(sem->Variable()->TypeInfo().name);
-                        return LValue{};
                     });
 
                 // If the identifier is part of an expression that is a partial reference to a
@@ -1810,7 +1808,6 @@
         } else {
             TINT_UNREACHABLE() << "unexpected call expression type";
         }
-        return nullptr;
     }
 
     /// Add diagnostic notes to show where control flow became non-uniform on the way to a node.
@@ -1942,7 +1939,6 @@
                     }
                     default: {
                         TINT_ICE() << "unhandled source of non-uniformity";
-                        break;
                     }
                 }
             },
diff --git a/src/tint/lang/wgsl/resolver/validation_test.cc b/src/tint/lang/wgsl/resolver/validation_test.cc
index 2e88cc0..5d0f51c 100644
--- a/src/tint/lang/wgsl/resolver/validation_test.cc
+++ b/src/tint/lang/wgsl/resolver/validation_test.cc
@@ -28,7 +28,6 @@
 #include "src/tint/lang/wgsl/resolver/resolver.h"
 
 #include "gmock/gmock.h"
-#include "gtest/gtest-spi.h"
 #include "src/tint/lang/core/builtin_value.h"
 #include "src/tint/lang/core/type/sampled_texture.h"
 #include "src/tint/lang/core/type/texture_dimension.h"
@@ -134,13 +133,14 @@
 }
 
 TEST_F(ResolverValidationTest, UnhandledStmt) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b;
             b.WrapInFunction(b.create<FakeStmt>());
             resolver::Resolve(b);
         },
-        "internal compiler error: Switch() matched no cases. Type: tint::resolver::FakeStmt");
+        testing::HasSubstr(
+            "internal compiler error: Switch() matched no cases. Type: tint::resolver::FakeStmt"));
 }
 
 TEST_F(ResolverValidationTest, Stmt_If_NonBool) {
@@ -164,13 +164,14 @@
 }
 
 TEST_F(ResolverValidationTest, Expr_ErrUnknownExprType) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             ProgramBuilder b;
             b.WrapInFunction(b.create<FakeExpr>());
             Resolver(&b, {}).Resolve();
         },
-        "internal compiler error: Switch() matched no cases. Type: tint::resolver::FakeExpr");
+        testing::HasSubstr(
+            "internal compiler error: Switch() matched no cases. Type: tint::resolver::FakeExpr"));
 }
 
 TEST_F(ResolverValidationTest, UsingUndefinedVariable_Fail) {
diff --git a/src/tint/lang/wgsl/resolver/validator.cc b/src/tint/lang/wgsl/resolver/validator.cc
index 7963482..155aaf1 100644
--- a/src/tint/lang/wgsl/resolver/validator.cc
+++ b/src/tint/lang/wgsl/resolver/validator.cc
@@ -1222,7 +1222,6 @@
 
                     if (TINT_UNLIKELY(!location.has_value())) {
                         TINT_ICE() << "@location has no value";
-                        return false;
                     }
 
                     return LocationAttribute(loc_attr, ty, stage, source);
@@ -1232,7 +1231,6 @@
 
                     if (TINT_UNLIKELY(!blend_src.has_value())) {
                         TINT_ICE() << "@blend_src has no value";
-                        return false;
                     }
 
                     return BlendSrcAttribute(blend_src_attr, stage);
@@ -1252,7 +1250,6 @@
 
                     if (TINT_UNLIKELY(!color.has_value())) {
                         TINT_ICE() << "@color has no value";
-                        return false;
                     }
 
                     return ColorAttribute(col_attr, ty, stage, source, is_input);
@@ -2041,7 +2038,6 @@
 
     if (TINT_UNLIKELY(!c->Is<core::type::ConstantArrayCount>())) {
         TINT_ICE() << "Invalid ArrayCount found";
-        return false;
     }
 
     const auto count = c->As<core::type::ConstantArrayCount>()->value;
@@ -2554,7 +2550,6 @@
         rhs = compound->rhs;
     } else {
         TINT_ICE() << "invalid assignment statement";
-        return false;
     }
 
     if (lhs->Is<ast::PhonyExpression>()) {
diff --git a/src/tint/lang/wgsl/sem/array_count.cc b/src/tint/lang/wgsl/sem/array_count.cc
index 3e6b5e0..37d3412 100644
--- a/src/tint/lang/wgsl/sem/array_count.cc
+++ b/src/tint/lang/wgsl/sem/array_count.cc
@@ -52,7 +52,6 @@
 
 core::type::ArrayCount* NamedOverrideArrayCount::Clone(core::type::CloneContext&) const {
     TINT_UNREACHABLE() << "Named override array count clone not available";
-    return nullptr;
 }
 
 UnnamedOverrideArrayCount::UnnamedOverrideArrayCount(const ValueExpression* e)
@@ -72,7 +71,6 @@
 
 core::type::ArrayCount* UnnamedOverrideArrayCount::Clone(core::type::CloneContext&) const {
     TINT_UNREACHABLE() << "Unnamed override array count clone not available";
-    return nullptr;
 }
 
 }  // namespace tint::sem
diff --git a/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program.cc b/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program.cc
index 8840d93..b404397 100644
--- a/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program.cc
+++ b/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program.cc
@@ -79,6 +79,7 @@
 #include "src/tint/lang/core/type/storage_texture.h"
 #include "src/tint/lang/core/type/texture.h"
 #include "src/tint/lang/core/type/type.h"
+#include "src/tint/lang/wgsl/ast/type.h"
 #include "src/tint/lang/wgsl/ir/builtin_call.h"
 #include "src/tint/lang/wgsl/ir/unary.h"
 #include "src/tint/lang/wgsl/program/program_builder.h"
@@ -248,7 +249,6 @@
                         break;
                     default:
                         TINT_UNIMPLEMENTED() << builtin.value();
-                        break;
                 }
             }
             if (auto loc = param->Location()) {
@@ -302,7 +302,6 @@
                     break;
                 default:
                     TINT_UNIMPLEMENTED() << builtin.value();
-                    break;
             }
         }
         if (auto loc = fn->ReturnLocation()) {
@@ -543,7 +542,6 @@
         // Return has arguments - this is the return value.
         if (ret->Args().Length() != 1) {
             TINT_ICE() << "expected 1 value for return, got " << ret->Args().Length();
-            return;
         }
 
         Append(b.Return(Expr(ret->Args().Front())));
@@ -685,7 +683,6 @@
                 break;
             default:
                 TINT_UNIMPLEMENTED() << u->Op();
-                break;
         }
         Bind(u->Result(0), expr);
     }
@@ -711,7 +708,7 @@
                 [&](const core::type::Struct* s) {
                     if (auto* c = index->As<core::ir::Constant>()) {
                         auto i = c->Value()->ValueAs<uint32_t>();
-                        TINT_ASSERT_OR_RETURN(i < s->Members().Length());
+                        TINT_ASSERT(i < s->Members().Length());
                         auto* member = s->Members()[i];
                         obj_ty = member->Type();
                         expr = b.MemberAccessor(expr, member->Name().NameView());
@@ -730,7 +727,6 @@
         for (uint32_t i : s->Indices()) {
             if (TINT_UNLIKELY(i >= 4)) {
                 TINT_ICE() << "invalid swizzle index: " << i;
-                return;
             }
             components.Push("xyzw"[i]);
         }
@@ -822,7 +818,6 @@
                 if (TINT_UNLIKELY(!lookup)) {
                     TINT_ICE() << "Expr(" << (value ? value->TypeInfo().name : "null")
                                << ") value has no expression";
-                    return nullptr;
                 }
                 return std::visit(
                     [&](auto&& got) -> const ast::Expression* {
@@ -951,7 +946,6 @@
                 auto count = a->ConstantCount();
                 if (TINT_UNLIKELY(!count)) {
                     TINT_ICE() << core::type::Array::kErrExpectedConstantCount;
-                    return b.ty.array(el, u32(1), std::move(attrs));
                 }
                 return b.ty.array(el, u32(count.value()), std::move(attrs));
             },
@@ -988,9 +982,8 @@
                                   : core::Access::kUndefined;
                 return b.ty.ptr(address_space, el, access);
             },
-            [&](const core::type::Reference*) {
+            [&](const core::type::Reference*) -> ast::Type {
                 TINT_ICE() << "reference types should never appear in the IR";
-                return b.ty.i32();
             },  //
             TINT_ICE_ON_NO_MATCH);
     }
diff --git a/src/tint/lang/wgsl/writer/raise/raise.cc b/src/tint/lang/wgsl/writer/raise/raise.cc
index dcb3e4e..c576ac4 100644
--- a/src/tint/lang/wgsl/writer/raise/raise.cc
+++ b/src/tint/lang/wgsl/writer/raise/raise.cc
@@ -173,7 +173,6 @@
             break;
     }
     TINT_ICE() << "unhandled builtin function: " << fn;
-    return wgsl::BuiltinFn::kNone;
 }
 
 void ReplaceBuiltinFnCall(core::ir::Module& mod, core::ir::CoreBuiltinCall* call) {
diff --git a/src/tint/utils/containers/vector_test.cc b/src/tint/utils/containers/vector_test.cc
index 0d8f5cb..f437ddb 100644
--- a/src/tint/utils/containers/vector_test.cc
+++ b/src/tint/utils/containers/vector_test.cc
@@ -31,13 +31,16 @@
 #include <tuple>
 
 #include "gmock/gmock.h"
-#include "gtest/gtest-spi.h"
 
 #include "src/tint/utils/containers/predicates.h"
 #include "src/tint/utils/macros/compiler.h"
 #include "src/tint/utils/memory/bitcast.h"
 #include "src/tint/utils/text/string_stream.h"
 
+// MSVC claims there's unreachable code in some of the EXPECT_DEATH cases, but scoping the
+// DISABLE_WARNING to the test is not sufficient to suppress the warning.
+TINT_BEGIN_DISABLE_WARNING(UNREACHABLE_CODE);
+
 namespace tint {
 namespace {
 
@@ -2107,21 +2110,18 @@
 }
 
 TEST(TintVectorTest, AssertOOBs) {
-    TINT_BEGIN_DISABLE_WARNING(UNREACHABLE_CODE);
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             Vector vec{1};
             [[maybe_unused]] int i = vec[1];
         },
         "internal compiler error");
-    TINT_END_DISABLE_WARNING(UNREACHABLE_CODE);
 }
 
 #if TINT_VECTOR_MUTATION_CHECKS_ENABLED
 TEST(TintVectorTest, AssertPushWhileIterating) {
-    TINT_BEGIN_DISABLE_WARNING(UNREACHABLE_CODE);
     using V = Vector<int, 4>;
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             V vec;
             vec.Push(1);
@@ -2132,13 +2132,11 @@
             }
         },
         "internal compiler error");
-    TINT_END_DISABLE_WARNING(UNREACHABLE_CODE);
 }
 
 TEST(TintVectorTest, AssertPopWhileIterating) {
-    TINT_BEGIN_DISABLE_WARNING(UNREACHABLE_CODE);
     using V = Vector<int, 4>;
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             V vec;
             vec.Push(1);
@@ -2149,13 +2147,11 @@
             }
         },
         "internal compiler error");
-    TINT_END_DISABLE_WARNING(UNREACHABLE_CODE);
 }
 
 TEST(TintVectorTest, AssertClearWhileIterating) {
-    TINT_BEGIN_DISABLE_WARNING(UNREACHABLE_CODE);
     using V = Vector<int, 4>;
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             V vec;
             vec.Push(1);
@@ -2166,7 +2162,6 @@
             }
         },
         "internal compiler error");
-    TINT_END_DISABLE_WARNING(UNREACHABLE_CODE);
 }
 #endif
 
@@ -2451,7 +2446,7 @@
 }
 
 TEST(TintVectorRefTest, AssertOOBs) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             Vector vec{1};
             const VectorRef<int> vec_ref(vec);
@@ -2467,3 +2462,5 @@
 TINT_INSTANTIATE_TYPEINFO(tint::C1);
 TINT_INSTANTIATE_TYPEINFO(tint::C2a);
 TINT_INSTANTIATE_TYPEINFO(tint::C2b);
+
+TINT_END_DISABLE_WARNING(UNREACHABLE_CODE);
diff --git a/src/tint/utils/diagnostic/source.cc b/src/tint/utils/diagnostic/source.cc
index b183f8a..47d8831 100644
--- a/src/tint/utils/diagnostic/source.cc
+++ b/src/tint/utils/diagnostic/source.cc
@@ -192,11 +192,11 @@
 }
 
 size_t Source::Range::Length(const FileContent& content) const {
-    TINT_ASSERT_OR_RETURN_VALUE(begin <= end, 0);
-    TINT_ASSERT_OR_RETURN_VALUE(begin.column > 0, 0);
-    TINT_ASSERT_OR_RETURN_VALUE(begin.line > 0, 0);
-    TINT_ASSERT_OR_RETURN_VALUE(end.line <= 1 + content.lines.size(), 0);
-    TINT_ASSERT_OR_RETURN_VALUE(end.column <= 1 + content.lines[end.line - 1].size(), 0);
+    TINT_ASSERT(begin <= end);
+    TINT_ASSERT(begin.column > 0);
+    TINT_ASSERT(begin.line > 0);
+    TINT_ASSERT(end.line <= 1 + content.lines.size());
+    TINT_ASSERT(end.column <= 1 + content.lines[end.line - 1].size());
 
     if (end.line == begin.line) {
         return end.column - begin.column;
diff --git a/src/tint/utils/generator/text_generator.cc b/src/tint/utils/generator/text_generator.cc
index e7140cb..e1ea901 100644
--- a/src/tint/utils/generator/text_generator.cc
+++ b/src/tint/utils/generator/text_generator.cc
@@ -72,7 +72,6 @@
         TINT_ICE() << "TextBuffer::Insert() called with before > lines.size()\n"
                    << "  before:" << before << "\n"
                    << "  lines.size(): " << lines.size();
-        return;
     }
     using DT = decltype(lines)::difference_type;
     lines.insert(lines.begin() + static_cast<DT>(before), LineInfo{indent, line});
@@ -90,7 +89,6 @@
         TINT_ICE() << "TextBuffer::Insert() called with before > lines.size()\n"
                    << "  before:" << before << "\n"
                    << "  lines.size(): " << lines.size();
-        return;
     }
     size_t idx = 0;
     for (auto& line : tb.lines) {
diff --git a/src/tint/utils/ice/ice.cc b/src/tint/utils/ice/ice.cc
index f40d49e..aac1eb9 100644
--- a/src/tint/utils/ice/ice.cc
+++ b/src/tint/utils/ice/ice.cc
@@ -27,10 +27,12 @@
 
 #include "src/tint/utils/ice/ice.h"
 
+#include <iostream>
 #include <memory>
 #include <string>
 
 #include "src/tint/utils/debug/debugger.h"
+#include "src/tint/utils/macros/compiler.h"
 
 namespace tint {
 namespace {
@@ -46,12 +48,23 @@
 InternalCompilerError::InternalCompilerError(const char* file, size_t line)
     : file_(file), line_(line) {}
 
+TINT_BEGIN_DISABLE_WARNING(DESTRUCTOR_NEVER_RETURNS);
 InternalCompilerError::~InternalCompilerError() {
     if (ice_reporter) {
         ice_reporter(*this);
+    } else {
+        std::cerr << Error() << std::endl << std::endl;
     }
+
     debugger::Break();
+
+#if defined(_MSC_VER) && !defined(__clang__)
+    abort();
+#else
+    __builtin_trap();
+#endif
 }
+TINT_END_DISABLE_WARNING(DESTRUCTOR_NEVER_RETURNS);
 
 std::string InternalCompilerError::Error() const {
     return std::string(File()) + ":" + std::to_string(Line()) +
diff --git a/src/tint/utils/ice/ice.h b/src/tint/utils/ice/ice.h
index ae84b68..96087bc 100644
--- a/src/tint/utils/ice/ice.h
+++ b/src/tint/utils/ice/ice.h
@@ -48,9 +48,9 @@
     InternalCompilerError(const char* file, size_t line);
 
     /// Destructor.
-    /// Adds the internal compiler error message to the diagnostics list, and then
-    /// calls the InternalCompilerErrorReporter if one is set.
-    ~InternalCompilerError();
+    /// Adds the internal compiler error message to the diagnostics list, calls the
+    /// InternalCompilerErrorReporter if one is set, then terminates the process.
+    [[noreturn]] ~InternalCompilerError();
 
     /// Appends `arg` to the ICE message.
     /// @param arg the argument to append to the ICE message
@@ -74,6 +74,9 @@
     std::string Error() const;
 
   private:
+    InternalCompilerError(const InternalCompilerError&) = delete;
+    InternalCompilerError(InternalCompilerError&&) = delete;
+
     char const* const file_;
     const size_t line_;
     std::stringstream msg_;
@@ -114,26 +117,4 @@
         }                                                \
     } while (false)
 
-/// TINT_ASSERT_OR_RETURN() is a macro for checking the expression is true, triggering a
-/// TINT_ICE if it is not and returning from the calling function.
-/// The ICE message contains the callsite's file and line.
-#define TINT_ASSERT_OR_RETURN(condition)                 \
-    do {                                                 \
-        if (TINT_UNLIKELY(!(condition))) {               \
-            TINT_ICE() << "TINT_ASSERT(" #condition ")"; \
-            return;                                      \
-        }                                                \
-    } while (false)
-
-/// TINT_ASSERT_OR_RETURN_VALUE() is a macro for checking the expression is true, triggering a
-/// TINT_ICE if it is not and returning a value from the calling function.
-/// The ICE message contains the callsite's file and line.
-#define TINT_ASSERT_OR_RETURN_VALUE(condition, value)    \
-    do {                                                 \
-        if (TINT_UNLIKELY(!(condition))) {               \
-            TINT_ICE() << "TINT_ASSERT(" #condition ")"; \
-            return value;                                \
-        }                                                \
-    } while (false)
-
 #endif  // SRC_TINT_UTILS_ICE_ICE_H_
diff --git a/src/tint/utils/ice/ice_test.cc b/src/tint/utils/ice/ice_test.cc
index 4c00d3d..0afa5de 100644
--- a/src/tint/utils/ice/ice_test.cc
+++ b/src/tint/utils/ice/ice_test.cc
@@ -27,13 +27,19 @@
 
 #include "src/tint/utils/ice/ice.h"
 
-#include "gtest/gtest-spi.h"
+#include "gtest/gtest.h"
 
 namespace tint {
 namespace {
 
 TEST(ICETest_AssertTrue_Test, Unreachable) {
-    EXPECT_FATAL_FAILURE({ TINT_UNREACHABLE(); }, "internal compiler error");
+    EXPECT_DEATH(
+        {
+            if ((true)) {
+                TINT_UNREACHABLE();
+            }
+        },
+        "internal compiler error");
 }
 
 TEST(ICETest_AssertTrue_Test, AssertTrue) {
@@ -41,7 +47,13 @@
 }
 
 TEST(ICETest_AssertTrue_Test, AssertFalse) {
-    EXPECT_FATAL_FAILURE({ TINT_ASSERT(false); }, "internal compiler error");
+    EXPECT_DEATH(
+        {
+            if ((true)) {
+                TINT_ASSERT(false);
+            }
+        },
+        "internal compiler error");
 }
 
 }  // namespace
diff --git a/src/tint/utils/macros/compiler.h b/src/tint/utils/macros/compiler.h
index a62a59e..6379c92 100644
--- a/src/tint/utils/macros/compiler.h
+++ b/src/tint/utils/macros/compiler.h
@@ -36,26 +36,30 @@
 ////////////////////////////////////////////////////////////////////////////////
 // MSVC
 ////////////////////////////////////////////////////////////////////////////////
+#define TINT_BUILD_IS_MSVC 1
 #define TINT_DISABLE_WARNING_CONSTANT_OVERFLOW __pragma(warning(disable : 4756))
-#define TINT_DISABLE_WARNING_MAYBE_UNINITIALIZED /* currently no-op */
-#define TINT_DISABLE_WARNING_NEWLINE_EOF         /* currently no-op */
-#define TINT_DISABLE_WARNING_OLD_STYLE_CAST      /* currently no-op */
-#define TINT_DISABLE_WARNING_SIGN_CONVERSION     /* currently no-op */
-#define TINT_DISABLE_WARNING_UNREACHABLE_CODE __pragma(warning(disable : 4702))
-#define TINT_DISABLE_WARNING_WEAK_VTABLES /* currently no-op */
-#define TINT_DISABLE_WARNING_FLOAT_EQUAL  /* currently no-op */
 #define TINT_DISABLE_WARNING_DEPRECATED __pragma(warning(disable : 4996))
-#define TINT_DISABLE_WARNING_RESERVED_IDENTIFIER       /* currently no-op */
-#define TINT_DISABLE_WARNING_RESERVED_MACRO_IDENTIFIER /* currently no-op */
-#define TINT_DISABLE_WARNING_UNUSED_VALUE              /* currently no-op */
-#define TINT_DISABLE_WARNING_UNUSED_PARAMETER __pragma(warning(disable : 4100))
-#define TINT_DISABLE_WARNING_SHADOW_FIELD_IN_CONSTRUCTOR /* currently no-op */
-#define TINT_DISABLE_WARNING_EXTRA_SEMICOLON             /* currently no-op */
-#define TINT_DISABLE_WARNING_ZERO_AS_NULLPTR             /* currently no-op */
+#define TINT_DISABLE_WARNING_DESTRUCTOR_NEVER_RETURNS __pragma(warning(disable : 4722))
+#define TINT_DISABLE_WARNING_EXTRA_SEMICOLON /* currently no-op */
+#define TINT_DISABLE_WARNING_FLOAT_EQUAL     /* currently no-op */
+#define TINT_DISABLE_WARNING_MAYBE_UNINITIALIZED __pragma(warning(disable : 4701))
 #define TINT_DISABLE_WARNING_MISSING_DESTRUCTOR_OVERRIDE /* currently no-op */
+#define TINT_DISABLE_WARNING_NEWLINE_EOF                 /* currently no-op */
+#define TINT_DISABLE_WARNING_OLD_STYLE_CAST              /* currently no-op */
+#define TINT_DISABLE_WARNING_RESERVED_IDENTIFIER         /* currently no-op */
+#define TINT_DISABLE_WARNING_RESERVED_MACRO_IDENTIFIER   /* currently no-op */
+#define TINT_DISABLE_WARNING_SHADOW_FIELD_IN_CONSTRUCTOR /* currently no-op */
+#define TINT_DISABLE_WARNING_SIGN_CONVERSION             /* currently no-op */
+#define TINT_DISABLE_WARNING_UNREACHABLE_CODE __pragma(warning(disable : 4702))
+#define TINT_DISABLE_WARNING_UNUSED_PARAMETER __pragma(warning(disable : 4100))
+#define TINT_DISABLE_WARNING_UNUSED_VALUE    /* currently no-op */
+#define TINT_DISABLE_WARNING_WEAK_VTABLES    /* currently no-op */
+#define TINT_DISABLE_WARNING_ZERO_AS_NULLPTR /* currently no-op */
+
+#define TINT_BEGIN_DISABLE_OPTIMIZATIONS() __pragma(optimize("", off)) TINT_REQUIRE_SEMICOLON
+#define TINT_END_DISABLE_OPTIMIZATIONS() __pragma(optimize("", on)) TINT_REQUIRE_SEMICOLON
 
 #define TINT_BEGIN_DISABLE_ALL_WARNINGS() __pragma(warning(push, 0)) TINT_REQUIRE_SEMICOLON
-
 #define TINT_END_DISABLE_ALL_WARNINGS() __pragma(warning(pop)) TINT_REQUIRE_SEMICOLON
 
 // clang-format off
@@ -83,34 +87,36 @@
 ////////////////////////////////////////////////////////////////////////////////
 // Clang
 ////////////////////////////////////////////////////////////////////////////////
-#define TINT_DISABLE_WARNING_CONSTANT_OVERFLOW /* currently no-op */
+#define TINT_BUILD_IS_CLANG 1
+#define TINT_DISABLE_WARNING_CONSTANT_OVERFLOW        /* currently no-op */
+#define TINT_DISABLE_WARNING_DEPRECATED               /* currently no-op */
+#define TINT_DISABLE_WARNING_DESTRUCTOR_NEVER_RETURNS /* currently no-op */
+#define TINT_DISABLE_WARNING_EXTRA_SEMICOLON \
+    _Pragma("clang diagnostic ignored \"-Wextra-semi-stmt\"")
+#define TINT_DISABLE_WARNING_FLOAT_EQUAL _Pragma("clang diagnostic ignored \"-Wfloat-equal\"")
 #define TINT_DISABLE_WARNING_MAYBE_UNINITIALIZED \
     _Pragma("clang diagnostic ignored \"-Wconditional-uninitialized\"")
+#define TINT_DISABLE_WARNING_MISSING_DESTRUCTOR_OVERRIDE                  \
+    _Pragma("clang diagnostic ignored \"-Wsuggest-destructor-override\"") \
+        _Pragma("clang diagnostic ignored \"-Winconsistent-missing-destructor-override\"")
 #define TINT_DISABLE_WARNING_NEWLINE_EOF _Pragma("clang diagnostic ignored \"-Wnewline-eof\"")
 #define TINT_DISABLE_WARNING_OLD_STYLE_CAST _Pragma("clang diagnostic ignored \"-Wold-style-cast\"")
-#define TINT_DISABLE_WARNING_SIGN_CONVERSION \
-    _Pragma("clang diagnostic ignored \"-Wsign-conversion\"")
-#define TINT_DISABLE_WARNING_UNREACHABLE_CODE /* currently no-op */
-#define TINT_DISABLE_WARNING_WEAK_VTABLES _Pragma("clang diagnostic ignored \"-Wweak-vtables\"")
-#define TINT_DISABLE_WARNING_FLOAT_EQUAL _Pragma("clang diagnostic ignored \"-Wfloat-equal\"")
-#define TINT_DISABLE_WARNING_DEPRECATED /* currently no-op */
 #define TINT_DISABLE_WARNING_RESERVED_IDENTIFIER \
     _Pragma("clang diagnostic ignored \"-Wreserved-identifier\"")
 #define TINT_DISABLE_WARNING_RESERVED_MACRO_IDENTIFIER                  \
     _Pragma("clang diagnostic ignored \"-Wreserved-macro-identifier\"") \
         _Pragma("clang diagnostic ignored \"-Wreserved-id-macro\"")
-#define TINT_DISABLE_WARNING_UNUSED_VALUE _Pragma("clang diagnostic ignored \"-Wunused-value\"")
-#define TINT_DISABLE_WARNING_UNUSED_PARAMETER \
-    _Pragma("clang diagnostic ignored \"-Wunused-parameter\"")
 #define TINT_DISABLE_WARNING_SHADOW_FIELD_IN_CONSTRUCTOR \
     _Pragma("clang diagnostic ignored \"-Wshadow-field-in-constructor\"")
-#define TINT_DISABLE_WARNING_EXTRA_SEMICOLON \
-    _Pragma("clang diagnostic ignored \"-Wextra-semi-stmt\"")
+#define TINT_DISABLE_WARNING_SIGN_CONVERSION \
+    _Pragma("clang diagnostic ignored \"-Wsign-conversion\"")
+#define TINT_DISABLE_WARNING_UNREACHABLE_CODE /* currently no-op */
+#define TINT_DISABLE_WARNING_UNUSED_PARAMETER \
+    _Pragma("clang diagnostic ignored \"-Wunused-parameter\"")
+#define TINT_DISABLE_WARNING_UNUSED_VALUE _Pragma("clang diagnostic ignored \"-Wunused-value\"")
+#define TINT_DISABLE_WARNING_WEAK_VTABLES _Pragma("clang diagnostic ignored \"-Wweak-vtables\"")
 #define TINT_DISABLE_WARNING_ZERO_AS_NULLPTR \
     _Pragma("clang diagnostic ignored \"-Wzero-as-null-pointer-constant\"")
-#define TINT_DISABLE_WARNING_MISSING_DESTRUCTOR_OVERRIDE                  \
-    _Pragma("clang diagnostic ignored \"-Wsuggest-destructor-override\"") \
-        _Pragma("clang diagnostic ignored \"-Winconsistent-missing-destructor-override\"")
 
 // clang-format off
 #define TINT_BEGIN_DISABLE_PROTOBUF_WARNINGS()        \
@@ -131,6 +137,9 @@
     _Pragma("clang diagnostic pop")          \
     TINT_REQUIRE_SEMICOLON
 
+#define TINT_BEGIN_DISABLE_OPTIMIZATIONS() /* currently no-op */ TINT_REQUIRE_SEMICOLON
+#define TINT_END_DISABLE_OPTIMIZATIONS() /* currently no-op */ TINT_REQUIRE_SEMICOLON
+
 #define TINT_BEGIN_DISABLE_ALL_WARNINGS() \
     _Pragma("clang diagnostic push")      \
     _Pragma("clang diagnostic ignored \"-Weverything\"")       \
@@ -161,30 +170,35 @@
 ////////////////////////////////////////////////////////////////////////////////
 // GCC
 ////////////////////////////////////////////////////////////////////////////////
-#define TINT_DISABLE_WARNING_CONSTANT_OVERFLOW /* currently no-op */
+#define TINT_BUILD_IS_GCC 1
+#define TINT_DISABLE_WARNING_CONSTANT_OVERFLOW        /* currently no-op */
+#define TINT_DISABLE_WARNING_DEPRECATED               /* currently no-op */
+#define TINT_DISABLE_WARNING_DESTRUCTOR_NEVER_RETURNS /* currently no-op */
+#define TINT_DISABLE_WARNING_EXTRA_SEMICOLON          /* currently no-op */
+#define TINT_DISABLE_WARNING_FLOAT_EQUAL              /* currently no-op */
 #define TINT_DISABLE_WARNING_MAYBE_UNINITIALIZED \
     _Pragma("GCC diagnostic ignored \"-Wmaybe-uninitialized\"")
-#define TINT_DISABLE_WARNING_NEWLINE_EOF               /* currently no-op */
-#define TINT_DISABLE_WARNING_OLD_STYLE_CAST            /* currently no-op */
-#define TINT_DISABLE_WARNING_SIGN_CONVERSION           /* currently no-op */
-#define TINT_DISABLE_WARNING_UNREACHABLE_CODE          /* currently no-op */
-#define TINT_DISABLE_WARNING_WEAK_VTABLES              /* currently no-op */
-#define TINT_DISABLE_WARNING_FLOAT_EQUAL               /* currently no-op */
-#define TINT_DISABLE_WARNING_DEPRECATED                /* currently no-op */
-#define TINT_DISABLE_WARNING_RESERVED_IDENTIFIER       /* currently no-op */
-#define TINT_DISABLE_WARNING_RESERVED_MACRO_IDENTIFIER /* currently no-op */
-#define TINT_DISABLE_WARNING_UNUSED_VALUE _Pragma("GCC diagnostic ignored \"-Wunused-value\"")
+#define TINT_DISABLE_WARNING_MISSING_DESTRUCTOR_OVERRIDE /* currently no-op */
+#define TINT_DISABLE_WARNING_NEWLINE_EOF                 /* currently no-op */
+#define TINT_DISABLE_WARNING_OLD_STYLE_CAST              /* currently no-op */
+#define TINT_DISABLE_WARNING_RESERVED_IDENTIFIER         /* currently no-op */
+#define TINT_DISABLE_WARNING_RESERVED_MACRO_IDENTIFIER   /* currently no-op */
+#define TINT_DISABLE_WARNING_SHADOW_FIELD_IN_CONSTRUCTOR /* currently no-op */
+#define TINT_DISABLE_WARNING_SIGN_CONVERSION             /* currently no-op */
+#define TINT_DISABLE_WARNING_UNREACHABLE_CODE            /* currently no-op */
 #define TINT_DISABLE_WARNING_UNUSED_PARAMETER \
     _Pragma("GCC diagnostic ignored \"-Wunused-parameter\"")
-#define TINT_DISABLE_WARNING_SHADOW_FIELD_IN_CONSTRUCTOR /* currently no-op */
-#define TINT_DISABLE_WARNING_EXTRA_SEMICOLON             /* currently no-op */
-#define TINT_DISABLE_WARNING_ZERO_AS_NULLPTR             /* currently no-op */
-#define TINT_DISABLE_WARNING_MISSING_DESTRUCTOR_OVERRIDE /* currently no-op */
+#define TINT_DISABLE_WARNING_UNUSED_VALUE _Pragma("GCC diagnostic ignored \"-Wunused-value\"")
+#define TINT_DISABLE_WARNING_WEAK_VTABLES    /* currently no-op */
+#define TINT_DISABLE_WARNING_ZERO_AS_NULLPTR /* currently no-op */
 
 #define TINT_BEGIN_DISABLE_PROTOBUF_WARNINGS() \
     _Pragma("GCC diagnostic push") TINT_DISABLE_WARNING_UNUSED_PARAMETER TINT_REQUIRE_SEMICOLON
 #define TINT_END_DISABLE_PROTOBUF_WARNINGS() _Pragma("GCC diagnostic pop") TINT_REQUIRE_SEMICOLON
 
+#define TINT_BEGIN_DISABLE_OPTIMIZATIONS() /* currently no-op */ TINT_REQUIRE_SEMICOLON
+#define TINT_END_DISABLE_OPTIMIZATIONS() /* currently no-op */ TINT_REQUIRE_SEMICOLON
+
 // clang-format off
 #define TINT_BEGIN_DISABLE_ALL_WARNINGS()             \
     _Pragma("GCC diagnostic push")                    \
@@ -231,6 +245,8 @@
 ////////////////////////////////////////////////////////////////////////////////
 // Other
 ////////////////////////////////////////////////////////////////////////////////
+#define TINT_BEGIN_DISABLE_OPTIMIZATIONS() TINT_REQUIRE_SEMICOLON
+#define TINT_END_DISABLE_OPTIMIZATIONS() TINT_REQUIRE_SEMICOLON
 #define TINT_BEGIN_DISABLE_ALL_WARNINGS() TINT_REQUIRE_SEMICOLON
 #define TINT_END_DISABLE_ALL_WARNINGS TINT_REQUIRE_SEMICOLON
 #define TINT_BEGIN_DISABLE_WARNING(name) TINT_REQUIRE_SEMICOLON
@@ -242,4 +258,34 @@
 
 #endif
 
+#ifndef TINT_BUILD_IS_MSVC
+#define TINT_BUILD_IS_MSVC 0
+#endif
+
+#ifndef TINT_BUILD_IS_CLANG
+#define TINT_BUILD_IS_CLANG 0
+#endif
+
+#ifndef TINT_BUILD_IS_GCC
+#define TINT_BUILD_IS_GCC 0
+#endif
+
+#if TINT_BUILD_IS_MSVC
+#define TINT_MSVC_ONLY(x) x
+#else
+#define TINT_MSVC_ONLY(x)
+#endif
+
+#if TINT_BUILD_IS_CLANG
+#define TINT_CLANG_ONLY(x) x
+#else
+#define TINT_CLANG_ONLY(x)
+#endif
+
+#if TINT_BUILD_IS_GCC
+#define TINT_GCC_ONLY(x) x
+#else
+#define TINT_GCC_ONLY(x)
+#endif
+
 #endif  // SRC_TINT_UTILS_MACROS_COMPILER_H_
diff --git a/src/tint/utils/rtti/BUILD.bazel b/src/tint/utils/rtti/BUILD.bazel
index e40a7b2..56b972c 100644
--- a/src/tint/utils/rtti/BUILD.bazel
+++ b/src/tint/utils/rtti/BUILD.bazel
@@ -40,6 +40,7 @@
   name = "rtti",
   srcs = [
     "castable.cc",
+    "switch.cc",
   ],
   hdrs = [
     "castable.h",
@@ -64,7 +65,6 @@
     "switch_test.cc",
   ],
   deps = [
-    "//src/tint/utils/ice",
     "//src/tint/utils/macros",
     "//src/tint/utils/math",
     "//src/tint/utils/memory",
@@ -82,7 +82,6 @@
     "switch_bench.cc",
   ],
   deps = [
-    "//src/tint/utils/ice",
     "//src/tint/utils/macros",
     "//src/tint/utils/math",
     "//src/tint/utils/memory",
diff --git a/src/tint/utils/rtti/BUILD.cmake b/src/tint/utils/rtti/BUILD.cmake
index 6c58e07..72e5490 100644
--- a/src/tint/utils/rtti/BUILD.cmake
+++ b/src/tint/utils/rtti/BUILD.cmake
@@ -42,6 +42,7 @@
   utils/rtti/castable.cc
   utils/rtti/castable.h
   utils/rtti/ignore.h
+  utils/rtti/switch.cc
   utils/rtti/switch.h
 )
 
@@ -63,7 +64,6 @@
 )
 
 tint_target_add_dependencies(tint_utils_rtti_test test
-  tint_utils_ice
   tint_utils_macros
   tint_utils_math
   tint_utils_memory
@@ -84,7 +84,6 @@
 )
 
 tint_target_add_dependencies(tint_utils_rtti_bench bench
-  tint_utils_ice
   tint_utils_macros
   tint_utils_math
   tint_utils_memory
diff --git a/src/tint/utils/rtti/BUILD.gn b/src/tint/utils/rtti/BUILD.gn
index 8df0474..f4bdbb1 100644
--- a/src/tint/utils/rtti/BUILD.gn
+++ b/src/tint/utils/rtti/BUILD.gn
@@ -47,6 +47,7 @@
     "castable.cc",
     "castable.h",
     "ignore.h",
+    "switch.cc",
     "switch.h",
   ]
   deps = [
@@ -65,7 +66,6 @@
     ]
     deps = [
       "${tint_src_dir}:gmock_and_gtest",
-      "${tint_src_dir}/utils/ice",
       "${tint_src_dir}/utils/macros",
       "${tint_src_dir}/utils/math",
       "${tint_src_dir}/utils/memory",
@@ -79,7 +79,6 @@
     sources = [ "switch_bench.cc" ]
     deps = [
       "${tint_src_dir}:google_benchmark",
-      "${tint_src_dir}/utils/ice",
       "${tint_src_dir}/utils/macros",
       "${tint_src_dir}/utils/math",
       "${tint_src_dir}/utils/memory",
diff --git a/src/tint/utils/rtti/switch.cc b/src/tint/utils/rtti/switch.cc
new file mode 100644
index 0000000..249c599
--- /dev/null
+++ b/src/tint/utils/rtti/switch.cc
@@ -0,0 +1,41 @@
+// Copyright 2024 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+//    list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+//    this list of conditions and the following disclaimer in the documentation
+//    and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+//    contributors may be used to endorse or promote products derived from
+//    this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "src/tint/utils/rtti/switch.h"
+#include "src/tint/utils/ice/ice.h"
+
+namespace tint::detail {
+
+void ICENoSwitchPassedNullptr(const char* file, unsigned int line) {
+    InternalCompilerError(file, line) << "Switch() passed nullptr";
+}
+
+void ICENoSwitchCasesMatched(const char* file, unsigned int line, const char* type_name) {
+    InternalCompilerError(file, line) << "Switch() matched no cases. Type: " << type_name;
+}
+
+}  // namespace tint::detail
diff --git a/src/tint/utils/rtti/switch.h b/src/tint/utils/rtti/switch.h
index 2436f5f..eb10dee 100644
--- a/src/tint/utils/rtti/switch.h
+++ b/src/tint/utils/rtti/switch.h
@@ -31,7 +31,6 @@
 #include <tuple>
 #include <utility>
 
-#include "src/tint/utils/ice/ice.h"
 #include "src/tint/utils/macros/defer.h"
 #include "src/tint/utils/memory/aligned_storage.h"
 #include "src/tint/utils/rtti/castable.h"
@@ -70,9 +69,9 @@
 ///     [&](TypeB*) { /* ... */ },
 ///     TINT_ICE_ON_NO_MATCH);
 /// ```
-#define TINT_ICE_ON_NO_MATCH    \
-    tint::SwitchMustMatchCase { \
-        __FILE__, __LINE__      \
+#define TINT_ICE_ON_NO_MATCH      \
+    ::tint::SwitchMustMatchCase { \
+        __FILE__, __LINE__        \
     }
 
 }  // namespace tint
@@ -120,7 +119,7 @@
 }
 /// Resolves to T if T is not nullptr_t, otherwise resolves to Ignore.
 template <typename T>
-using NullptrToIgnore = std::conditional_t<std::is_same_v<T, std::nullptr_t>, tint::Ignore, T>;
+using NullptrToIgnore = std::conditional_t<std::is_same_v<T, std::nullptr_t>, ::tint::Ignore, T>;
 
 /// Resolves to `const TYPE` if any of `CASE_RETURN_TYPES` are const or pointer-to-const, otherwise
 /// resolves to TYPE.
@@ -145,7 +144,7 @@
 
 /// SwitchReturnTypeImpl specialization for non-castable case types and an inferred return type.
 template <typename... CASE_RETURN_TYPES>
-struct SwitchReturnTypeImpl</*IS_CASTABLE*/ false, tint::detail::Infer, CASE_RETURN_TYPES...> {
+struct SwitchReturnTypeImpl</*IS_CASTABLE*/ false, ::tint::detail::Infer, CASE_RETURN_TYPES...> {
     /// Resolves to the common type for all the cases return types.
     using type = std::common_type_t<CASE_RETURN_TYPES...>;
 };
@@ -161,7 +160,7 @@
 
 /// SwitchReturnTypeImpl specialization for castable case types and an inferred return type.
 template <typename... CASE_RETURN_TYPES>
-struct SwitchReturnTypeImpl</*IS_CASTABLE*/ true, tint::detail::Infer, CASE_RETURN_TYPES...> {
+struct SwitchReturnTypeImpl</*IS_CASTABLE*/ true, ::tint::detail::Infer, CASE_RETURN_TYPES...> {
   private:
     using InferredType =
         CastableCommonBase<NullptrToIgnore<std::remove_pointer_t<CASE_RETURN_TYPES>>...>;
@@ -176,7 +175,7 @@
 /// from the case return types.
 template <typename REQUESTED_TYPE, typename... CASE_RETURN_TYPES>
 using SwitchReturnType = typename SwitchReturnTypeImpl<
-    tint::IsCastable<NullptrToIgnore<std::remove_pointer_t<CASE_RETURN_TYPES>>...>,
+    ::tint::IsCastable<NullptrToIgnore<std::remove_pointer_t<CASE_RETURN_TYPES>>...>,
     REQUESTED_TYPE,
     CASE_RETURN_TYPES...>::type;
 
@@ -188,23 +187,34 @@
 template <typename CASE>
 struct SwitchCaseReturnTypeImpl<CASE, /* is_flag */ false> {
     /// The case function's return type.
-    using type = tint::traits::ReturnType<CASE>;
+    using type = ::tint::traits::ReturnType<CASE>;
 };
 
 /// SwitchCaseReturnTypeImpl specialization for flags.
 template <typename CASE>
 struct SwitchCaseReturnTypeImpl<CASE, /* is_flag */ true> {
     /// These are not functions, they have no return type.
-    using type = tint::Ignore;
+    using type = ::tint::Ignore;
 };
 
 /// Resolves to the return type for a Switch() case.
-/// If CASE is a flag like SwitchMustMatchCase, then resolves to tint::Ignore
+/// If CASE is a flag like SwitchMustMatchCase, then resolves to ::tint::Ignore
 template <typename CASE>
 using SwitchCaseReturnType = typename SwitchCaseReturnTypeImpl<
     CASE,
     std::is_same_v<std::decay_t<CASE>, SwitchMustMatchCase>>::type;
 
+/// Raises an ICE error that a Switch() was passed a nullptr object and there was no default case
+[[noreturn]] void ICENoSwitchPassedNullptr(const char* file, unsigned int line);
+
+/// Raises an ICE error that a Switch() with a TINT_ICE_ON_NO_MATCH matched no cases.
+/// @param file the file holding the Switch()
+/// @param line the line of the TINT_ICE_ON_NO_MATCH
+/// @type_name the type name of the object passed to Switch()
+[[noreturn]] void ICENoSwitchCasesMatched(const char* file,
+                                          unsigned int line,
+                                          const char* type_name);
+
 }  // namespace tint::detail
 
 namespace tint {
@@ -248,18 +258,19 @@
 /// @param args the switch cases followed by an optional TINT_ICE_ON_NO_MATCH
 /// @return the value returned by the called case. If no cases matched, then the zero value for the
 /// consistent case type.
-template <typename RETURN_TYPE = tint::detail::Infer, typename T = CastableBase, typename... ARGS>
+template <typename RETURN_TYPE = ::tint::detail::Infer, typename T = CastableBase, typename... ARGS>
 inline auto Switch(T* object, ARGS&&... args) {
     TINT_BEGIN_DISABLE_WARNING(UNUSED_VALUE);
 
     using ArgsTuple = std::tuple<ARGS...>;
     static constexpr int kMustMatchCaseIndex =
-        tint::detail::IndexOfSwitchMustMatchCase<ArgsTuple>();
+        ::tint::detail::IndexOfSwitchMustMatchCase<ArgsTuple>();
     static constexpr bool kHasMustMatchCase = kMustMatchCaseIndex >= 0;
-    static constexpr int kDefaultIndex = tint::detail::IndexOfDefaultCase<ArgsTuple>();
+    static constexpr int kDefaultIndex = ::tint::detail::IndexOfDefaultCase<ArgsTuple>();
     static constexpr bool kHasDefaultCase = kDefaultIndex >= 0;
     using ReturnType =
-        tint::detail::SwitchReturnType<RETURN_TYPE, tint::detail::SwitchCaseReturnType<ARGS>...>;
+        ::tint::detail::SwitchReturnType<RETURN_TYPE,
+                                         ::tint::detail::SwitchCaseReturnType<ARGS>...>;
     static constexpr bool kHasReturnType = !std::is_same_v<ReturnType, void>;
 
     // Static assertions
@@ -280,7 +291,7 @@
     if (!object) {  // Object is nullptr, so no cases can match
         if constexpr (kHasMustMatchCase) {
             const SwitchMustMatchCase& info = (args, ...);
-            tint::InternalCompilerError(info.file, info.line) << "Switch() passed nullptr";
+            ::tint::detail::ICENoSwitchPassedNullptr(info.file, info.line);
             if constexpr (kHasReturnType) {
                 return ReturnType{};
             } else {
@@ -303,7 +314,7 @@
     AlignedStorage<std::conditional_t<kHasReturnType, ReturnType, uint8_t>> return_storage;
     auto* result = &return_storage.Get();
 
-    const tint::TypeInfo& type_info = object->TypeInfo();
+    const ::tint::TypeInfo& type_info = object->TypeInfo();
 
     // Examines the parameter type of the case function.
     // If the parameter is a pointer type that `object` is of, or derives from, then that case
@@ -317,10 +328,9 @@
         using CaseFunc = std::decay_t<decltype(case_fn)>;
         bool success = false;
         if constexpr (std::is_same_v<CaseFunc, SwitchMustMatchCase>) {
-            tint::InternalCompilerError(case_fn.file, case_fn.line)
-                << "Switch() matched no cases. Type: " << type_info.name;
+            ::tint::detail::ICENoSwitchCasesMatched(case_fn.file, case_fn.line, type_info.name);
         } else {
-            using CaseType = tint::detail::SwitchCaseType<CaseFunc>;
+            using CaseType = ::tint::detail::SwitchCaseType<CaseFunc>;
             if constexpr (std::is_same_v<CaseType, Default>) {
                 if constexpr (kHasReturnType) {
                     new (result) ReturnType(static_cast<ReturnType>(case_fn(Default{})));
diff --git a/src/tint/utils/rtti/switch_test.cc b/src/tint/utils/rtti/switch_test.cc
index f915c9e..4ae0f95 100644
--- a/src/tint/utils/rtti/switch_test.cc
+++ b/src/tint/utils/rtti/switch_test.cc
@@ -30,7 +30,7 @@
 #include <memory>
 #include <string>
 
-#include "gtest/gtest-spi.h"
+#include "gmock/gmock.h"
 #include "gtest/gtest.h"
 
 namespace tint {
@@ -230,7 +230,7 @@
 }
 
 TEST(Castable, SwitchMustMatch_NoMatchWithoutReturnValue) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             std::unique_ptr<Animal> frog = std::make_unique<Frog>();
             Switch(
@@ -239,11 +239,11 @@
                 [&](Mammal*) {},   //
                 TINT_ICE_ON_NO_MATCH);
         },
-        "internal compiler error: Switch() matched no cases. Type: Frog");
+        testing::HasSubstr("internal compiler error: Switch() matched no cases. Type: Frog"));
 }
 
 TEST(Castable, SwitchMustMatch_NoMatchWithReturnValue) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             std::unique_ptr<Animal> frog = std::make_unique<Frog>();
             int res = Switch(
@@ -253,11 +253,11 @@
                 TINT_ICE_ON_NO_MATCH);
             ASSERT_EQ(res, 0);
         },
-        "internal compiler error: Switch() matched no cases. Type: Frog");
+        testing::HasSubstr("internal compiler error: Switch() matched no cases. Type: Frog"));
 }
 
 TEST(Castable, SwitchMustMatch_NullptrWithoutReturnValue) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             Switch(
                 static_cast<CastableBase*>(nullptr),  //
@@ -265,11 +265,11 @@
                 [&](Mammal*) {},                      //
                 TINT_ICE_ON_NO_MATCH);
         },
-        "internal compiler error: Switch() passed nullptr");
+        testing::HasSubstr("internal compiler error: Switch() passed nullptr"));
 }
 
 TEST(Castable, SwitchMustMatch_NullptrWithReturnValue) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             int res = Switch(
                 static_cast<CastableBase*>(nullptr),  //
@@ -278,7 +278,7 @@
                 TINT_ICE_ON_NO_MATCH);
             ASSERT_EQ(res, 0);
         },
-        "internal compiler error: Switch() passed nullptr");
+        testing::HasSubstr("internal compiler error: Switch() passed nullptr"));
 }
 
 TEST(Castable, SwitchMatchFirst) {
diff --git a/src/tint/utils/symbol/symbol_table.cc b/src/tint/utils/symbol/symbol_table.cc
index 6685517..69ead5d 100644
--- a/src/tint/utils/symbol/symbol_table.cc
+++ b/src/tint/utils/symbol/symbol_table.cc
@@ -94,7 +94,6 @@
     char* name_mem = Bitcast<char*>(name_allocator_.Allocate(name.length() + 1));
     if (name_mem == nullptr) {
         TINT_ICE() << "failed to allocate memory for symbol's string";
-        return {};
     }
 
     memcpy(name_mem, name.data(), name.length() + 1);
diff --git a/src/tint/utils/symbol/symbol_table_test.cc b/src/tint/utils/symbol/symbol_table_test.cc
index 2a51e20..8421e1f 100644
--- a/src/tint/utils/symbol/symbol_table_test.cc
+++ b/src/tint/utils/symbol/symbol_table_test.cc
@@ -27,7 +27,7 @@
 
 #include "src/tint/utils/symbol/symbol_table.h"
 
-#include "gtest/gtest-spi.h"
+#include "gtest/gtest.h"
 
 namespace tint {
 namespace {
@@ -50,7 +50,7 @@
 }
 
 TEST_F(SymbolTableTest, AssertsForBlankString) {
-    EXPECT_FATAL_FAILURE(
+    EXPECT_DEATH(
         {
             auto generation_id = GenerationID::New();
             SymbolTable s{generation_id};