[tint] Separate out fatal macros from diagnostics

Many places where we assert, ICE or call other fatal macros there are no
diagnostic lists to append to. Regardless, a fatal error should not
happen in production, so handling these as standard diagnostics is
questionable.

Change-Id: I1ad4992586dee52ef2a58aa19e81083ae300aa96
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/143381
Reviewed-by: James Price <jrprice@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
Auto-Submit: Ben Clayton <bclayton@google.com>
diff --git a/include/tint/tint.h b/include/tint/tint.h
index fe3a787..d6e54e8 100644
--- a/include/tint/tint.h
+++ b/include/tint/tint.h
@@ -30,6 +30,8 @@
 #include "src/tint/lang/wgsl/ast/transform/vertex_pulling.h"
 #include "src/tint/lang/wgsl/helpers/flatten_bindings.h"
 #include "src/tint/lang/wgsl/inspector/inspector.h"
+#include "src/tint/utils/diagnostic/formatter.h"
+#include "src/tint/utils/diagnostic/printer.h"
 #include "tint/array_length_from_uniform_options.h"
 #include "tint/binding_point.h"
 #include "tint/binding_remapper_options.h"
diff --git a/src/dawn/native/TintUtils.cpp b/src/dawn/native/TintUtils.cpp
index 4cb758c..1d2dfd4 100644
--- a/src/dawn/native/TintUtils.cpp
+++ b/src/dawn/native/TintUtils.cpp
@@ -28,17 +28,11 @@
 
 thread_local DeviceBase* tlDevice = nullptr;
 
-void TintICEReporter(const tint::diag::List& diagnostics) {
+void TintICEReporter(const tint::InternalCompilerError& err) {
     if (tlDevice) {
-        tlDevice->HandleError(DAWN_INTERNAL_ERROR(diagnostics.str()));
+        tlDevice->HandleError(DAWN_INTERNAL_ERROR(err.Error()));
 #if DAWN_ENABLE_ASSERTS
-        for (const tint::diag::Diagnostic& diag : diagnostics) {
-            if (diag.severity >= tint::diag::Severity::InternalCompilerError) {
-                HandleAssertionFailure(
-                    diag.source.file ? diag.source.file->path.c_str() : "<unknown>", "",
-                    diag.source.range.begin.line, diag.message.c_str());
-            }
-        }
+        HandleAssertionFailure(err.File(), "", err.Line(), err.Message().c_str());
 #endif
     }
 }
diff --git a/src/tint/BUILD.gn b/src/tint/BUILD.gn
index d16559c..1a20807 100644
--- a/src/tint/BUILD.gn
+++ b/src/tint/BUILD.gn
@@ -229,8 +229,6 @@
     "utils/containers/unique_allocator.h",
     "utils/containers/unique_vector.h",
     "utils/containers/vector.h",
-    "utils/debug/debug.cc",
-    "utils/debug/debug.h",
     "utils/debug/debugger.cc",
     "utils/debug/debugger.h",
     "utils/diagnostic/diagnostic.cc",
@@ -241,6 +239,8 @@
     "utils/diagnostic/printer.h",
     "utils/diagnostic/source.cc",
     "utils/diagnostic/source.h",
+    "utils/ice/ice.cc",
+    "utils/ice/ice.h",
     "utils/macros/compiler.h",
     "utils/macros/concat.h",
     "utils/macros/defer.h",
@@ -1918,9 +1918,9 @@
       "utils/containers/unique_allocator_test.cc",
       "utils/containers/unique_vector_test.cc",
       "utils/containers/vector_test.cc",
-      "utils/debug/debug_test.cc",
       "utils/diagnostic/source_test.cc",
       "utils/file/tmpfile_test.cc",
+      "utils/ice/ice_test.cc",
       "utils/macros/defer_test.cc",
       "utils/macros/scoped_assignment_test.cc",
       "utils/math/crc32_test.cc",
diff --git a/src/tint/CMakeLists.txt b/src/tint/CMakeLists.txt
index 24472ad..2c85a44 100644
--- a/src/tint/CMakeLists.txt
+++ b/src/tint/CMakeLists.txt
@@ -56,8 +56,6 @@
 
 ## Tint diagnostic utilities. Used by libtint and tint_utils_io.
 add_library(tint_diagnostic_utils
-  utils/debug/debug.cc
-  utils/debug/debug.h
   utils/diagnostic/diagnostic.cc
   utils/diagnostic/diagnostic.h
   utils/diagnostic/formatter.cc
@@ -68,6 +66,8 @@
   utils/diagnostic/source.h
   utils/debug/debugger.cc
   utils/debug/debugger.h
+  utils/ice/ice.cc
+  utils/ice/ice.h
   utils/text/unicode.cc
   utils/text/unicode.h
 )
@@ -1139,12 +1139,12 @@
     utils/containers/unique_allocator_test.cc
     utils/containers/unique_vector_test.cc
     utils/containers/vector_test.cc
-    utils/debug/debug_test.cc
     utils/diagnostic/diagnostic_test.cc
     utils/diagnostic/formatter_test.cc
     utils/diagnostic/printer_test.cc
     utils/diagnostic/source_test.cc
     utils/file/tmpfile_test.cc
+    utils/ice/ice_test.cc
     utils/macros/defer_test.cc
     utils/macros/scoped_assignment_test.cc
     utils/math/crc32_test.cc
diff --git a/src/tint/cmd/helper.cc b/src/tint/cmd/helper.cc
index 29c8ab3..5fc4de5 100644
--- a/src/tint/cmd/helper.cc
+++ b/src/tint/cmd/helper.cc
@@ -22,6 +22,8 @@
 #include "spirv-tools/libspirv.hpp"
 #endif
 
+#include "src/tint/utils/diagnostic/formatter.h"
+#include "src/tint/utils/diagnostic/printer.h"
 #include "src/tint/utils/text/string.h"
 
 namespace tint::cmd {
@@ -68,10 +70,10 @@
 
 }  // namespace
 
-[[noreturn]] void TintInternalCompilerErrorReporter(const tint::diag::List& diagnostics) {
-    auto printer = tint::diag::Printer::create(stderr, true);
-    tint::diag::Formatter{}.format(diagnostics, printer.get());
-    tint::diag::Style bold_red{tint::diag::Color::kRed, true};
+[[noreturn]] void TintInternalCompilerErrorReporter(const InternalCompilerError& err) {
+    auto printer = diag::Printer::create(stderr, true);
+    diag::Style bold_red{diag::Color::kRed, true};
+    printer->write(err.Error(), bold_red);
     constexpr const char* please_file_bug = R"(
 ********************************************************************
 *  The tint shader compiler has encountered an unexpected error.   *
diff --git a/src/tint/cmd/helper.h b/src/tint/cmd/helper.h
index 6215059..8b00708 100644
--- a/src/tint/cmd/helper.h
+++ b/src/tint/cmd/helper.h
@@ -33,8 +33,7 @@
 };
 
 /// Reporter callback for internal tint errors
-/// @param diagnostics the diagnostics to emit
-[[noreturn]] void TintInternalCompilerErrorReporter(const tint::diag::List& diagnostics);
+[[noreturn]] void TintInternalCompilerErrorReporter(const InternalCompilerError& err);
 
 /// PrintWGSL writes the WGSL of the program to the provided ostream, if the
 /// WGSL writer is enabled, otherwise it does nothing.
diff --git a/src/tint/cmd/info.cc b/src/tint/cmd/info.cc
index 83421bc..34593f2 100644
--- a/src/tint/cmd/info.cc
+++ b/src/tint/cmd/info.cc
@@ -328,9 +328,6 @@
         return 0;
     }
 
-    auto diag_printer = tint::diag::Printer::create(stderr, true);
-    tint::diag::Formatter diag_formatter;
-
     std::unique_ptr<tint::Program> program;
     std::unique_ptr<tint::Source::File> source_file;
 
diff --git a/src/tint/cmd/loopy.cc b/src/tint/cmd/loopy.cc
index 26b9d20..e48fee7 100644
--- a/src/tint/cmd/loopy.cc
+++ b/src/tint/cmd/loopy.cc
@@ -318,9 +318,6 @@
         options.format = Format::kSpirv;
     }
 
-    auto diag_printer = tint::diag::Printer::create(stderr, true);
-    tint::diag::Formatter diag_formatter;
-
     std::unique_ptr<tint::Program> program;
     std::unique_ptr<tint::Source::File> source_file;
 
diff --git a/src/tint/cmd/main.cc b/src/tint/cmd/main.cc
index 72803b9..18cd971 100644
--- a/src/tint/cmd/main.cc
+++ b/src/tint/cmd/main.cc
@@ -41,6 +41,8 @@
 #include "src/tint/utils/cli/cli.h"
 #include "src/tint/utils/command/command.h"
 #include "src/tint/utils/containers/transform.h"
+#include "src/tint/utils/diagnostic/formatter.h"
+#include "src/tint/utils/diagnostic/printer.h"
 #include "src/tint/utils/macros/defer.h"
 #include "src/tint/utils/text/string.h"
 #include "src/tint/utils/text/string_stream.h"
@@ -809,7 +811,7 @@
         case tint::ast::PipelineStage::kCompute:
             return EShLangCompute;
         default:
-            TINT_ASSERT(AST, false);
+            TINT_UNREACHABLE();
             return EShLangVertex;
     }
 }
@@ -1004,9 +1006,6 @@
         options.format = Format::kSpvAsm;
     }
 
-    auto diag_printer = tint::diag::Printer::create(stderr, true);
-    tint::diag::Formatter diag_formatter;
-
     std::unique_ptr<tint::Program> program;
     std::unique_ptr<tint::Source::File> source_file;
 
@@ -1139,7 +1138,7 @@
     auto out = transform_manager.Run(program.get(), std::move(transform_inputs), outputs);
     if (!out.IsValid()) {
         tint::cmd::PrintWGSL(std::cerr, out);
-        diag_formatter.format(out.Diagnostics(), diag_printer.get());
+        std::cerr << out.Diagnostics().str() << std::endl;
         return 1;
     }
 
diff --git a/src/tint/fuzzers/tint_ast_clone_fuzzer.cc b/src/tint/fuzzers/tint_ast_clone_fuzzer.cc
index e498915..d017032 100644
--- a/src/tint/fuzzers/tint_ast_clone_fuzzer.cc
+++ b/src/tint/fuzzers/tint_ast_clone_fuzzer.cc
@@ -40,9 +40,8 @@
         }                                                                                       \
     } while (false)
 
-[[noreturn]] void TintInternalCompilerErrorReporter(const tint::diag::List& diagnostics) {
-    auto printer = tint::diag::Printer::create(stderr, true);
-    tint::diag::Formatter{}.format(diagnostics, printer.get());
+[[noreturn]] void TintInternalCompilerErrorReporter(const tint::InternalCompilerError& err) {
+    std::cerr << err.Error() << std::endl;
     __builtin_trap();
 }
 
diff --git a/src/tint/fuzzers/tint_ast_fuzzer/expression_size.cc b/src/tint/fuzzers/tint_ast_fuzzer/expression_size.cc
index addbbf5..a01fd67 100644
--- a/src/tint/fuzzers/tint_ast_fuzzer/expression_size.cc
+++ b/src/tint/fuzzers/tint_ast_fuzzer/expression_size.cc
@@ -29,8 +29,7 @@
             continue;
         }
         size_t expr_size = 0;
-        diag::List empty;
-        ast::TraverseExpressions(expr_ast_node, empty, [&](const ast::Expression* expression) {
+        ast::TraverseExpressions(expr_ast_node, [&](const ast::Expression* expression) {
             if (expression == expr_ast_node) {
                 expr_size++;
                 return ast::TraverseAction::Descend;
diff --git a/src/tint/fuzzers/tint_ast_fuzzer/fuzzer.cc b/src/tint/fuzzers/tint_ast_fuzzer/fuzzer.cc
index 8f2946d..01445b3 100644
--- a/src/tint/fuzzers/tint_ast_fuzzer/fuzzer.cc
+++ b/src/tint/fuzzers/tint_ast_fuzzer/fuzzer.cc
@@ -114,9 +114,8 @@
 
         fuzzer.Run(data, size);
         if (fuzzer.HasErrors()) {
-            std::cout << "Fuzzing " << target.name << " produced an error" << std::endl;
-            auto printer = tint::diag::Printer::create(stderr, true);
-            tint::diag::Formatter{}.format(fuzzer.Diagnostics(), printer.get());
+            std::cout << "Fuzzing " << target.name << " produced an error" << std::endl
+                      << fuzzer.Diagnostics().str() << std::endl;
         }
     }
 
diff --git a/src/tint/fuzzers/tint_common_fuzzer.cc b/src/tint/fuzzers/tint_common_fuzzer.cc
index 4bb3261..e4b56e0 100644
--- a/src/tint/fuzzers/tint_common_fuzzer.cc
+++ b/src/tint/fuzzers/tint_common_fuzzer.cc
@@ -37,6 +37,7 @@
 #include "src/tint/lang/wgsl/program/program.h"
 #include "src/tint/lang/wgsl/sem/variable.h"
 #include "src/tint/utils/diagnostic/formatter.h"
+#include "src/tint/utils/diagnostic/printer.h"
 #include "src/tint/utils/math/hash.h"
 #include "tint/binding_point.h"
 
@@ -59,21 +60,22 @@
         __builtin_trap();                                          \
     } while (false)
 
-[[noreturn]] void TintInternalCompilerErrorReporter(const tint::diag::List& diagnostics) {
-    FATAL_ERROR(diagnostics, "");
+[[noreturn]] void TintInternalCompilerErrorReporter(const InternalCompilerError& err) {
+    std::cerr << err.Error() << std::endl;
+    __builtin_trap();
 }
 
 // Wrapping in a macro, so it can be a one-liner in the code, but not
 // introduce another level in the stack trace. This will help with de-duping
 // ClusterFuzz issues.
-#define CHECK_INSPECTOR(program, inspector)                                                    \
-    do {                                                                                       \
-        if ((inspector).has_error()) {                                                         \
-            if (!enforce_validity) {                                                           \
-                return;                                                                        \
-            }                                                                                  \
-            FATAL_ERROR((program)->Diagnostics(), "Inspector failed: " + (inspector).error()); \
-        }                                                                                      \
+#define CHECK_INSPECTOR(program, inspector)                                                  \
+    do {                                                                                     \
+        if ((inspector).has_error()) {                                                       \
+            if (!enforce_validity) {                                                         \
+                return;                                                                      \
+            }                                                                                \
+            FATAL_ERROR(program->Diagnostics(), "Inspector failed: " + (inspector).error()); \
+        }                                                                                    \
     } while (false)
 
 // Wrapping in a macro to make code more readable and help with issue de-duping.
diff --git a/src/tint/fuzzers/tint_concurrency_fuzzer.cc b/src/tint/fuzzers/tint_concurrency_fuzzer.cc
index 24d8e02..0d2d8b0 100644
--- a/src/tint/fuzzers/tint_concurrency_fuzzer.cc
+++ b/src/tint/fuzzers/tint_concurrency_fuzzer.cc
@@ -32,9 +32,8 @@
 
 static constexpr size_t kNumThreads = 8;
 
-[[noreturn]] void TintInternalCompilerErrorReporter(const tint::diag::List& diagnostics) {
-    auto printer = tint::diag::Printer::create(stderr, true);
-    tint::diag::Formatter{}.format(diagnostics, printer.get());
+[[noreturn]] void TintInternalCompilerErrorReporter(const tint::InternalCompilerError& err) {
+    std::cerr << err.Error() << std::endl;
     __builtin_trap();
 }
 
diff --git a/src/tint/fuzzers/tint_ir_roundtrip_fuzzer.cc b/src/tint/fuzzers/tint_ir_roundtrip_fuzzer.cc
index 757b8f4..fa2c0b7 100644
--- a/src/tint/fuzzers/tint_ir_roundtrip_fuzzer.cc
+++ b/src/tint/fuzzers/tint_ir_roundtrip_fuzzer.cc
@@ -22,9 +22,8 @@
 #include "src/tint/lang/wgsl/writer/ir_to_program/ir_to_program.h"
 #include "src/tint/lang/wgsl/writer/writer.h"
 
-[[noreturn]] void TintInternalCompilerErrorReporter(const tint::diag::List& diagnostics) {
-    auto printer = tint::diag::Printer::create(stderr, true);
-    tint::diag::Formatter{}.format(diagnostics, printer.get());
+[[noreturn]] void TintInternalCompilerErrorReporter(const tint::InternalCompilerError& err) {
+    std::cerr << err.Error() << std::endl;
     __builtin_trap();
 }
 
diff --git a/src/tint/lang/core/builtin/number.cc b/src/tint/lang/core/builtin/number.cc
index 980d934..5c48960 100644
--- a/src/tint/lang/core/builtin/number.cc
+++ b/src/tint/lang/core/builtin/number.cc
@@ -18,7 +18,7 @@
 #include <cmath>
 #include <cstring>
 
-#include "src/tint/utils/debug/debug.h"
+#include "src/tint/utils/ice/ice.h"
 #include "src/tint/utils/memory/bitcast.h"
 #include "src/tint/utils/text/string_stream.h"
 
@@ -244,14 +244,13 @@
         // Since we ensure that kSmallestValue = 0x1f-14 > abs(value) >= kSmallestSubnormalValue =
         // 0x1f-24, value will have a unbiased exponent in range -24 to -15 (inclusive), and the
         // corresponding biased exponent in f32 is in range 103 to 112 (inclusive).
-        TINT_ASSERT(Semantic,
-                    (kMinF32BiasedExpForF16SubnormalNumber <= biased_exponent_original) &&
-                        (biased_exponent_original <= kMaxF32BiasedExpForF16SubnormalNumber));
+        TINT_ASSERT((kMinF32BiasedExpForF16SubnormalNumber <= biased_exponent_original) &&
+                    (biased_exponent_original <= kMaxF32BiasedExpForF16SubnormalNumber));
 
         // As we have proved, masking out the lowest 126-e mantissa bits of input value will result
         // in a valid subnormal f16 value, which is exactly the required quantization result.
         uint32_t discard_bits = 126 - biased_exponent_original;  // In range 14 to 23 (inclusive)
-        TINT_ASSERT(Semantic, (14 <= discard_bits) && (discard_bits <= kF32MantissaBits));
+        TINT_ASSERT((14 <= discard_bits) && (discard_bits <= kF32MantissaBits));
         uint32_t discard_mask = (1u << discard_bits) - 1;
         u32 = u32 & ~discard_mask;
     } else {
@@ -293,7 +292,7 @@
     uint32_t f32_mantissa = f32_bit_pattern & kF32MantissaMask;
 
     uint16_t f16_sign_part = static_cast<uint16_t>((f32_bit_pattern & kF32SignMask) >> 16);
-    TINT_ASSERT(Semantic, (f16_sign_part & ~kF16SignMask) == 0);
+    TINT_ASSERT((f16_sign_part & ~kF16SignMask) == 0);
 
     if ((f32_bit_pattern & ~kF32SignMask) == 0) {
         // +/- zero
@@ -308,8 +307,8 @@
         uint16_t f16_mantissa_part =
             static_cast<uint16_t>(f32_mantissa >> (kF32MantissaBits - kF16MantissaBits));
 
-        TINT_ASSERT(Semantic, (f16_exp_part & ~kF16ExponentMask) == 0);
-        TINT_ASSERT(Semantic, (f16_mantissa_part & ~kF16MantissaMask) == 0);
+        TINT_ASSERT((f16_exp_part & ~kF16ExponentMask) == 0);
+        TINT_ASSERT((f16_mantissa_part & ~kF16MantissaMask) == 0);
 
         return f16_sign_part | f16_exp_part | f16_mantissa_part;
     }
@@ -330,17 +329,16 @@
             static_cast<uint16_t>((f32_mantissa | (kF32MantissaMask + 1)) >>
                                   (kF32MantissaBits + 1 - f16_valid_mantissa_bits));
 
-        TINT_ASSERT(Semantic, (1 <= f16_valid_mantissa_bits) &&
-                                  (f16_valid_mantissa_bits <= kF16MantissaBits));
-        TINT_ASSERT(Semantic, (f16_mantissa_part & ~((1u << f16_valid_mantissa_bits) - 1)) == 0);
-        TINT_ASSERT(Semantic, (f16_mantissa_part != 0));
+        TINT_ASSERT((1 <= f16_valid_mantissa_bits) &&
+                    (f16_valid_mantissa_bits <= kF16MantissaBits));
+        TINT_ASSERT((f16_mantissa_part & ~((1u << f16_valid_mantissa_bits) - 1)) == 0);
+        TINT_ASSERT((f16_mantissa_part != 0));
 
         return f16_sign_part | f16_exp_part | f16_mantissa_part;
     }
 
     // Neither zero, subnormal f16 or normal f16, shall never hit.
-    tint::diag::List diag;
-    TINT_UNREACHABLE(Semantic, diag);
+    TINT_UNREACHABLE();
     return kF16Nan;
 }
 
diff --git a/src/tint/lang/core/constant/composite.cc b/src/tint/lang/core/constant/composite.cc
index c1a4dce..735f6b3 100644
--- a/src/tint/lang/core/constant/composite.cc
+++ b/src/tint/lang/core/constant/composite.cc
@@ -27,7 +27,7 @@
                      bool all_0,
                      bool any_0)
     : type(t), elements(std::move(els)), all_zero(all_0), any_zero(any_0), hash(CalcHash()) {
-    TINT_ASSERT(Constant, !elements.IsEmpty());
+    TINT_ASSERT(!elements.IsEmpty());
 }
 
 Composite::~Composite() = default;
diff --git a/src/tint/lang/core/constant/scalar.h b/src/tint/lang/core/constant/scalar.h
index 59ca5d0..4ae023d 100644
--- a/src/tint/lang/core/constant/scalar.h
+++ b/src/tint/lang/core/constant/scalar.h
@@ -43,7 +43,7 @@
     /// @param v the scalar value
     Scalar(const type::Type* t, T v) : type(t), value(v) {
         if constexpr (IsFloatingPoint<T>) {
-            TINT_ASSERT(Constant, std::isfinite(v.value));
+            TINT_ASSERT(std::isfinite(v.value));
         }
     }
     ~Scalar() override = default;
diff --git a/src/tint/lang/core/constant/value.cc b/src/tint/lang/core/constant/value.cc
index ac1954f..6578da3 100644
--- a/src/tint/lang/core/constant/value.cc
+++ b/src/tint/lang/core/constant/value.cc
@@ -96,8 +96,8 @@
         [&](Default) {
             auto va = InternalValue();
             auto vb = b->InternalValue();
-            TINT_ASSERT(Resolver, !std::holds_alternative<std::monostate>(va));
-            TINT_ASSERT(Resolver, !std::holds_alternative<std::monostate>(vb));
+            TINT_ASSERT(!std::holds_alternative<std::monostate>(va));
+            TINT_ASSERT(!std::holds_alternative<std::monostate>(vb));
             return va == vb;
         });
 }
diff --git a/src/tint/lang/core/ir/access.cc b/src/tint/lang/core/ir/access.cc
index 9d73b98..15e567e 100644
--- a/src/tint/lang/core/ir/access.cc
+++ b/src/tint/lang/core/ir/access.cc
@@ -16,8 +16,6 @@
 
 #include <utility>
 
-#include "src/tint/utils/debug/debug.h"
-
 TINT_INSTANTIATE_TYPEINFO(tint::ir::Access);
 
 namespace tint::ir {
diff --git a/src/tint/lang/core/ir/binary.cc b/src/tint/lang/core/ir/binary.cc
index 2669a6f..f64b626 100644
--- a/src/tint/lang/core/ir/binary.cc
+++ b/src/tint/lang/core/ir/binary.cc
@@ -13,7 +13,6 @@
 // limitations under the License.
 
 #include "src/tint/lang/core/ir/binary.h"
-#include "src/tint/utils/debug/debug.h"
 
 TINT_INSTANTIATE_TYPEINFO(tint::ir::Binary);
 
diff --git a/src/tint/lang/core/ir/bitcast.cc b/src/tint/lang/core/ir/bitcast.cc
index 2fbb073..6efa962 100644
--- a/src/tint/lang/core/ir/bitcast.cc
+++ b/src/tint/lang/core/ir/bitcast.cc
@@ -13,7 +13,6 @@
 // limitations under the License.
 
 #include "src/tint/lang/core/ir/bitcast.h"
-#include "src/tint/utils/debug/debug.h"
 
 TINT_INSTANTIATE_TYPEINFO(tint::ir::Bitcast);
 
diff --git a/src/tint/lang/core/ir/block.cc b/src/tint/lang/core/ir/block.cc
index 1d4fb31..a7bc38f 100644
--- a/src/tint/lang/core/ir/block.cc
+++ b/src/tint/lang/core/ir/block.cc
@@ -13,6 +13,7 @@
 // limitations under the License.
 
 #include "src/tint/lang/core/ir/block.h"
+#include "src/tint/utils/ice/ice.h"
 
 TINT_INSTANTIATE_TYPEINFO(tint::ir::Block);
 
@@ -23,8 +24,8 @@
 Block::~Block() = default;
 
 Instruction* Block::Prepend(Instruction* inst) {
-    TINT_ASSERT_OR_RETURN_VALUE(IR, inst, inst);
-    TINT_ASSERT_OR_RETURN_VALUE(IR, inst->Block() == nullptr, inst);
+    TINT_ASSERT_OR_RETURN_VALUE(inst, inst);
+    TINT_ASSERT_OR_RETURN_VALUE(inst->Block() == nullptr, inst);
 
     inst->SetBlock(this);
     instructions_.count += 1;
@@ -42,8 +43,8 @@
 }
 
 Instruction* Block::Append(Instruction* inst) {
-    TINT_ASSERT_OR_RETURN_VALUE(IR, inst, inst);
-    TINT_ASSERT_OR_RETURN_VALUE(IR, inst->Block() == nullptr, inst);
+    TINT_ASSERT_OR_RETURN_VALUE(inst, inst);
+    TINT_ASSERT_OR_RETURN_VALUE(inst->Block() == nullptr, inst);
 
     inst->SetBlock(this);
     instructions_.count += 1;
@@ -61,10 +62,10 @@
 }
 
 void Block::InsertBefore(Instruction* before, Instruction* inst) {
-    TINT_ASSERT_OR_RETURN(IR, before);
-    TINT_ASSERT_OR_RETURN(IR, inst);
-    TINT_ASSERT_OR_RETURN(IR, before->Block() == this);
-    TINT_ASSERT_OR_RETURN(IR, inst->Block() == nullptr);
+    TINT_ASSERT_OR_RETURN(before);
+    TINT_ASSERT_OR_RETURN(inst);
+    TINT_ASSERT_OR_RETURN(before->Block() == this);
+    TINT_ASSERT_OR_RETURN(inst->Block() == nullptr);
 
     inst->SetBlock(this);
     instructions_.count += 1;
@@ -83,10 +84,10 @@
 }
 
 void Block::InsertAfter(Instruction* after, Instruction* inst) {
-    TINT_ASSERT_OR_RETURN(IR, after);
-    TINT_ASSERT_OR_RETURN(IR, inst);
-    TINT_ASSERT_OR_RETURN(IR, after->Block() == this);
-    TINT_ASSERT_OR_RETURN(IR, inst->Block() == nullptr);
+    TINT_ASSERT_OR_RETURN(after);
+    TINT_ASSERT_OR_RETURN(inst);
+    TINT_ASSERT_OR_RETURN(after->Block() == this);
+    TINT_ASSERT_OR_RETURN(inst->Block() == nullptr);
 
     inst->SetBlock(this);
     instructions_.count += 1;
@@ -104,10 +105,10 @@
 }
 
 void Block::Replace(Instruction* target, Instruction* inst) {
-    TINT_ASSERT_OR_RETURN(IR, target);
-    TINT_ASSERT_OR_RETURN(IR, inst);
-    TINT_ASSERT_OR_RETURN(IR, target->Block() == this);
-    TINT_ASSERT_OR_RETURN(IR, inst->Block() == nullptr);
+    TINT_ASSERT_OR_RETURN(target);
+    TINT_ASSERT_OR_RETURN(inst);
+    TINT_ASSERT_OR_RETURN(target->Block() == this);
+    TINT_ASSERT_OR_RETURN(inst->Block() == nullptr);
 
     inst->SetBlock(this);
     target->SetBlock(nullptr);
@@ -134,8 +135,8 @@
 }
 
 void Block::Remove(Instruction* inst) {
-    TINT_ASSERT_OR_RETURN(IR, inst);
-    TINT_ASSERT_OR_RETURN(IR, inst->Block() == this);
+    TINT_ASSERT_OR_RETURN(inst);
+    TINT_ASSERT_OR_RETURN(inst->Block() == this);
 
     inst->SetBlock(nullptr);
     instructions_.count -= 1;
diff --git a/src/tint/lang/core/ir/block_param.cc b/src/tint/lang/core/ir/block_param.cc
index d6c4cd6..46a4070 100644
--- a/src/tint/lang/core/ir/block_param.cc
+++ b/src/tint/lang/core/ir/block_param.cc
@@ -13,13 +13,14 @@
 // limitations under the License.
 
 #include "src/tint/lang/core/ir/block_param.h"
+#include "src/tint/utils/ice/ice.h"
 
 TINT_INSTANTIATE_TYPEINFO(tint::ir::BlockParam);
 
 namespace tint::ir {
 
 BlockParam::BlockParam(const type::Type* ty) : type_(ty) {
-    TINT_ASSERT(IR, type_ != nullptr);
+    TINT_ASSERT(type_ != nullptr);
 }
 
 BlockParam::~BlockParam() = default;
diff --git a/src/tint/lang/core/ir/break_if.cc b/src/tint/lang/core/ir/break_if.cc
index 15cd0f2..5ca3b93 100644
--- a/src/tint/lang/core/ir/break_if.cc
+++ b/src/tint/lang/core/ir/break_if.cc
@@ -19,13 +19,14 @@
 #include "src/tint/lang/core/ir/block.h"
 #include "src/tint/lang/core/ir/loop.h"
 #include "src/tint/lang/core/ir/multi_in_block.h"
+#include "src/tint/utils/ice/ice.h"
 
 TINT_INSTANTIATE_TYPEINFO(tint::ir::BreakIf);
 
 namespace tint::ir {
 
 BreakIf::BreakIf(Value* condition, ir::Loop* loop, VectorRef<Value*> args) : loop_(loop) {
-    TINT_ASSERT(IR, loop_);
+    TINT_ASSERT(loop_);
 
     AddOperand(BreakIf::kConditionOperandOffset, condition);
     AddOperands(BreakIf::kArgsOperandOffset, std::move(args));
diff --git a/src/tint/lang/core/ir/builder.cc b/src/tint/lang/core/ir/builder.cc
index 060a732..d611b12 100644
--- a/src/tint/lang/core/ir/builder.cc
+++ b/src/tint/lang/core/ir/builder.cc
@@ -19,6 +19,7 @@
 #include "src/tint/lang/core/constant/scalar.h"
 #include "src/tint/lang/core/type/pointer.h"
 #include "src/tint/lang/core/type/reference.h"
+#include "src/tint/utils/ice/ice.h"
 
 namespace tint::ir {
 
@@ -107,10 +108,10 @@
 
 const type::Type* Builder::VectorPtrElementType(const type::Type* type) {
     auto* vec_ptr_ty = type->As<type::Pointer>();
-    TINT_ASSERT(IR, vec_ptr_ty);
+    TINT_ASSERT(vec_ptr_ty);
     if (TINT_LIKELY(vec_ptr_ty)) {
         auto* vec_ty = vec_ptr_ty->StoreType()->As<type::Vector>();
-        TINT_ASSERT(IR, vec_ty);
+        TINT_ASSERT(vec_ty);
         if (TINT_LIKELY(vec_ty)) {
             return vec_ty->type();
         }
diff --git a/src/tint/lang/core/ir/builder.h b/src/tint/lang/core/ir/builder.h
index 8f5bfd6..479398e 100644
--- a/src/tint/lang/core/ir/builder.h
+++ b/src/tint/lang/core/ir/builder.h
@@ -65,6 +65,7 @@
 #include "src/tint/lang/core/type/u32.h"
 #include "src/tint/lang/core/type/vector.h"
 #include "src/tint/lang/core/type/void.h"
+#include "src/tint/utils/ice/ice.h"
 #include "src/tint/utils/macros/scoped_assignment.h"
 #include "src/tint/utils/rtti/switch.h"
 
@@ -265,7 +266,7 @@
                 return in;  /// Pass-through
             } else if constexpr (is_instruction) {
                 /// Extract the first result from the instruction
-                TINT_ASSERT(IR, in->HasResults() && !in->HasMultiResults());
+                TINT_ASSERT(in->HasResults() && !in->HasMultiResults());
                 return in->Result();
             }
         } else if constexpr (is_numeric) {
@@ -664,7 +665,7 @@
     ir::Let* Let(std::string_view name, VALUE&& value) {
         auto* val = Value(std::forward<VALUE>(value));
         if (TINT_UNLIKELY(!val)) {
-            TINT_ASSERT(IR, val);
+            TINT_ASSERT(val);
             return nullptr;
         }
         auto* let = Append(ir.instructions.Create<ir::Let>(InstructionResult(val->Type()), val));
diff --git a/src/tint/lang/core/ir/builtin_call.cc b/src/tint/lang/core/ir/builtin_call.cc
index d754f5a..da086cb 100644
--- a/src/tint/lang/core/ir/builtin_call.cc
+++ b/src/tint/lang/core/ir/builtin_call.cc
@@ -16,8 +16,6 @@
 
 #include <utility>
 
-#include "src/tint/utils/debug/debug.h"
-
 TINT_INSTANTIATE_TYPEINFO(tint::ir::BuiltinCall);
 
 namespace tint::ir {
diff --git a/src/tint/lang/core/ir/constant.cc b/src/tint/lang/core/ir/constant.cc
index cf09c50..a161e4d 100644
--- a/src/tint/lang/core/ir/constant.cc
+++ b/src/tint/lang/core/ir/constant.cc
@@ -13,13 +13,14 @@
 // limitations under the License.
 
 #include "src/tint/lang/core/ir/constant.h"
+#include "src/tint/utils/ice/ice.h"
 
 TINT_INSTANTIATE_TYPEINFO(tint::ir::Constant);
 
 namespace tint::ir {
 
 Constant::Constant(const constant::Value* val) : value_(val) {
-    TINT_ASSERT(IR, value_);
+    TINT_ASSERT(value_);
 }
 
 Constant::~Constant() = default;
diff --git a/src/tint/lang/core/ir/construct.cc b/src/tint/lang/core/ir/construct.cc
index 8912359..bbbff97 100644
--- a/src/tint/lang/core/ir/construct.cc
+++ b/src/tint/lang/core/ir/construct.cc
@@ -16,8 +16,6 @@
 
 #include <utility>
 
-#include "src/tint/utils/debug/debug.h"
-
 TINT_INSTANTIATE_TYPEINFO(tint::ir::Construct);
 
 namespace tint::ir {
diff --git a/src/tint/lang/core/ir/continue.cc b/src/tint/lang/core/ir/continue.cc
index ce2c9d0..206b045 100644
--- a/src/tint/lang/core/ir/continue.cc
+++ b/src/tint/lang/core/ir/continue.cc
@@ -19,13 +19,14 @@
 #include "src/tint/lang/core/ir/block.h"
 #include "src/tint/lang/core/ir/loop.h"
 #include "src/tint/lang/core/ir/multi_in_block.h"
+#include "src/tint/utils/ice/ice.h"
 
 TINT_INSTANTIATE_TYPEINFO(tint::ir::Continue);
 
 namespace tint::ir {
 
 Continue::Continue(ir::Loop* loop, VectorRef<Value*> args) : loop_(loop) {
-    TINT_ASSERT(IR, loop_);
+    TINT_ASSERT(loop_);
 
     AddOperands(Continue::kArgsOperandOffset, std::move(args));
 
diff --git a/src/tint/lang/core/ir/convert.cc b/src/tint/lang/core/ir/convert.cc
index 00ba18f..ac55ec5 100644
--- a/src/tint/lang/core/ir/convert.cc
+++ b/src/tint/lang/core/ir/convert.cc
@@ -16,8 +16,6 @@
 
 #include <utility>
 
-#include "src/tint/utils/debug/debug.h"
-
 TINT_INSTANTIATE_TYPEINFO(tint::ir::Convert);
 
 namespace tint::ir {
diff --git a/src/tint/lang/core/ir/core_builtin_call.cc b/src/tint/lang/core/ir/core_builtin_call.cc
index a75c5bc..0f4e45a 100644
--- a/src/tint/lang/core/ir/core_builtin_call.cc
+++ b/src/tint/lang/core/ir/core_builtin_call.cc
@@ -16,7 +16,7 @@
 
 #include <utility>
 
-#include "src/tint/utils/debug/debug.h"
+#include "src/tint/utils/ice/ice.h"
 
 TINT_INSTANTIATE_TYPEINFO(tint::ir::CoreBuiltinCall);
 
@@ -26,8 +26,8 @@
                                  builtin::Function func,
                                  VectorRef<Value*> arguments)
     : Base(result, arguments), func_(func) {
-    TINT_ASSERT(IR, func != builtin::Function::kNone);
-    TINT_ASSERT(IR, func != builtin::Function::kTintMaterialize);
+    TINT_ASSERT(func != builtin::Function::kNone);
+    TINT_ASSERT(func != builtin::Function::kTintMaterialize);
 }
 
 CoreBuiltinCall::~CoreBuiltinCall() = default;
diff --git a/src/tint/lang/core/ir/disassembler.cc b/src/tint/lang/core/ir/disassembler.cc
index 2c06f15..fedf684 100644
--- a/src/tint/lang/core/ir/disassembler.cc
+++ b/src/tint/lang/core/ir/disassembler.cc
@@ -52,6 +52,7 @@
 #include "src/tint/lang/core/ir/var.h"
 #include "src/tint/lang/core/type/struct.h"
 #include "src/tint/lang/core/type/type.h"
+#include "src/tint/utils/ice/ice.h"
 #include "src/tint/utils/macros/scoped_assignment.h"
 #include "src/tint/utils/rtti/switch.h"
 #include "src/tint/utils/text/string.h"
@@ -89,12 +90,12 @@
 }
 
 size_t Disassembler::IdOf(Block* node) {
-    TINT_ASSERT(IR, node);
+    TINT_ASSERT(node);
     return block_ids_.GetOrCreate(node, [&] { return block_ids_.Count(); });
 }
 
 std::string Disassembler::IdOf(Value* value) {
-    TINT_ASSERT(IR, value);
+    TINT_ASSERT(value);
     return value_ids_.GetOrCreate(value, [&] {
         if (auto sym = mod_.NameOf(value)) {
             if (ids_.Add(sym.Name())) {
diff --git a/src/tint/lang/core/ir/discard.cc b/src/tint/lang/core/ir/discard.cc
index c0220e1..27b1a1e 100644
--- a/src/tint/lang/core/ir/discard.cc
+++ b/src/tint/lang/core/ir/discard.cc
@@ -14,7 +14,6 @@
 
 #include "src/tint/lang/core/ir/discard.h"
 #include "src/tint/lang/core/type/void.h"
-#include "src/tint/utils/debug/debug.h"
 
 TINT_INSTANTIATE_TYPEINFO(tint::ir::Discard);
 
diff --git a/src/tint/lang/core/ir/discard.h b/src/tint/lang/core/ir/discard.h
index 5d9b4e8..9ae20d8 100644
--- a/src/tint/lang/core/ir/discard.h
+++ b/src/tint/lang/core/ir/discard.h
@@ -16,7 +16,7 @@
 #define SRC_TINT_LANG_CORE_IR_DISCARD_H_
 
 #include "src/tint/lang/core/ir/call.h"
-#include "src/tint/utils/debug/debug.h"
+
 #include "src/tint/utils/rtti/castable.h"
 
 namespace tint::ir {
diff --git a/src/tint/lang/core/ir/function.cc b/src/tint/lang/core/ir/function.cc
index 98754b8..408daf8 100644
--- a/src/tint/lang/core/ir/function.cc
+++ b/src/tint/lang/core/ir/function.cc
@@ -15,6 +15,7 @@
 #include "src/tint/lang/core/ir/function.h"
 
 #include "src/tint/utils/containers/predicates.h"
+#include "src/tint/utils/ice/ice.h"
 
 TINT_INSTANTIATE_TYPEINFO(tint::ir::Function);
 
@@ -24,7 +25,7 @@
                    PipelineStage stage,
                    std::optional<std::array<uint32_t, 3>> wg_size)
     : pipeline_stage_(stage), workgroup_size_(wg_size) {
-    TINT_ASSERT(IR, rt != nullptr);
+    TINT_ASSERT(rt != nullptr);
 
     return_.type = rt;
 }
@@ -33,12 +34,12 @@
 
 void Function::SetParams(VectorRef<FunctionParam*> params) {
     params_ = std::move(params);
-    TINT_ASSERT(IR, !params_.Any(tint::IsNull));
+    TINT_ASSERT(!params_.Any(IsNull));
 }
 
 void Function::SetParams(std::initializer_list<FunctionParam*> params) {
     params_ = params;
-    TINT_ASSERT(IR, !params_.Any(tint::IsNull));
+    TINT_ASSERT(!params_.Any(IsNull));
 }
 
 StringStream& operator<<(StringStream& out, Function::PipelineStage value) {
diff --git a/src/tint/lang/core/ir/function.h b/src/tint/lang/core/ir/function.h
index 143efe0..660440f 100644
--- a/src/tint/lang/core/ir/function.h
+++ b/src/tint/lang/core/ir/function.h
@@ -23,6 +23,7 @@
 #include "src/tint/lang/core/ir/location.h"
 #include "src/tint/lang/core/ir/value.h"
 #include "src/tint/lang/core/type/type.h"
+#include "src/tint/utils/ice/ice.h"
 
 // Forward declarations
 namespace tint::ir {
@@ -91,7 +92,7 @@
     /// Sets the return attributes
     /// @param builtin the builtin to set
     void SetReturnBuiltin(ReturnBuiltin builtin) {
-        TINT_ASSERT(IR, !return_.builtin.has_value());
+        TINT_ASSERT(!return_.builtin.has_value());
         return_.builtin = builtin;
     }
     /// @returns the return builtin attribute
@@ -130,7 +131,7 @@
     /// Sets the root block for the function
     /// @param target the root block
     void SetBlock(Block* target) {
-        TINT_ASSERT(IR, target != nullptr);
+        TINT_ASSERT(target != nullptr);
         block_ = target;
     }
     /// @returns the function root block
diff --git a/src/tint/lang/core/ir/function_param.cc b/src/tint/lang/core/ir/function_param.cc
index 492522e..1dc8930 100644
--- a/src/tint/lang/core/ir/function_param.cc
+++ b/src/tint/lang/core/ir/function_param.cc
@@ -14,12 +14,14 @@
 
 #include "src/tint/lang/core/ir/function_param.h"
 
+#include "src/tint/utils/ice/ice.h"
+
 TINT_INSTANTIATE_TYPEINFO(tint::ir::FunctionParam);
 
 namespace tint::ir {
 
 FunctionParam::FunctionParam(const type::Type* ty) : type_(ty) {
-    TINT_ASSERT(IR, ty != nullptr);
+    TINT_ASSERT(ty != nullptr);
 }
 
 FunctionParam::~FunctionParam() = default;
diff --git a/src/tint/lang/core/ir/function_param.h b/src/tint/lang/core/ir/function_param.h
index e4edabc..44ad9a5 100644
--- a/src/tint/lang/core/ir/function_param.h
+++ b/src/tint/lang/core/ir/function_param.h
@@ -21,6 +21,7 @@
 #include "src/tint/lang/core/ir/location.h"
 #include "src/tint/lang/core/ir/value.h"
 #include "src/tint/utils/containers/vector.h"
+#include "src/tint/utils/ice/ice.h"
 #include "src/tint/utils/rtti/castable.h"
 
 namespace tint::ir {
@@ -65,7 +66,7 @@
     /// Sets the builtin information. Note, it is currently an error if the builtin is already set.
     /// @param val the builtin to set
     void SetBuiltin(FunctionParam::Builtin val) {
-        TINT_ASSERT(IR, !builtin_.has_value());
+        TINT_ASSERT(!builtin_.has_value());
         builtin_ = val;
     }
     /// @returns the builtin set for the parameter
diff --git a/src/tint/lang/core/ir/if.cc b/src/tint/lang/core/ir/if.cc
index e080712..372039f 100644
--- a/src/tint/lang/core/ir/if.cc
+++ b/src/tint/lang/core/ir/if.cc
@@ -17,12 +17,13 @@
 TINT_INSTANTIATE_TYPEINFO(tint::ir::If);
 
 #include "src/tint/lang/core/ir/multi_in_block.h"
+#include "src/tint/utils/ice/ice.h"
 
 namespace tint::ir {
 
 If::If(Value* cond, ir::Block* t, ir::Block* f) : true_(t), false_(f) {
-    TINT_ASSERT(IR, true_);
-    TINT_ASSERT(IR, false_);
+    TINT_ASSERT(true_);
+    TINT_ASSERT(false_);
 
     AddOperand(If::kConditionOperandOffset, cond);
 
diff --git a/src/tint/lang/core/ir/instruction.cc b/src/tint/lang/core/ir/instruction.cc
index 85e8aa7..feb7a58 100644
--- a/src/tint/lang/core/ir/instruction.cc
+++ b/src/tint/lang/core/ir/instruction.cc
@@ -15,7 +15,7 @@
 #include "src/tint/lang/core/ir/instruction.h"
 
 #include "src/tint/lang/core/ir/block.h"
-#include "src/tint/utils/debug/debug.h"
+#include "src/tint/utils/ice/ice.h"
 
 TINT_INSTANTIATE_TYPEINFO(tint::ir::Instruction);
 
@@ -26,7 +26,7 @@
 Instruction::~Instruction() = default;
 
 void Instruction::Destroy() {
-    TINT_ASSERT(IR, Alive());
+    TINT_ASSERT(Alive());
     if (Block()) {
         Remove();
     }
@@ -38,25 +38,25 @@
 }
 
 void Instruction::InsertBefore(Instruction* before) {
-    TINT_ASSERT_OR_RETURN(IR, before);
-    TINT_ASSERT_OR_RETURN(IR, before->Block() != nullptr);
+    TINT_ASSERT_OR_RETURN(before);
+    TINT_ASSERT_OR_RETURN(before->Block() != nullptr);
     before->Block()->InsertBefore(before, this);
 }
 
 void Instruction::InsertAfter(Instruction* after) {
-    TINT_ASSERT_OR_RETURN(IR, after);
-    TINT_ASSERT_OR_RETURN(IR, after->Block() != nullptr);
+    TINT_ASSERT_OR_RETURN(after);
+    TINT_ASSERT_OR_RETURN(after->Block() != nullptr);
     after->Block()->InsertAfter(after, this);
 }
 
 void Instruction::ReplaceWith(Instruction* replacement) {
-    TINT_ASSERT_OR_RETURN(IR, replacement);
-    TINT_ASSERT_OR_RETURN(IR, Block() != nullptr);
+    TINT_ASSERT_OR_RETURN(replacement);
+    TINT_ASSERT_OR_RETURN(Block() != nullptr);
     Block()->Replace(this, replacement);
 }
 
 void Instruction::Remove() {
-    TINT_ASSERT_OR_RETURN(IR, Block() != nullptr);
+    TINT_ASSERT_OR_RETURN(Block() != nullptr);
     Block()->Remove(this);
 }
 
diff --git a/src/tint/lang/core/ir/instruction_result.cc b/src/tint/lang/core/ir/instruction_result.cc
index 20a4674..300eca3 100644
--- a/src/tint/lang/core/ir/instruction_result.cc
+++ b/src/tint/lang/core/ir/instruction_result.cc
@@ -16,19 +16,20 @@
 
 #include "src/tint/lang/core/ir/constant.h"
 #include "src/tint/lang/core/ir/instruction.h"
+#include "src/tint/utils/ice/ice.h"
 
 TINT_INSTANTIATE_TYPEINFO(tint::ir::InstructionResult);
 
 namespace tint::ir {
 
 InstructionResult::InstructionResult(const type::Type* type) : type_(type) {
-    TINT_ASSERT(IR, type_ != nullptr);
+    TINT_ASSERT(type_ != nullptr);
 }
 
 InstructionResult::~InstructionResult() = default;
 
 void InstructionResult::Destroy() {
-    TINT_ASSERT(IR, source_ == nullptr);
+    TINT_ASSERT(source_ == nullptr);
     Base::Destroy();
 }
 
diff --git a/src/tint/lang/core/ir/intrinsic_call.cc b/src/tint/lang/core/ir/intrinsic_call.cc
index ee52c23..5ab9663 100644
--- a/src/tint/lang/core/ir/intrinsic_call.cc
+++ b/src/tint/lang/core/ir/intrinsic_call.cc
@@ -16,8 +16,6 @@
 
 #include <utility>
 
-#include "src/tint/utils/debug/debug.h"
-
 TINT_INSTANTIATE_TYPEINFO(tint::ir::IntrinsicCall);
 
 namespace tint::ir {
diff --git a/src/tint/lang/core/ir/let.cc b/src/tint/lang/core/ir/let.cc
index b489fc1..7309786 100644
--- a/src/tint/lang/core/ir/let.cc
+++ b/src/tint/lang/core/ir/let.cc
@@ -14,7 +14,6 @@
 
 #include "src/tint/lang/core/ir/let.h"
 #include "src/tint/lang/core/ir/store.h"
-#include "src/tint/utils/debug/debug.h"
 
 TINT_INSTANTIATE_TYPEINFO(tint::ir::Let);
 
diff --git a/src/tint/lang/core/ir/load.cc b/src/tint/lang/core/ir/load.cc
index 00a03f5..3ed33f1 100644
--- a/src/tint/lang/core/ir/load.cc
+++ b/src/tint/lang/core/ir/load.cc
@@ -15,7 +15,7 @@
 #include "src/tint/lang/core/ir/load.h"
 
 #include "src/tint/lang/core/type/pointer.h"
-#include "src/tint/utils/debug/debug.h"
+#include "src/tint/utils/ice/ice.h"
 
 TINT_INSTANTIATE_TYPEINFO(tint::ir::Load);
 
@@ -24,8 +24,8 @@
 Load::Load(InstructionResult* result, Value* from) {
     flags_.Add(Flag::kSequenced);
 
-    TINT_ASSERT(IR, from->Type()->Is<type::Pointer>());
-    TINT_ASSERT(IR, from && from->Type()->UnwrapPtr() == result->Type());
+    TINT_ASSERT(from->Type()->Is<type::Pointer>());
+    TINT_ASSERT(from && from->Type()->UnwrapPtr() == result->Type());
 
     AddOperand(Load::kFromOperandOffset, from);
     AddResult(result);
diff --git a/src/tint/lang/core/ir/load_vector_element.cc b/src/tint/lang/core/ir/load_vector_element.cc
index aad4f47..eb1669e 100644
--- a/src/tint/lang/core/ir/load_vector_element.cc
+++ b/src/tint/lang/core/ir/load_vector_element.cc
@@ -13,7 +13,6 @@
 // limitations under the License.
 
 #include "src/tint/lang/core/ir/load_vector_element.h"
-#include "src/tint/utils/debug/debug.h"
 
 TINT_INSTANTIATE_TYPEINFO(tint::ir::LoadVectorElement);
 
diff --git a/src/tint/lang/core/ir/loop.cc b/src/tint/lang/core/ir/loop.cc
index 81d9def..001a270 100644
--- a/src/tint/lang/core/ir/loop.cc
+++ b/src/tint/lang/core/ir/loop.cc
@@ -17,6 +17,7 @@
 #include <utility>
 
 #include "src/tint/lang/core/ir/multi_in_block.h"
+#include "src/tint/utils/ice/ice.h"
 
 TINT_INSTANTIATE_TYPEINFO(tint::ir::Loop);
 
@@ -24,9 +25,9 @@
 
 Loop::Loop(ir::Block* i, ir::MultiInBlock* b, ir::MultiInBlock* c)
     : initializer_(i), body_(b), continuing_(c) {
-    TINT_ASSERT(IR, initializer_);
-    TINT_ASSERT(IR, body_);
-    TINT_ASSERT(IR, continuing_);
+    TINT_ASSERT(initializer_);
+    TINT_ASSERT(body_);
+    TINT_ASSERT(continuing_);
 
     if (initializer_) {
         initializer_->SetParent(this);
diff --git a/src/tint/lang/core/ir/module.cc b/src/tint/lang/core/ir/module.cc
index 0c5da05..c7bc576 100644
--- a/src/tint/lang/core/ir/module.cc
+++ b/src/tint/lang/core/ir/module.cc
@@ -16,6 +16,8 @@
 
 #include <limits>
 
+#include "src/tint/utils/ice/ice.h"
+
 namespace tint::ir {
 
 Module::Module() = default;
@@ -27,7 +29,7 @@
 Module& Module::operator=(Module&&) = default;
 
 Symbol Module::NameOf(Instruction* inst) {
-    TINT_ASSERT(IR, inst->HasResults() && !inst->HasMultiResults());
+    TINT_ASSERT(inst->HasResults() && !inst->HasMultiResults());
     return NameOf(inst->Result());
 }
 
@@ -36,17 +38,17 @@
 }
 
 void Module::SetName(Instruction* inst, std::string_view name) {
-    TINT_ASSERT(IR, inst->HasResults() && !inst->HasMultiResults());
+    TINT_ASSERT(inst->HasResults() && !inst->HasMultiResults());
     return SetName(inst->Result(), name);
 }
 
 void Module::SetName(Value* value, std::string_view name) {
-    TINT_ASSERT(IR, !name.empty());
+    TINT_ASSERT(!name.empty());
     value_to_name_.Replace(value, symbols.Register(name));
 }
 
 void Module::SetName(Value* value, Symbol name) {
-    TINT_ASSERT(IR, name.IsValid());
+    TINT_ASSERT(name.IsValid());
     value_to_name_.Replace(value, name);
 }
 
diff --git a/src/tint/lang/core/ir/module.h b/src/tint/lang/core/ir/module.h
index df39ff9..1ae271e 100644
--- a/src/tint/lang/core/ir/module.h
+++ b/src/tint/lang/core/ir/module.h
@@ -26,6 +26,7 @@
 #include "src/tint/lang/core/ir/value.h"
 #include "src/tint/lang/core/type/manager.h"
 #include "src/tint/utils/containers/vector.h"
+#include "src/tint/utils/diagnostic/source.h"
 #include "src/tint/utils/generation_id.h"
 #include "src/tint/utils/memory/block_allocator.h"
 #include "src/tint/utils/result/result.h"
diff --git a/src/tint/lang/core/ir/multi_in_block.cc b/src/tint/lang/core/ir/multi_in_block.cc
index 615876c..3753feb 100644
--- a/src/tint/lang/core/ir/multi_in_block.cc
+++ b/src/tint/lang/core/ir/multi_in_block.cc
@@ -15,6 +15,7 @@
 #include "src/tint/lang/core/ir/multi_in_block.h"
 
 #include "src/tint/utils/containers/predicates.h"
+#include "src/tint/utils/ice/ice.h"
 
 TINT_INSTANTIATE_TYPEINFO(tint::ir::MultiInBlock);
 
@@ -33,7 +34,7 @@
 }
 
 void MultiInBlock::AddInboundSiblingBranch(ir::Terminator* node) {
-    TINT_ASSERT(IR, node != nullptr);
+    TINT_ASSERT(node != nullptr);
 
     if (node) {
         inbound_sibling_branches_.Push(node);
diff --git a/src/tint/lang/core/ir/next_iteration.cc b/src/tint/lang/core/ir/next_iteration.cc
index 797cd0c..a7d9faf 100644
--- a/src/tint/lang/core/ir/next_iteration.cc
+++ b/src/tint/lang/core/ir/next_iteration.cc
@@ -18,6 +18,7 @@
 
 #include "src/tint/lang/core/ir/loop.h"
 #include "src/tint/lang/core/ir/multi_in_block.h"
+#include "src/tint/utils/ice/ice.h"
 
 TINT_INSTANTIATE_TYPEINFO(tint::ir::NextIteration);
 
@@ -25,7 +26,7 @@
 
 NextIteration::NextIteration(ir::Loop* loop, VectorRef<Value*> args /* = tint::Empty */)
     : loop_(loop) {
-    TINT_ASSERT(IR, loop_);
+    TINT_ASSERT(loop_);
 
     AddOperands(NextIteration::kArgsOperandOffset, std::move(args));
 
diff --git a/src/tint/lang/core/ir/operand_instruction.h b/src/tint/lang/core/ir/operand_instruction.h
index d6fd4bb..abc81e3 100644
--- a/src/tint/lang/core/ir/operand_instruction.h
+++ b/src/tint/lang/core/ir/operand_instruction.h
@@ -19,6 +19,7 @@
 
 #include "src/tint/lang/core/ir/instruction.h"
 #include "src/tint/lang/core/ir/instruction_result.h"
+#include "src/tint/utils/ice/ice.h"
 
 namespace tint::ir {
 
@@ -41,7 +42,7 @@
     /// @param index the operand index
     /// @param value the value to use
     void SetOperand(size_t index, ir::Value* value) override {
-        TINT_ASSERT(IR, index < operands_.Length());
+        TINT_ASSERT(index < operands_.Length());
         if (operands_[index]) {
             operands_[index]->RemoveUsage({this, index});
         }
@@ -101,7 +102,7 @@
     /// @param idx the index the operand should be at
     /// @param value the operand value to append
     void AddOperand(size_t idx, ir::Value* value) {
-        TINT_ASSERT(IR, idx == operands_.Length());
+        TINT_ASSERT(idx == operands_.Length());
 
         if (value) {
             value->AddUsage({this, static_cast<uint32_t>(operands_.Length())});
diff --git a/src/tint/lang/core/ir/store.cc b/src/tint/lang/core/ir/store.cc
index e4f7ce2..648e9f2 100644
--- a/src/tint/lang/core/ir/store.cc
+++ b/src/tint/lang/core/ir/store.cc
@@ -13,7 +13,6 @@
 // limitations under the License.
 
 #include "src/tint/lang/core/ir/store.h"
-#include "src/tint/utils/debug/debug.h"
 
 TINT_INSTANTIATE_TYPEINFO(tint::ir::Store);
 
diff --git a/src/tint/lang/core/ir/store_vector_element.cc b/src/tint/lang/core/ir/store_vector_element.cc
index 5cbb108..219ded3 100644
--- a/src/tint/lang/core/ir/store_vector_element.cc
+++ b/src/tint/lang/core/ir/store_vector_element.cc
@@ -13,7 +13,6 @@
 // limitations under the License.
 
 #include "src/tint/lang/core/ir/store_vector_element.h"
-#include "src/tint/utils/debug/debug.h"
 
 TINT_INSTANTIATE_TYPEINFO(tint::ir::StoreVectorElement);
 
diff --git a/src/tint/lang/core/ir/switch.cc b/src/tint/lang/core/ir/switch.cc
index 4f1c5b2..bda068f 100644
--- a/src/tint/lang/core/ir/switch.cc
+++ b/src/tint/lang/core/ir/switch.cc
@@ -14,12 +14,14 @@
 
 #include "src/tint/lang/core/ir/switch.h"
 
+#include "src/tint/utils/ice/ice.h"
+
 TINT_INSTANTIATE_TYPEINFO(tint::ir::Switch);
 
 namespace tint::ir {
 
 Switch::Switch(Value* cond) {
-    TINT_ASSERT(IR, cond);
+    TINT_ASSERT(cond);
 
     AddOperand(Switch::kConditionOperandOffset, cond);
 }
diff --git a/src/tint/lang/core/ir/swizzle.cc b/src/tint/lang/core/ir/swizzle.cc
index b81fab8..83361a5 100644
--- a/src/tint/lang/core/ir/swizzle.cc
+++ b/src/tint/lang/core/ir/swizzle.cc
@@ -16,7 +16,7 @@
 
 #include <utility>
 
-#include "src/tint/utils/debug/debug.h"
+#include "src/tint/utils/ice/ice.h"
 
 TINT_INSTANTIATE_TYPEINFO(tint::ir::Swizzle);
 
@@ -24,14 +24,14 @@
 
 Swizzle::Swizzle(InstructionResult* result, Value* object, VectorRef<uint32_t> indices)
     : indices_(std::move(indices)) {
-    TINT_ASSERT(IR, !indices.IsEmpty());
-    TINT_ASSERT(IR, indices.Length() <= 4);
+    TINT_ASSERT(!indices.IsEmpty());
+    TINT_ASSERT(indices.Length() <= 4);
 
     AddOperand(Swizzle::kObjectOperandOffset, object);
     AddResult(result);
 
     for (auto idx : indices_) {
-        TINT_ASSERT(IR, idx < 4);
+        TINT_ASSERT(idx < 4);
     }
 }
 
diff --git a/src/tint/lang/core/ir/transform/builtin_polyfill_spirv.cc b/src/tint/lang/core/ir/transform/builtin_polyfill_spirv.cc
index 99079b9..926045e 100644
--- a/src/tint/lang/core/ir/transform/builtin_polyfill_spirv.cc
+++ b/src/tint/lang/core/ir/transform/builtin_polyfill_spirv.cc
@@ -26,6 +26,7 @@
 #include "src/tint/lang/core/type/sampled_texture.h"
 #include "src/tint/lang/core/type/storage_texture.h"
 #include "src/tint/lang/core/type/texture.h"
+#include "src/tint/utils/ice/ice.h"
 
 TINT_INSTANTIATE_TYPEINFO(tint::ir::transform::BuiltinPolyfillSpirv);
 TINT_INSTANTIATE_TYPEINFO(tint::ir::transform::BuiltinPolyfillSpirv::LiteralOperand);
@@ -147,7 +148,7 @@
                 default:
                     break;
             }
-            TINT_ASSERT_OR_RETURN(Transform, replacement);
+            TINT_ASSERT_OR_RETURN(replacement);
 
             // Replace the old builtin result with the new value.
             if (auto name = ir->NameOf(builtin->Result())) {
@@ -174,13 +175,13 @@
         while (auto* let = tint::As<Let>(ptr->Source())) {
             ptr = let->Value()->As<InstructionResult>();
         }
-        TINT_ASSERT_OR_RETURN_VALUE(Transform, ptr, nullptr);
+        TINT_ASSERT_OR_RETURN_VALUE(ptr, nullptr);
 
         auto* access = ptr->Source()->As<Access>();
-        TINT_ASSERT_OR_RETURN_VALUE(Transform, access, nullptr);
-        TINT_ASSERT_OR_RETURN_VALUE(Transform, access->Indices().Length() == 1u, nullptr);
-        TINT_ASSERT_OR_RETURN_VALUE(
-            Transform, access->Object()->Type()->UnwrapPtr()->Is<type::Struct>(), nullptr);
+        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<type::Struct>(),
+                                    nullptr);
         auto* const_idx = access->Indices()[0]->As<Constant>();
 
         // Replace the builtin call with a call to the spirv.array_length intrinsic.
@@ -205,7 +206,7 @@
                 case builtin::AddressSpace::kStorage:
                     return b.Constant(u32(SpvScopeDevice));
                 default:
-                    TINT_ASSERT(Transform, false && "unhandled atomic address space");
+                    TINT_UNREACHABLE() << "unhandled atomic address space";
                     return nullptr;
             }
         }();
diff --git a/src/tint/lang/core/ir/transform/demote_to_helper.cc b/src/tint/lang/core/ir/transform/demote_to_helper.cc
index ce8aec4b..335ce09 100644
--- a/src/tint/lang/core/ir/transform/demote_to_helper.cc
+++ b/src/tint/lang/core/ir/transform/demote_to_helper.cc
@@ -18,6 +18,7 @@
 
 #include "src/tint/lang/core/ir/builder.h"
 #include "src/tint/lang/core/ir/module.h"
+#include "src/tint/utils/ice/ice.h"
 
 TINT_INSTANTIATE_TYPEINFO(tint::ir::transform::DemoteToHelper);
 
@@ -140,7 +141,7 @@
             // Move the original instruction into the if-true block.
             auto* result = ifelse->True()->Append(inst);
 
-            TINT_ASSERT(Transform, !inst->HasMultiResults());
+            TINT_ASSERT(!inst->HasMultiResults());
             if (inst->HasResults() && !inst->Result()->Type()->Is<type::Void>()) {
                 // The original instruction had a result, so return it from the if instruction.
                 ifelse->SetResults(Vector{b.InstructionResult(inst->Result()->Type())});
diff --git a/src/tint/lang/core/ir/transform/expand_implicit_splats.cc b/src/tint/lang/core/ir/transform/expand_implicit_splats.cc
index b8faedf..81eb5a6 100644
--- a/src/tint/lang/core/ir/transform/expand_implicit_splats.cc
+++ b/src/tint/lang/core/ir/transform/expand_implicit_splats.cc
@@ -123,7 +123,7 @@
                 expand_operand(builtin, CoreBuiltinCall::kArgsOperandOffset + 2);
                 break;
             default:
-                TINT_ASSERT(Transform, false && "unhandled builtin call");
+                TINT_UNREACHABLE() << "unhandled builtin call";
                 break;
         }
     }
diff --git a/src/tint/lang/core/ir/transform/handle_matrix_arithmetic.cc b/src/tint/lang/core/ir/transform/handle_matrix_arithmetic.cc
index 423d660..40d2190 100644
--- a/src/tint/lang/core/ir/transform/handle_matrix_arithmetic.cc
+++ b/src/tint/lang/core/ir/transform/handle_matrix_arithmetic.cc
@@ -19,6 +19,7 @@
 #include "src/tint/lang/core/ir/builder.h"
 #include "src/tint/lang/core/ir/module.h"
 #include "src/tint/lang/core/type/matrix.h"
+#include "src/tint/utils/ice/ice.h"
 
 TINT_INSTANTIATE_TYPEINFO(tint::ir::transform::HandleMatrixArithmetic);
 
@@ -41,7 +42,7 @@
             continue;
         }
         if (auto* binary = inst->As<Binary>()) {
-            TINT_ASSERT(Transform, binary->Operands().Length() == 2);
+            TINT_ASSERT(binary->Operands().Length() == 2);
             if (binary->LHS()->Type()->Is<type::Matrix>() ||
                 binary->RHS()->Type()->Is<type::Matrix>()) {
                 binary_worklist.Push(binary);
@@ -113,7 +114,7 @@
                 break;
 
             default:
-                TINT_ASSERT(Transform, false && "unhandled matrix arithmetic instruction");
+                TINT_UNREACHABLE() << "unhandled matrix arithmetic instruction";
                 break;
         }
     }
diff --git a/src/tint/lang/core/ir/unary.cc b/src/tint/lang/core/ir/unary.cc
index 41a9aaa..5f83962 100644
--- a/src/tint/lang/core/ir/unary.cc
+++ b/src/tint/lang/core/ir/unary.cc
@@ -13,7 +13,6 @@
 // limitations under the License.
 
 #include "src/tint/lang/core/ir/unary.h"
-#include "src/tint/utils/debug/debug.h"
 
 TINT_INSTANTIATE_TYPEINFO(tint::ir::Unary);
 
diff --git a/src/tint/lang/core/ir/user_call.cc b/src/tint/lang/core/ir/user_call.cc
index 01e7f91..11f791a 100644
--- a/src/tint/lang/core/ir/user_call.cc
+++ b/src/tint/lang/core/ir/user_call.cc
@@ -16,8 +16,6 @@
 
 #include <utility>
 
-#include "src/tint/utils/debug/debug.h"
-
 TINT_INSTANTIATE_TYPEINFO(tint::ir::UserCall);
 
 namespace tint::ir {
diff --git a/src/tint/lang/core/ir/value.cc b/src/tint/lang/core/ir/value.cc
index 4353ab6..3677d9e 100644
--- a/src/tint/lang/core/ir/value.cc
+++ b/src/tint/lang/core/ir/value.cc
@@ -16,6 +16,7 @@
 
 #include "src/tint/lang/core/ir/constant.h"
 #include "src/tint/lang/core/ir/instruction.h"
+#include "src/tint/utils/ice/ice.h"
 
 TINT_INSTANTIATE_TYPEINFO(tint::ir::Value);
 
@@ -26,8 +27,8 @@
 Value::~Value() = default;
 
 void Value::Destroy() {
-    TINT_ASSERT(IR, Alive());
-    TINT_ASSERT(IR, Usages().Count() == 0);
+    TINT_ASSERT(Alive());
+    TINT_ASSERT(Usages().Count() == 0);
     flags_.Add(Flag::kDead);
 }
 
diff --git a/src/tint/lang/core/ir/var.cc b/src/tint/lang/core/ir/var.cc
index 0609fd0..3bf295c 100644
--- a/src/tint/lang/core/ir/var.cc
+++ b/src/tint/lang/core/ir/var.cc
@@ -13,8 +13,9 @@
 // limitations under the License.
 
 #include "src/tint/lang/core/ir/var.h"
+
 #include "src/tint/lang/core/ir/store.h"
-#include "src/tint/utils/debug/debug.h"
+#include "src/tint/utils/ice/ice.h"
 
 TINT_INSTANTIATE_TYPEINFO(tint::ir::Var);
 
@@ -22,7 +23,7 @@
 
 Var::Var(InstructionResult* result) {
     if (result && result->Type()) {
-        TINT_ASSERT(IR, result->Type()->Is<type::Pointer>());
+        TINT_ASSERT(result->Type()->Is<type::Pointer>());
     }
 
     // Default to no initializer.
diff --git a/src/tint/lang/core/type/array.cc b/src/tint/lang/core/type/array.cc
index 4d2d81c..a3831a4 100644
--- a/src/tint/lang/core/type/array.cc
+++ b/src/tint/lang/core/type/array.cc
@@ -18,7 +18,7 @@
 
 #include "src/tint/lang/core/type/manager.h"
 #include "src/tint/lang/core/type/texture_dimension.h"
-#include "src/tint/utils/debug/debug.h"
+#include "src/tint/utils/ice/ice.h"
 #include "src/tint/utils/math/hash.h"
 #include "src/tint/utils/text/string_stream.h"
 #include "src/tint/utils/text/symbol_table.h"
@@ -68,7 +68,7 @@
       size_(size),
       stride_(stride),
       implicit_stride_(implicit_stride) {
-    TINT_ASSERT(Type, element_);
+    TINT_ASSERT(element_);
 }
 
 bool Array::Equals(const UniqueNode& other) const {
diff --git a/src/tint/lang/core/type/atomic.cc b/src/tint/lang/core/type/atomic.cc
index 1ab17f4..4ff5607 100644
--- a/src/tint/lang/core/type/atomic.cc
+++ b/src/tint/lang/core/type/atomic.cc
@@ -16,8 +16,8 @@
 
 #include "src/tint/lang/core/type/manager.h"
 #include "src/tint/lang/core/type/reference.h"
-#include "src/tint/utils/debug/debug.h"
 #include "src/tint/utils/diagnostic/diagnostic.h"
+#include "src/tint/utils/ice/ice.h"
 #include "src/tint/utils/math/hash.h"
 #include "src/tint/utils/text/string_stream.h"
 
@@ -32,7 +32,7 @@
                Flag::kFixedFootprint,
            }),
       subtype_(subtype) {
-    TINT_ASSERT(AST, !subtype->Is<Reference>());
+    TINT_ASSERT(!subtype->Is<Reference>());
 }
 
 bool Atomic::Equals(const type::UniqueNode& other) const {
diff --git a/src/tint/lang/core/type/builtin_structs.cc b/src/tint/lang/core/type/builtin_structs.cc
index c3d381e..c3fbbc0 100644
--- a/src/tint/lang/core/type/builtin_structs.cc
+++ b/src/tint/lang/core/type/builtin_structs.cc
@@ -81,12 +81,12 @@
                     return abstract;
                 },
                 [&](Default) {
-                    TINT_ASSERT(Builtin, false && "unhandled modf type");
+                    TINT_UNREACHABLE() << "unhandled modf type";
                     return nullptr;
                 });
         },
         [&](Default) {
-            TINT_ASSERT(Builtin, false && "unhandled modf type");
+            TINT_UNREACHABLE() << "unhandled modf type";
             return nullptr;
         });
 }
@@ -147,12 +147,12 @@
                     return abstract;
                 },
                 [&](Default) {
-                    TINT_ASSERT(Builtin, false && "unhandled frexp type");
+                    TINT_UNREACHABLE() << "unhandled frexp type";
                     return nullptr;
                 });
         },
         [&](Default) {
-            TINT_ASSERT(Builtin, false && "unhandled frexp type");
+            TINT_UNREACHABLE() << "unhandled frexp type";
             return nullptr;
         });
 }
@@ -170,7 +170,7 @@
         [&](const I32*) { return build(builtin::Builtin::kAtomicCompareExchangeResultI32); },
         [&](const U32*) { return build(builtin::Builtin::kAtomicCompareExchangeResultU32); },
         [&](Default) {
-            TINT_ASSERT(Builtin, false && "unhandled atomic_compare_exchange type");
+            TINT_UNREACHABLE() << "unhandled atomic_compare_exchange type";
             return nullptr;
         });
 }
diff --git a/src/tint/lang/core/type/depth_multisampled_texture.cc b/src/tint/lang/core/type/depth_multisampled_texture.cc
index 386ff3d..71983b9 100644
--- a/src/tint/lang/core/type/depth_multisampled_texture.cc
+++ b/src/tint/lang/core/type/depth_multisampled_texture.cc
@@ -16,8 +16,8 @@
 
 #include "src/tint/lang/core/type/manager.h"
 #include "src/tint/lang/core/type/texture_dimension.h"
-#include "src/tint/utils/debug/debug.h"
 #include "src/tint/utils/diagnostic/diagnostic.h"
+#include "src/tint/utils/ice/ice.h"
 #include "src/tint/utils/math/hash.h"
 #include "src/tint/utils/text/string_stream.h"
 
@@ -33,8 +33,8 @@
 }  // namespace
 
 DepthMultisampledTexture::DepthMultisampledTexture(TextureDimension dim)
-    : Base(Hash(tint::TypeInfo::Of<DepthMultisampledTexture>().full_hashcode, dim), dim) {
-    TINT_ASSERT(Type, IsValidDepthDimension(dim));
+    : Base(Hash(TypeInfo::Of<DepthMultisampledTexture>().full_hashcode, dim), dim) {
+    TINT_ASSERT(IsValidDepthDimension(dim));
 }
 
 DepthMultisampledTexture::~DepthMultisampledTexture() = default;
diff --git a/src/tint/lang/core/type/depth_texture.cc b/src/tint/lang/core/type/depth_texture.cc
index f4f989a..973bb56 100644
--- a/src/tint/lang/core/type/depth_texture.cc
+++ b/src/tint/lang/core/type/depth_texture.cc
@@ -16,8 +16,8 @@
 
 #include "src/tint/lang/core/type/manager.h"
 #include "src/tint/lang/core/type/texture_dimension.h"
-#include "src/tint/utils/debug/debug.h"
 #include "src/tint/utils/diagnostic/diagnostic.h"
+#include "src/tint/utils/ice/ice.h"
 #include "src/tint/utils/math/hash.h"
 #include "src/tint/utils/text/string_stream.h"
 
@@ -34,8 +34,8 @@
 }  // namespace
 
 DepthTexture::DepthTexture(TextureDimension dim)
-    : Base(Hash(tint::TypeInfo::Of<DepthTexture>().full_hashcode, dim), dim) {
-    TINT_ASSERT(Type, IsValidDepthDimension(dim));
+    : Base(Hash(TypeInfo::Of<DepthTexture>().full_hashcode, dim), dim) {
+    TINT_ASSERT(IsValidDepthDimension(dim));
 }
 
 DepthTexture::~DepthTexture() = default;
diff --git a/src/tint/lang/core/type/manager.cc b/src/tint/lang/core/type/manager.cc
index e624a3c..499c5d3 100644
--- a/src/tint/lang/core/type/manager.cc
+++ b/src/tint/lang/core/type/manager.cc
@@ -143,7 +143,7 @@
     if (stride == 0) {
         stride = implicit_stride;
     }
-    TINT_ASSERT(Type, stride >= implicit_stride);
+    TINT_ASSERT(stride >= implicit_stride);
 
     return Get<type::Array>(/* element type */ elem_ty,
                             /* element count */ Get<ConstantArrayCount>(count),
diff --git a/src/tint/lang/core/type/matrix.cc b/src/tint/lang/core/type/matrix.cc
index 50787a4..59e006a 100644
--- a/src/tint/lang/core/type/matrix.cc
+++ b/src/tint/lang/core/type/matrix.cc
@@ -16,8 +16,8 @@
 
 #include "src/tint/lang/core/type/manager.h"
 #include "src/tint/lang/core/type/vector.h"
-#include "src/tint/utils/debug/debug.h"
 #include "src/tint/utils/diagnostic/diagnostic.h"
+#include "src/tint/utils/ice/ice.h"
 #include "src/tint/utils/math/hash.h"
 #include "src/tint/utils/text/string_stream.h"
 
@@ -36,10 +36,10 @@
       column_type_(column_type),
       rows_(column_type->Width()),
       columns_(columns) {
-    TINT_ASSERT(AST, rows_ > 1);
-    TINT_ASSERT(AST, rows_ < 5);
-    TINT_ASSERT(AST, columns_ > 1);
-    TINT_ASSERT(AST, columns_ < 5);
+    TINT_ASSERT(rows_ > 1);
+    TINT_ASSERT(rows_ < 5);
+    TINT_ASSERT(columns_ > 1);
+    TINT_ASSERT(columns_ < 5);
 }
 
 Matrix::~Matrix() = default;
diff --git a/src/tint/lang/core/type/multisampled_texture.cc b/src/tint/lang/core/type/multisampled_texture.cc
index e49706e..20b9da3 100644
--- a/src/tint/lang/core/type/multisampled_texture.cc
+++ b/src/tint/lang/core/type/multisampled_texture.cc
@@ -16,8 +16,8 @@
 
 #include "src/tint/lang/core/type/manager.h"
 #include "src/tint/lang/core/type/texture_dimension.h"
-#include "src/tint/utils/debug/debug.h"
 #include "src/tint/utils/diagnostic/diagnostic.h"
+#include "src/tint/utils/ice/ice.h"
 #include "src/tint/utils/math/hash.h"
 #include "src/tint/utils/text/string_stream.h"
 
@@ -28,7 +28,7 @@
 MultisampledTexture::MultisampledTexture(TextureDimension dim, const Type* type)
     : Base(Hash(tint::TypeInfo::Of<MultisampledTexture>().full_hashcode, dim, type), dim),
       type_(type) {
-    TINT_ASSERT(Type, type_);
+    TINT_ASSERT(type_);
 }
 
 MultisampledTexture::~MultisampledTexture() = default;
diff --git a/src/tint/lang/core/type/pointer.cc b/src/tint/lang/core/type/pointer.cc
index 1104d1f..d1412dd 100644
--- a/src/tint/lang/core/type/pointer.cc
+++ b/src/tint/lang/core/type/pointer.cc
@@ -16,8 +16,8 @@
 
 #include "src/tint/lang/core/type/manager.h"
 #include "src/tint/lang/core/type/reference.h"
-#include "src/tint/utils/debug/debug.h"
 #include "src/tint/utils/diagnostic/diagnostic.h"
+#include "src/tint/utils/ice/ice.h"
 #include "src/tint/utils/math/hash.h"
 #include "src/tint/utils/text/string_stream.h"
 
@@ -31,8 +31,8 @@
       subtype_(subtype),
       address_space_(address_space),
       access_(access) {
-    TINT_ASSERT(Type, !subtype->Is<Reference>());
-    TINT_ASSERT(Type, access != builtin::Access::kUndefined);
+    TINT_ASSERT(!subtype->Is<Reference>());
+    TINT_ASSERT(access != builtin::Access::kUndefined);
 }
 
 bool Pointer::Equals(const UniqueNode& other) const {
diff --git a/src/tint/lang/core/type/reference.cc b/src/tint/lang/core/type/reference.cc
index 63dc855..f540631 100644
--- a/src/tint/lang/core/type/reference.cc
+++ b/src/tint/lang/core/type/reference.cc
@@ -15,8 +15,8 @@
 #include "src/tint/lang/core/type/reference.h"
 
 #include "src/tint/lang/core/type/manager.h"
-#include "src/tint/utils/debug/debug.h"
 #include "src/tint/utils/diagnostic/diagnostic.h"
+#include "src/tint/utils/ice/ice.h"
 #include "src/tint/utils/math/hash.h"
 #include "src/tint/utils/text/string_stream.h"
 
@@ -32,8 +32,8 @@
       subtype_(subtype),
       address_space_(address_space),
       access_(access) {
-    TINT_ASSERT(Type, !subtype->Is<Reference>());
-    TINT_ASSERT(Type, access != builtin::Access::kUndefined);
+    TINT_ASSERT(!subtype->Is<Reference>());
+    TINT_ASSERT(access != builtin::Access::kUndefined);
 }
 
 bool Reference::Equals(const UniqueNode& other) const {
diff --git a/src/tint/lang/core/type/sampled_texture.cc b/src/tint/lang/core/type/sampled_texture.cc
index 6290476..297287b 100644
--- a/src/tint/lang/core/type/sampled_texture.cc
+++ b/src/tint/lang/core/type/sampled_texture.cc
@@ -16,8 +16,8 @@
 
 #include "src/tint/lang/core/type/manager.h"
 #include "src/tint/lang/core/type/texture_dimension.h"
-#include "src/tint/utils/debug/debug.h"
 #include "src/tint/utils/diagnostic/diagnostic.h"
+#include "src/tint/utils/ice/ice.h"
 #include "src/tint/utils/math/hash.h"
 #include "src/tint/utils/text/string_stream.h"
 
@@ -26,8 +26,8 @@
 namespace tint::type {
 
 SampledTexture::SampledTexture(TextureDimension dim, const Type* type)
-    : Base(Hash(tint::TypeInfo::Of<SampledTexture>().full_hashcode, dim, type), dim), type_(type) {
-    TINT_ASSERT(Type, type_);
+    : Base(Hash(TypeInfo::Of<SampledTexture>().full_hashcode, dim, type), dim), type_(type) {
+    TINT_ASSERT(type_);
 }
 
 SampledTexture::~SampledTexture() = default;
diff --git a/src/tint/lang/core/type/type.cc b/src/tint/lang/core/type/type.cc
index 93adb19..3c5185f 100644
--- a/src/tint/lang/core/type/type.cc
+++ b/src/tint/lang/core/type/type.cc
@@ -37,7 +37,7 @@
 
 Type::Type(size_t hash, type::Flags flags) : Base(hash), flags_(flags) {
     if (IsConstructible()) {
-        TINT_ASSERT(Type, HasCreationFixedFootprint());
+        TINT_ASSERT(HasCreationFixedFootprint());
     }
 }
 
diff --git a/src/tint/lang/core/type/vector.cc b/src/tint/lang/core/type/vector.cc
index dd50a5d..5e7d865 100644
--- a/src/tint/lang/core/type/vector.cc
+++ b/src/tint/lang/core/type/vector.cc
@@ -15,8 +15,8 @@
 #include "src/tint/lang/core/type/vector.h"
 
 #include "src/tint/lang/core/type/manager.h"
-#include "src/tint/utils/debug/debug.h"
 #include "src/tint/utils/diagnostic/diagnostic.h"
+#include "src/tint/utils/ice/ice.h"
 #include "src/tint/utils/math/hash.h"
 #include "src/tint/utils/text/string_stream.h"
 
@@ -34,8 +34,8 @@
       subtype_(subtype),
       width_(width),
       packed_(packed) {
-    TINT_ASSERT(Type, width_ > 1);
-    TINT_ASSERT(Type, width_ < 5);
+    TINT_ASSERT(width_ > 1);
+    TINT_ASSERT(width_ < 5);
 }
 
 Vector::~Vector() = default;
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 8d82da4..d07b8a8 100644
--- a/src/tint/lang/glsl/writer/ast_printer/ast_printer.cc
+++ b/src/tint/lang/glsl/writer/ast_printer/ast_printer.cc
@@ -78,7 +78,7 @@
 #include "src/tint/lang/wgsl/sem/value_conversion.h"
 #include "src/tint/lang/wgsl/sem/variable.h"
 #include "src/tint/utils/containers/map.h"
-#include "src/tint/utils/debug/debug.h"
+#include "src/tint/utils/ice/ice.h"
 #include "src/tint/utils/macros/defer.h"
 #include "src/tint/utils/macros/scoped_assignment.h"
 #include "src/tint/utils/rtti/switch.h"
@@ -307,8 +307,7 @@
                 RecordExtension(enable);
             },
             [&](Default) {
-                TINT_ICE(Writer, diagnostics_)
-                    << "unhandled module-scope declaration: " << decl->TypeInfo().name;
+                TINT_ICE() << "unhandled module-scope declaration: " << decl->TypeInfo().name;
             });
     }
 
@@ -375,9 +374,9 @@
         // Source type must be vec2<f16> or vec4<f16>, since type f16 and vec3<f16> can only have
         // identity bitcast.
         auto* src_vec = src_type->As<type::Vector>();
-        TINT_ASSERT(Writer, src_vec);
-        TINT_ASSERT(Writer, ((src_vec->Width() == 2u) || (src_vec->Width() == 4u)));
-        std::string fn = tint::GetOrCreate(
+        TINT_ASSERT(src_vec);
+        TINT_ASSERT(((src_vec->Width() == 2u) || (src_vec->Width() == 4u)));
+        std::string fn = GetOrCreate(
             bitcast_funcs_, BinaryOperandType{{src_type, dst_type}}, [&]() -> std::string {
                 TextBuffer b;
                 TINT_DEFER(helpers_.Append(b));
@@ -429,9 +428,9 @@
     } else if (dst_type->DeepestElement()->Is<type::F16>()) {
         // Destination type must be vec2<f16> or vec4<f16>.
         auto* dst_vec = dst_type->As<type::Vector>();
-        TINT_ASSERT(Writer, dst_vec);
-        TINT_ASSERT(Writer, ((dst_vec->Width() == 2u) || (dst_vec->Width() == 4u)));
-        std::string fn = tint::GetOrCreate(
+        TINT_ASSERT(dst_vec);
+        TINT_ASSERT(((dst_vec->Width() == 2u) || (dst_vec->Width() == 4u)));
+        std::string fn = GetOrCreate(
             bitcast_funcs_, BinaryOperandType{{src_type, dst_type}}, [&]() -> std::string {
                 TextBuffer b;
                 TINT_DEFER(helpers_.Append(b));
@@ -452,9 +451,9 @@
                     ScopedIndent si(&b);
                     if (auto src_vec = src_type->As<type::Vector>()) {
                         // Source vector type must be vec2<f32/i32/u32>, destination type vec4<f16>.
-                        TINT_ASSERT(Writer, (src_vec->DeepestElement()
-                                                 ->IsAnyOf<type::I32, type::U32, type::F32>()));
-                        TINT_ASSERT(Writer, (src_vec->Width() == 2u));
+                        TINT_ASSERT((
+                            src_vec->DeepestElement()->IsAnyOf<type::I32, type::U32, type::F32>()));
+                        TINT_ASSERT((src_vec->Width() == 2u));
                         {
                             auto s = Line(&b);
                             s << "uvec2 r = ";
@@ -470,7 +469,7 @@
                         Line(&b) << "return f16vec4(v_xy.x, v_xy.y, v_zw.x, v_zw.y);";
                     } else {
                         // Source scalar type must be f32/i32/u32, destination type vec2<f16>.
-                        TINT_ASSERT(Writer, (src_type->IsAnyOf<type::I32, type::U32, type::F32>()));
+                        TINT_ASSERT((src_type->IsAnyOf<type::I32, type::U32, type::F32>()));
                         {
                             auto s = Line(&b);
                             s << "uint r = ";
@@ -572,7 +571,7 @@
     } else if (TINT_LIKELY(expr->op == ast::BinaryOp::kOr)) {
         out << " | ";
     } else {
-        TINT_ICE(Writer, diagnostics_) << "unexpected binary op: " << FriendlyName(expr->op);
+        TINT_ICE() << "unexpected binary op: " << FriendlyName(expr->op);
         return;
     }
 
@@ -698,7 +697,7 @@
         case ast::BinaryOp::kLogicalAnd:
         case ast::BinaryOp::kLogicalOr: {
             // These are both handled above.
-            TINT_UNREACHABLE(Writer, diagnostics_);
+            TINT_UNREACHABLE();
             return;
         }
         case ast::BinaryOp::kEqual:
@@ -786,8 +785,7 @@
         [&](const sem::ValueConversion* conv) { EmitValueConversion(out, call, conv); },
         [&](const sem::ValueConstructor* ctor) { EmitValueConstructor(out, call, ctor); },
         [&](Default) {
-            TINT_ICE(Writer, diagnostics_)
-                << "unhandled call target: " << call->Target()->TypeInfo().name;
+            TINT_ICE() << "unhandled call target: " << call->Target()->TypeInfo().name;
         });
 }
 
@@ -1018,7 +1016,7 @@
             break;
     }
 
-    TINT_UNREACHABLE(Writer, diagnostics_) << "unsupported atomic builtin: " << builtin->Type();
+    TINT_UNREACHABLE() << "unsupported atomic builtin: " << builtin->Type();
 }
 
 void ASTPrinter::EmitArrayLength(StringStream& out, const ast::CallExpression* expr) {
@@ -1167,7 +1165,7 @@
 void ASTPrinter::EmitModfCall(StringStream& out,
                               const ast::CallExpression* expr,
                               const sem::Builtin* builtin) {
-    TINT_ASSERT(Writer, expr->args.Length() == 1);
+    TINT_ASSERT(expr->args.Length() == 1);
     CallBuiltinHelper(out, expr, builtin,
                       [&](TextBuffer* b, const std::vector<std::string>& params) {
                           // Emit the builtin return type unique to this overload. This does not
@@ -1188,7 +1186,7 @@
 void ASTPrinter::EmitFrexpCall(StringStream& out,
                                const ast::CallExpression* expr,
                                const sem::Builtin* builtin) {
-    TINT_ASSERT(Writer, expr->args.Length() == 1);
+    TINT_ASSERT(expr->args.Length() == 1);
     CallBuiltinHelper(out, expr, builtin,
                       [&](TextBuffer* b, const std::vector<std::string>& params) {
                           // Emit the builtin return type unique to this overload. This does not
@@ -1269,8 +1267,7 @@
     } else if (builtin->Type() == builtin::Function::kStorageBarrier) {
         out << "{ barrier(); memoryBarrierBuffer(); }";
     } else {
-        TINT_UNREACHABLE(Writer, diagnostics_)
-            << "unexpected barrier builtin type " << builtin::str(builtin->Type());
+        TINT_UNREACHABLE() << "unexpected barrier builtin type " << builtin::str(builtin->Type());
     }
 }
 
@@ -1301,7 +1298,7 @@
 
     auto* texture = arg(Usage::kTexture);
     if (TINT_UNLIKELY(!texture)) {
-        TINT_ICE(Writer, diagnostics_) << "missing texture argument";
+        TINT_ICE() << "missing texture argument";
         return;
     }
 
@@ -1486,7 +1483,7 @@
 
     auto* param_coords = arg(Usage::kCoords);
     if (TINT_UNLIKELY(!param_coords)) {
-        TINT_ICE(Writer, diagnostics_) << "missing coords argument";
+        TINT_ICE() << "missing coords argument";
         return;
     }
 
@@ -1577,9 +1574,9 @@
         }
     }
     if (TINT_UNLIKELY(wgsl_ret_width > glsl_ret_width)) {
-        TINT_ICE(Writer, diagnostics_)
-            << "WGSL return width (" << wgsl_ret_width << ") is wider than GLSL return width ("
-            << glsl_ret_width << ") for " << builtin->Type();
+        TINT_ICE() << "WGSL return width (" << wgsl_ret_width
+                   << ") is wider than GLSL return width (" << glsl_ret_width << ") for "
+                   << builtin->Type();
         return;
     }
 }
@@ -1873,8 +1870,7 @@
                         "unhandled address space " + tint::ToString(sem->AddressSpace()));
                     return;
                 default: {
-                    TINT_ICE(Writer, diagnostics_)
-                        << "unhandled address space " << sem->AddressSpace();
+                    TINT_ICE() << "unhandled address space " << sem->AddressSpace();
                     break;
                 }
             }
@@ -1890,8 +1886,7 @@
             // Constants are embedded at their use
         },
         [&](Default) {
-            TINT_ICE(Writer, diagnostics_)
-                << "unhandled global variable type " << global->TypeInfo().name;
+            TINT_ICE() << "unhandled global variable type " << global->TypeInfo().name;
         });
 }
 
@@ -1899,7 +1894,7 @@
     auto* type = sem->Type()->UnwrapRef();
     auto* str = type->As<type::Struct>();
     if (TINT_UNLIKELY(!str)) {
-        TINT_ICE(Writer, builder_.Diagnostics()) << "storage variable must be of struct type";
+        TINT_ICE() << "storage variable must be of struct type";
         return;
     }
     auto bp = *sem->As<sem::GlobalVariable>()->BindingPoint();
@@ -1918,7 +1913,7 @@
     auto* type = sem->Type()->UnwrapRef();
     auto* str = type->As<type::Struct>();
     if (TINT_UNLIKELY(!str)) {
-        TINT_ICE(Writer, builder_.Diagnostics()) << "storage variable must be of struct type";
+        TINT_ICE() << "storage variable must be of struct type";
         return;
     }
     auto bp = *sem->As<sem::GlobalVariable>()->BindingPoint();
@@ -1944,8 +1939,7 @@
         out << "layout(";
         switch (storage->texel_format()) {
             case builtin::TexelFormat::kBgra8Unorm:
-                TINT_ICE(Writer, diagnostics_)
-                    << "bgra8unorm should have been polyfilled to rgba8unorm";
+                TINT_ICE() << "bgra8unorm should have been polyfilled to rgba8unorm";
                 break;
             case builtin::TexelFormat::kR32Uint:
                 out << "r32ui";
@@ -1996,7 +1990,7 @@
                 out << "rgba32f";
                 break;
             case builtin::TexelFormat::kUndefined:
-                TINT_ICE(Writer, diagnostics_) << "invalid texel format";
+                TINT_ICE() << "invalid texel format";
                 return;
         }
         out << ") ";
@@ -2173,7 +2167,7 @@
             if (TINT_UNLIKELY(!type->Is<type::Struct>())) {
                 // ICE likely indicates that the CanonicalizeEntryPointIO transform was
                 // not run, or a builtin parameter was added after it was run.
-                TINT_ICE(Writer, diagnostics_) << "Unsupported non-struct entry point parameter";
+                TINT_ICE() << "Unsupported non-struct entry point parameter";
             }
 
             if (!first) {
@@ -2539,10 +2533,7 @@
         [&](const sem::StructMemberAccess* member_access) {
             out << member_access->Member()->Name().Name();
         },
-        [&](Default) {
-            TINT_ICE(Writer, diagnostics_)
-                << "unknown member access type: " << sem->TypeInfo().name;
-        });
+        [&](Default) { TINT_ICE() << "unknown member access type: " << sem->TypeInfo().name; });
 }
 
 void ASTPrinter::EmitReturn(const ast::ReturnStatement* stmt) {
@@ -2585,8 +2576,7 @@
                     // Constants are embedded at their use
                 },
                 [&](Default) {  //
-                    TINT_ICE(Writer, diagnostics_)
-                        << "unknown variable type: " << v->variable->TypeInfo().name;
+                    TINT_ICE() << "unknown variable type: " << v->variable->TypeInfo().name;
                 });
         },
         [&](const ast::ConstAssert*) {
@@ -2684,7 +2674,7 @@
     } else if (type->Is<type::I32>()) {
         out << "int";
     } else if (auto* mat = type->As<type::Matrix>()) {
-        TINT_ASSERT(Writer, (mat->type()->IsAnyOf<type::F32, type::F16>()));
+        TINT_ASSERT((mat->type()->IsAnyOf<type::F32, type::F16>()));
         if (mat->type()->Is<type::F16>()) {
             out << "f16";
         }
@@ -2693,14 +2683,14 @@
             out << "x" << mat->rows();
         }
     } else if (TINT_UNLIKELY(type->Is<type::Pointer>())) {
-        TINT_ICE(Writer, diagnostics_) << "Attempting to emit pointer type. These should have been "
-                                          "removed with the SimplifyPointers transform";
+        TINT_ICE() << "Attempting to emit pointer type. These should have been removed with the "
+                      "SimplifyPointers transform";
     } else if (type->Is<type::Sampler>()) {
     } else if (auto* str = type->As<type::Struct>()) {
         out << StructName(str);
     } else if (auto* tex = type->As<type::Texture>()) {
         if (TINT_UNLIKELY(tex->Is<type::ExternalTexture>())) {
-            TINT_ICE(Writer, diagnostics_) << "Multiplanar external texture transform was not run.";
+            TINT_ICE() << "Multiplanar external texture transform was not run.";
             return;
         }
 
@@ -2724,7 +2714,7 @@
         } else if (TINT_LIKELY(subtype->Is<type::U32>())) {
             out << "u";
         } else {
-            TINT_ICE(Writer, diagnostics_) << "Unsupported texture type";
+            TINT_ICE() << "Unsupported texture type";
             return;
         }
 
@@ -2750,8 +2740,7 @@
                 out << "CubeArray";
                 break;
             default:
-                TINT_UNREACHABLE(Writer, diagnostics_)
-                    << "unexpected TextureDimension " << tex->dim();
+                TINT_UNREACHABLE() << "unexpected TextureDimension " << tex->dim();
                 return;
         }
         if (tex->Is<type::DepthTexture>()) {
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 94a6307..6699805 100644
--- a/src/tint/lang/hlsl/writer/ast_printer/ast_printer.cc
+++ b/src/tint/lang/hlsl/writer/ast_printer/ast_printer.cc
@@ -76,7 +76,7 @@
 #include "src/tint/lang/wgsl/sem/value_conversion.h"
 #include "src/tint/lang/wgsl/sem/variable.h"
 #include "src/tint/utils/containers/map.h"
-#include "src/tint/utils/debug/debug.h"
+#include "src/tint/utils/ice/ice.h"
 #include "src/tint/utils/macros/compiler.h"
 #include "src/tint/utils/macros/defer.h"
 #include "src/tint/utils/macros/scoped_assignment.h"
@@ -394,8 +394,7 @@
                 return EmitFunction(func);
             },
             [&](Default) {
-                TINT_ICE(Writer, diagnostics_)
-                    << "unhandled module-scope declaration: " << decl->TypeInfo().name;
+                TINT_ICE() << "unhandled module-scope declaration: " << decl->TypeInfo().name;
                 return false;
             });
 
@@ -451,8 +450,7 @@
                     out << "vec = (idx.xxxx == int4(0, 1, 2, 3)) ? val.xxxx : vec;";
                     break;
                 default:
-                    TINT_UNREACHABLE(Writer, diagnostics_)
-                        << "invalid vector size " << vec->Width();
+                    TINT_UNREACHABLE() << "invalid vector size " << vec->Width();
                     break;
             }
         }
@@ -612,8 +610,7 @@
                                     auto* vec = TypeOf(lhs_row_access->object)
                                                     ->UnwrapRef()
                                                     ->As<type::Vector>();
-                                    TINT_UNREACHABLE(Writer, diagnostics_)
-                                        << "invalid vector size " << vec->Width();
+                                    TINT_UNREACHABLE() << "invalid vector size " << vec->Width();
                                     break;
                                 }
                             }
@@ -694,8 +691,8 @@
                 // Source type must be vec2<f16> or vec4<f16>, since type f16 and vec3<f16> can only
                 // have identity bitcast.
                 auto* src_vec = src_type->As<type::Vector>();
-                TINT_ASSERT(Writer, src_vec);
-                TINT_ASSERT(Writer, ((src_vec->Width() == 2u) || (src_vec->Width() == 4u)));
+                TINT_ASSERT(src_vec);
+                TINT_ASSERT(((src_vec->Width() == 2u) || (src_vec->Width() == 4u)));
 
                 // Bitcast f16 types to others by converting the given f16 value to f32 and call
                 // f32tof16 to get the bits. This should be safe, because the convertion is precise
@@ -759,14 +756,13 @@
             } else {
                 // Destination type must be vec2<f16> or vec4<f16>.
                 auto* dst_vec = dst_type->As<type::Vector>();
-                TINT_ASSERT(Writer,
-                            (dst_vec && ((dst_vec->Width() == 2u) || (dst_vec->Width() == 4u)) &&
+                TINT_ASSERT((dst_vec && ((dst_vec->Width() == 2u) || (dst_vec->Width() == 4u)) &&
                              dst_el_type->Is<type::F16>()));
                 // Source type must be f32/i32/u32 or vec2<f32/i32/u32>.
                 auto* src_vec = src_type->As<type::Vector>();
-                TINT_ASSERT(Writer, (src_type->IsAnyOf<type::I32, type::U32, type::F32>() ||
-                                     (src_vec && src_vec->Width() == 2u &&
-                                      src_el_type->IsAnyOf<type::I32, type::U32, type::F32>())));
+                TINT_ASSERT((src_type->IsAnyOf<type::I32, type::U32, type::F32>() ||
+                             (src_vec && src_vec->Width() == 2u &&
+                              src_el_type->IsAnyOf<type::I32, type::U32, type::F32>())));
                 std::string src_type_suffix = (src_vec ? "2" : "");
 
                 // Bitcast other types to f16 types by reinterpreting their bits as f16 using
@@ -854,7 +850,7 @@
     }
 
     // Otherwise, bitcasting between non-f16 types.
-    TINT_ASSERT(Writer, (!src_el_type->Is<type::F16>() && !dst_el_type->Is<type::F16>()));
+    TINT_ASSERT((!src_el_type->Is<type::F16>() && !dst_el_type->Is<type::F16>()));
     out << "as";
     if (!EmitType(out, dst_el_type, builtin::AddressSpace::kUndefined, builtin::Access::kReadWrite,
                   "")) {
@@ -989,7 +985,7 @@
         case ast::BinaryOp::kLogicalAnd:
         case ast::BinaryOp::kLogicalOr: {
             // These are both handled above.
-            TINT_UNREACHABLE(Writer, diagnostics_);
+            TINT_UNREACHABLE();
             return false;
         }
         case ast::BinaryOp::kEqual:
@@ -1097,7 +1093,7 @@
         [&](const sem::ValueConversion* conv) { return EmitValueConversion(out, call, conv); },
         [&](const sem::ValueConstructor* ctor) { return EmitValueConstructor(out, call, ctor); },
         [&](Default) {
-            TINT_ICE(Writer, diagnostics_) << "unhandled call target: " << target->TypeInfo().name;
+            TINT_ICE() << "unhandled call target: " << target->TypeInfo().name;
             return false;
         });
 }
@@ -1133,9 +1129,8 @@
                 }
                 break;
             default:
-                TINT_UNREACHABLE(Writer, diagnostics_)
-                    << "unsupported DecomposeMemoryAccess::Intrinsic address space:"
-                    << intrinsic->address_space;
+                TINT_UNREACHABLE() << "unsupported DecomposeMemoryAccess::Intrinsic address space:"
+                                   << intrinsic->address_space;
                 return false;
         }
     }
@@ -1278,7 +1273,7 @@
     // It could also be conversions between f16 and f32 matrix when f16 is properly supported.
     if (type->Is<type::Matrix>() && call->Arguments().Length() == 1) {
         if (!ctor->Parameters()[0]->Type()->UnwrapRef()->is_float_matrix()) {
-            TINT_UNREACHABLE(Writer, diagnostics_)
+            TINT_UNREACHABLE()
                 << "found a single-parameter matrix initializer that is not identity initializer";
             return false;
         }
@@ -1348,7 +1343,7 @@
     bool scalar_offset_constant = false;
 
     if (auto* val = builder_.Sem().GetVal(offset)->ConstantValue()) {
-        TINT_ASSERT(Writer, val->Type()->Is<type::U32>());
+        TINT_ASSERT(val->Type()->Is<type::U32>());
         scalar_offset_bytes = static_cast<uint32_t>(val->ValueAs<AInt>());
         scalar_offset_index = scalar_offset_bytes / 4;  // bytes -> scalar index
         scalar_offset_constant = true;
@@ -1601,16 +1596,15 @@
                 case DataType::kVec4F16:
                     return load_vec4_f16();
             }
-            TINT_UNREACHABLE(Writer, diagnostics_)
-                << "unsupported DecomposeMemoryAccess::Intrinsic::DataType: "
-                << static_cast<int>(intrinsic->type);
+            TINT_UNREACHABLE() << "unsupported DecomposeMemoryAccess::Intrinsic::DataType: "
+                               << static_cast<int>(intrinsic->type);
             return false;
         }
         default:
             break;
     }
-    TINT_UNREACHABLE(Writer, diagnostics_)
-        << "unsupported DecomposeMemoryAccess::Intrinsic::Op: " << static_cast<int>(intrinsic->op);
+    TINT_UNREACHABLE() << "unsupported DecomposeMemoryAccess::Intrinsic::Op: "
+                       << static_cast<int>(intrinsic->op);
     return false;
 }
 
@@ -1688,9 +1682,8 @@
                 case DataType::kVec4F16:
                     return templated_load("vector<float16_t, 4> ");
             }
-            TINT_UNREACHABLE(Writer, diagnostics_)
-                << "unsupported DecomposeMemoryAccess::Intrinsic::DataType: "
-                << static_cast<int>(intrinsic->type);
+            TINT_UNREACHABLE() << "unsupported DecomposeMemoryAccess::Intrinsic::DataType: "
+                               << static_cast<int>(intrinsic->type);
             return false;
         }
 
@@ -1760,9 +1753,8 @@
                 case DataType::kVec4F16:
                     return templated_store("vector<float16_t, 4> ");
             }
-            TINT_UNREACHABLE(Writer, diagnostics_)
-                << "unsupported DecomposeMemoryAccess::Intrinsic::DataType: "
-                << static_cast<int>(intrinsic->type);
+            TINT_UNREACHABLE() << "unsupported DecomposeMemoryAccess::Intrinsic::DataType: "
+                               << static_cast<int>(intrinsic->type);
             return false;
         }
         default:
@@ -1771,8 +1763,8 @@
             break;
     }
 
-    TINT_UNREACHABLE(Writer, diagnostics_)
-        << "unsupported DecomposeMemoryAccess::Intrinsic::Op: " << static_cast<int>(intrinsic->op);
+    TINT_UNREACHABLE() << "unsupported DecomposeMemoryAccess::Intrinsic::Op: "
+                       << static_cast<int>(intrinsic->op);
     return false;
 }
 
@@ -1978,9 +1970,8 @@
             break;
     }
 
-    TINT_UNREACHABLE(Writer, diagnostics_)
-        << "unsupported atomic DecomposeMemoryAccess::Intrinsic::Op: "
-        << static_cast<int>(intrinsic->op);
+    TINT_UNREACHABLE() << "unsupported atomic DecomposeMemoryAccess::Intrinsic::Op: "
+                       << static_cast<int>(intrinsic->op);
     return false;
 }
 
@@ -2155,7 +2146,7 @@
             break;
     }
 
-    TINT_UNREACHABLE(Writer, diagnostics_) << "unsupported atomic builtin: " << builtin->Type();
+    TINT_UNREACHABLE() << "unsupported atomic builtin: " << builtin->Type();
     return false;
 }
 
@@ -2493,8 +2484,7 @@
     } else if (builtin->Type() == builtin::Function::kStorageBarrier) {
         out << "DeviceMemoryBarrierWithGroupSync()";
     } else {
-        TINT_UNREACHABLE(Writer, diagnostics_)
-            << "unexpected barrier builtin type " << builtin::str(builtin->Type());
+        TINT_UNREACHABLE() << "unexpected barrier builtin type " << builtin::str(builtin->Type());
         return false;
     }
     return true;
@@ -2517,7 +2507,7 @@
 
     auto* texture = arg(Usage::kTexture);
     if (TINT_UNLIKELY(!texture)) {
-        TINT_ICE(Writer, diagnostics_) << "missing texture argument";
+        TINT_ICE() << "missing texture argument";
         return false;
     }
 
@@ -2538,7 +2528,7 @@
                 case builtin::Function::kTextureDimensions:
                     switch (texture_type->dim()) {
                         case type::TextureDimension::kNone:
-                            TINT_ICE(Writer, diagnostics_) << "texture dimension is kNone";
+                            TINT_ICE() << "texture dimension is kNone";
                             return false;
                         case type::TextureDimension::k1d:
                             num_dimensions = 1;
@@ -2566,7 +2556,7 @@
                 case builtin::Function::kTextureNumLayers:
                     switch (texture_type->dim()) {
                         default:
-                            TINT_ICE(Writer, diagnostics_) << "texture dimension is not arrayed";
+                            TINT_ICE() << "texture dimension is not arrayed";
                             return false;
                         case type::TextureDimension::k2dArray:
                             num_dimensions = is_ms ? 4 : 3;
@@ -2581,8 +2571,7 @@
                 case builtin::Function::kTextureNumLevels:
                     switch (texture_type->dim()) {
                         default:
-                            TINT_ICE(Writer, diagnostics_)
-                                << "texture dimension does not support mips";
+                            TINT_ICE() << "texture dimension does not support mips";
                             return false;
                         case type::TextureDimension::k1d:
                             num_dimensions = 2;
@@ -2604,8 +2593,7 @@
                 case builtin::Function::kTextureNumSamples:
                     switch (texture_type->dim()) {
                         default:
-                            TINT_ICE(Writer, diagnostics_)
-                                << "texture dimension does not support multisampling";
+                            TINT_ICE() << "texture dimension does not support multisampling";
                             return false;
                         case type::TextureDimension::k2d:
                             num_dimensions = 3;
@@ -2618,7 +2606,7 @@
                     }
                     break;
                 default:
-                    TINT_ICE(Writer, diagnostics_) << "unexpected builtin";
+                    TINT_ICE() << "unexpected builtin";
                     return false;
             }
 
@@ -2640,8 +2628,8 @@
             }
 
             if (TINT_UNLIKELY(num_dimensions > 4)) {
-                TINT_ICE(Writer, diagnostics_) << "Texture query builtin temporary vector has "
-                                               << num_dimensions << " dimensions";
+                TINT_ICE() << "Texture query builtin temporary vector has " << num_dimensions
+                           << " dimensions";
                 return false;
             }
 
@@ -2674,8 +2662,7 @@
                 } else {
                     static constexpr char xyzw[] = {'x', 'y', 'z', 'w'};
                     if (TINT_UNLIKELY(num_dimensions < 0 || num_dimensions > 4)) {
-                        TINT_ICE(Writer, diagnostics_)
-                            << "vector dimensions are " << num_dimensions;
+                        TINT_ICE() << "vector dimensions are " << num_dimensions;
                         return false;
                     }
                     for (int i = 0; i < num_dimensions; i++) {
@@ -2781,7 +2768,7 @@
 
     auto* param_coords = arg(Usage::kCoords);
     if (TINT_UNLIKELY(!param_coords)) {
-        TINT_ICE(Writer, diagnostics_) << "missing coords argument";
+        TINT_ICE() << "missing coords argument";
         return false;
     }
 
@@ -2864,9 +2851,9 @@
             }
         }
         if (TINT_UNLIKELY(wgsl_ret_width > hlsl_ret_width)) {
-            TINT_ICE(Writer, diagnostics_)
-                << "WGSL return width (" << wgsl_ret_width << ") is wider than HLSL return width ("
-                << hlsl_ret_width << ") for " << builtin->Type();
+            TINT_ICE() << "WGSL return width (" << wgsl_ret_width
+                       << ") is wider than HLSL return width (" << hlsl_ret_width << ") for "
+                       << builtin->Type();
             return false;
         }
     }
@@ -3184,7 +3171,7 @@
     // there is always an (unused) return statement.
 
     auto* sem = builder_.Sem().Get(func);
-    TINT_ASSERT(Writer, sem->DiscardStatement() && !sem->ReturnType()->Is<type::Void>());
+    TINT_ASSERT(sem->DiscardStatement() && !sem->ReturnType()->Is<type::Void>());
 
     ScopedIndent si(this);
     Line() << "if (true) {";
@@ -3232,8 +3219,7 @@
                         "unhandled address space " + tint::ToString(sem->AddressSpace()));
                     return false;
                 default: {
-                    TINT_ICE(Writer, diagnostics_)
-                        << "unhandled address space " << sem->AddressSpace();
+                    TINT_ICE() << "unhandled address space " << sem->AddressSpace();
                     return false;
                 }
             }
@@ -3249,8 +3235,7 @@
             return true;  // Constants are embedded at their use
         },
         [&](Default) {
-            TINT_ICE(Writer, diagnostics_)
-                << "unhandled global variable type " << global->TypeInfo().name;
+            TINT_ICE() << "unhandled global variable type " << global->TypeInfo().name;
 
             return false;
         });
@@ -3480,7 +3465,7 @@
             if (TINT_UNLIKELY(!type->Is<type::Struct>())) {
                 // ICE likely indicates that the CanonicalizeEntryPointIO transform was
                 // not run, or a builtin parameter was added after it was run.
-                TINT_ICE(Writer, diagnostics_) << "Unsupported non-struct entry point parameter";
+                TINT_ICE() << "Unsupported non-struct entry point parameter";
             }
 
             if (!first) {
@@ -3997,8 +3982,7 @@
             return true;
         },
         [&](Default) {
-            TINT_ICE(Writer, diagnostics_)
-                << "unknown member access type: " << sem->TypeInfo().name;
+            TINT_ICE() << "unknown member access type: " << sem->TypeInfo().name;
             return false;
         });
 }
@@ -4073,8 +4057,7 @@
                     return true;  // Constants are embedded at their use
                 },
                 [&](Default) {  //
-                    TINT_ICE(Writer, diagnostics_)
-                        << "unknown variable type: " << v->variable->TypeInfo().name;
+                    TINT_ICE() << "unknown variable type: " << v->variable->TypeInfo().name;
                     return false;
                 });
         },
@@ -4089,7 +4072,7 @@
 }
 
 bool ASTPrinter::EmitDefaultOnlySwitch(const ast::SwitchStatement* stmt) {
-    TINT_ASSERT(Writer, stmt->body.Length() == 1 && stmt->body[0]->ContainsDefault());
+    TINT_ASSERT(stmt->body.Length() == 1 && stmt->body[0]->ContainsDefault());
 
     // FXC fails to compile a switch with just a default case, ignoring the
     // default case body. We work around this here by emitting the default case
@@ -4184,7 +4167,7 @@
             std::vector<uint32_t> sizes;
             while (auto* arr = base_type->As<type::Array>()) {
                 if (TINT_UNLIKELY(arr->Count()->Is<type::RuntimeArrayCount>())) {
-                    TINT_ICE(Writer, diagnostics_)
+                    TINT_ICE()
                         << "runtime arrays may only exist in storage buffers, which should have "
                            "been transformed into a ByteAddressBuffer";
                     return false;
@@ -4253,8 +4236,8 @@
             return true;
         },
         [&](const type::Pointer*) {
-            TINT_ICE(Writer, diagnostics_) << "Attempting to emit pointer type. These should have "
-                                              "been removed with the SimplifyPointers transform";
+            TINT_ICE() << "Attempting to emit pointer type. These should have "
+                          "been removed with the SimplifyPointers transform";
             return false;
         },
         [&](const type::Sampler* sampler) {
@@ -4271,8 +4254,7 @@
         },
         [&](const type::Texture* tex) {
             if (TINT_UNLIKELY(tex->Is<type::ExternalTexture>())) {
-                TINT_ICE(Writer, diagnostics_)
-                    << "Multiplanar external texture transform was not run.";
+                TINT_ICE() << "Multiplanar external texture transform was not run.";
                 return false;
             }
 
@@ -4306,16 +4288,15 @@
                     out << "CubeArray";
                     break;
                 default:
-                    TINT_UNREACHABLE(Writer, diagnostics_)
-                        << "unexpected TextureDimension " << tex->dim();
+                    TINT_UNREACHABLE() << "unexpected TextureDimension " << tex->dim();
                     return false;
             }
 
             if (storage) {
                 auto* component = image_format_to_rwtexture_type(storage->texel_format());
                 if (TINT_UNLIKELY(!component)) {
-                    TINT_ICE(Writer, diagnostics_) << "Unsupported StorageTexture TexelFormat: "
-                                                   << static_cast<int>(storage->texel_format());
+                    TINT_ICE() << "Unsupported StorageTexture TexelFormat: "
+                               << static_cast<int>(storage->texel_format());
                     return false;
                 }
                 out << "<" << component << ">";
@@ -4331,7 +4312,7 @@
                 } else if (TINT_LIKELY(subtype->Is<type::U32>())) {
                     out << "uint4";
                 } else {
-                    TINT_ICE(Writer, diagnostics_) << "Unsupported multisampled texture type";
+                    TINT_ICE() << "Unsupported multisampled texture type";
                     return false;
                 }
                 out << ">";
@@ -4410,7 +4391,7 @@
             if (auto location = attributes.location) {
                 auto& pipeline_stage_uses = str->PipelineStageUses();
                 if (TINT_UNLIKELY(pipeline_stage_uses.size() != 1)) {
-                    TINT_ICE(Writer, diagnostics_) << "invalid entry point IO struct uses";
+                    TINT_ICE() << "invalid entry point IO struct uses";
                 }
                 if (pipeline_stage_uses.count(type::PipelineStageUsage::kVertexInput)) {
                     post += " : TEXCOORD" + std::to_string(location.value());
@@ -4427,7 +4408,7 @@
                     }
 
                 } else {
-                    TINT_ICE(Writer, diagnostics_) << "invalid use of location attribute";
+                    TINT_ICE() << "invalid use of location attribute";
                 }
             }
             if (auto builtin = attributes.builtin) {
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 b9aa6c1..f9557c64 100644
--- a/src/tint/lang/msl/writer/ast_printer/ast_printer.cc
+++ b/src/tint/lang/msl/writer/ast_printer/ast_printer.cc
@@ -297,7 +297,7 @@
             },
             [&](Default) {
                 // These are pushed into the entry point by sanitizer transforms.
-                TINT_ICE(Writer, diagnostics_) << "unhandled type: " << decl->TypeInfo().name;
+                TINT_ICE() << "unhandled type: " << decl->TypeInfo().name;
                 return false;
             });
         if (!ok) {
@@ -614,7 +614,7 @@
         [&](const sem::ValueConversion* conv) { return EmitTypeConversion(out, call, conv); },
         [&](const sem::ValueConstructor* ctor) { return EmitTypeInitializer(out, call, ctor); },
         [&](Default) {
-            TINT_ICE(Writer, diagnostics_) << "unhandled call target: " << target->TypeInfo().name;
+            TINT_ICE() << "unhandled call target: " << target->TypeInfo().name;
             return false;
         });
 }
@@ -946,7 +946,7 @@
             break;
     }
 
-    TINT_UNREACHABLE(Writer, diagnostics_) << "unsupported atomic builtin: " << builtin->Type();
+    TINT_UNREACHABLE() << "unsupported atomic builtin: " << builtin->Type();
     return false;
 }
 
@@ -967,7 +967,7 @@
 
     auto* texture = arg(Usage::kTexture)->Declaration();
     if (TINT_UNLIKELY(!texture)) {
-        TINT_ICE(Writer, diagnostics_) << "missing texture arg";
+        TINT_ICE() << "missing texture arg";
         return false;
     }
 
@@ -1104,8 +1104,7 @@
             out << ".write(";
             break;
         default:
-            TINT_UNREACHABLE(Writer, diagnostics_)
-                << "Unhandled texture builtin '" << builtin->str() << "'";
+            TINT_UNREACHABLE() << "Unhandled texture builtin '" << builtin->str() << "'";
             return false;
     }
 
@@ -1138,7 +1137,7 @@
                         out << "uint3(";
                         break;
                     default:
-                        TINT_ICE(Writer, diagnostics_) << "unhandled texture dimensionality";
+                        TINT_ICE() << "unhandled texture dimensionality";
                         break;
                 }
             }
@@ -1252,7 +1251,7 @@
                 out << "component::w";
                 break;
             default:
-                TINT_ICE(Writer, diagnostics_) << "invalid textureGather component: " << c;
+                TINT_ICE() << "invalid textureGather component: " << c;
                 break;
         }
     }
@@ -1882,15 +1881,14 @@
     const uint32_t kInvalidBindingIndex = std::numeric_limits<uint32_t>::max();
     auto get_binding_index = [&](const ast::Parameter* param) -> uint32_t {
         if (TINT_UNLIKELY(!param->HasBindingPoint())) {
-            TINT_ICE(Writer, diagnostics_)
-                << "missing binding attributes for entry point parameter";
+            TINT_ICE() << "missing binding attributes for entry point parameter";
             return kInvalidBindingIndex;
         }
         auto* param_sem = builder_.Sem().Get<sem::Parameter>(param);
         auto bp = param_sem->BindingPoint();
         if (TINT_UNLIKELY(bp->group != 0)) {
-            TINT_ICE(Writer, diagnostics_) << "encountered non-zero resource group index (use "
-                                              "BindingRemapper to fix)";
+            TINT_ICE() << "encountered non-zero resource group index (use "
+                          "BindingRemapper to fix)";
             return kInvalidBindingIndex;
         }
         return bp->binding;
@@ -1965,8 +1963,7 @@
                         default:
                             break;
                     }
-                    TINT_ICE(Writer, diagnostics_)
-                        << "invalid pointer address space for entry point parameter";
+                    TINT_ICE() << "invalid pointer address space for entry point parameter";
                     return false;
                 },
                 [&](Default) {
@@ -1989,7 +1986,7 @@
                         out << " [[" << name << "]]";
                     }
                     if (TINT_UNLIKELY(!builtin_found)) {
-                        TINT_ICE(Writer, diagnostics_) << "Unsupported entry point parameter";
+                        TINT_ICE() << "Unsupported entry point parameter";
                         return false;
                     }
                     return true;
@@ -2294,8 +2291,7 @@
             return true;
         },
         [&](Default) {
-            TINT_ICE(Writer, diagnostics_)
-                << "unknown member access type: " << sem->TypeInfo().name;
+            TINT_ICE() << "unknown member access type: " << sem->TypeInfo().name;
             return false;
         });
 }
@@ -2381,8 +2377,7 @@
                     return true;  // Constants are embedded at their use
                 },
                 [&](Default) {  //
-                    TINT_ICE(Writer, diagnostics_)
-                        << "unknown statement type: " << stmt->TypeInfo().name;
+                    TINT_ICE() << "unknown statement type: " << stmt->TypeInfo().name;
                     return false;
                 });
         },
@@ -2446,8 +2441,7 @@
                 out << "atomic_uint";
                 return true;
             }
-            TINT_ICE(Writer, diagnostics_)
-                << "unhandled atomic type " << atomic->Type()->FriendlyName();
+            TINT_ICE() << "unhandled atomic type " << atomic->Type()->FriendlyName();
             return false;
         },
         [&](const type::Array* arr) {
@@ -2520,8 +2514,7 @@
         },
         [&](const type::Texture* tex) {
             if (TINT_UNLIKELY(tex->Is<type::ExternalTexture>())) {
-                TINT_ICE(Writer, diagnostics_)
-                    << "Multiplanar external texture transform was not run.";
+                TINT_ICE() << "Multiplanar external texture transform was not run.";
                 return false;
             }
 
@@ -2660,7 +2653,7 @@
         default:
             break;
     }
-    TINT_ICE(Writer, diagnostics_) << "unhandled address space: " << sc;
+    TINT_ICE() << "unhandled address space: " << sc;
     return false;
 }
 
@@ -2703,8 +2696,8 @@
         if (is_host_shareable) {
             if (TINT_UNLIKELY(wgsl_offset < msl_offset)) {
                 // Unimplementable layout
-                TINT_ICE(Writer, diagnostics_) << "Structure member WGSL offset (" << wgsl_offset
-                                               << ") is behind MSL offset (" << msl_offset << ")";
+                TINT_ICE() << "Structure member WGSL offset (" << wgsl_offset
+                           << ") is behind MSL offset (" << msl_offset << ")";
                 return false;
             }
 
@@ -2739,7 +2732,7 @@
         if (auto location = attributes.location) {
             auto& pipeline_stage_uses = str->PipelineStageUses();
             if (TINT_UNLIKELY(pipeline_stage_uses.size() != 1)) {
-                TINT_ICE(Writer, diagnostics_) << "invalid entry point IO struct uses";
+                TINT_ICE() << "invalid entry point IO struct uses";
                 return false;
             }
 
@@ -2758,7 +2751,7 @@
                     out << " [[color(" + std::to_string(location.value()) + ")]]";
                 }
             } else {
-                TINT_ICE(Writer, diagnostics_) << "invalid use of location decoration";
+                TINT_ICE() << "invalid use of location decoration";
                 return false;
             }
         }
@@ -2783,8 +2776,8 @@
             // Calculate new MSL offset
             auto size_align = MslPackedTypeSizeAndAlign(diagnostics_, ty);
             if (TINT_UNLIKELY(msl_offset % size_align.align)) {
-                TINT_ICE(Writer, diagnostics_)
-                    << "Misaligned MSL structure member " << ty->FriendlyName() << " " << mem_name;
+                TINT_ICE() << "Misaligned MSL structure member " << ty->FriendlyName() << " "
+                           << mem_name;
                 return false;
             }
             msl_offset += size_align.size;
@@ -2891,7 +2884,7 @@
             out << "threadgroup ";
             break;
         default:
-            TINT_ICE(Writer, diagnostics_) << "unhandled variable address space";
+            TINT_ICE() << "unhandled variable address space";
             return false;
     }
 
@@ -2936,7 +2929,7 @@
             out << "threadgroup ";
             break;
         default:
-            TINT_ICE(Writer, diagnostics_) << "unhandled variable address space";
+            TINT_ICE() << "unhandled variable address space";
             return false;
     }
 
diff --git a/src/tint/lang/msl/writer/printer/printer.cc b/src/tint/lang/msl/writer/printer/printer.cc
index 3427bce..ea0e938 100644
--- a/src/tint/lang/msl/writer/printer/printer.cc
+++ b/src/tint/lang/msl/writer/printer/printer.cc
@@ -48,9 +48,9 @@
 }  // namespace
 
 // Helper for calling TINT_UNIMPLEMENTED() from a Switch(object_ptr) default case.
-#define UNHANDLED_CASE(object_ptr)           \
-    TINT_UNIMPLEMENTED(Writer, diagnostics_) \
-        << "unhandled case in Switch(): " << (object_ptr ? object_ptr->TypeInfo().name : "<null>")
+#define UNHANDLED_CASE(object_ptr)                         \
+    TINT_UNIMPLEMENTED() << "unhandled case in Switch(): " \
+                         << (object_ptr ? object_ptr->TypeInfo().name : "<null>")
 
 Printer::Printer(ir::Module* module) : ir_(module) {}
 
@@ -149,7 +149,7 @@
             out << "constant";
             break;
         default:
-            TINT_ICE(Writer, diagnostics_) << "unhandled address space: " << sc;
+            TINT_ICE() << "unhandled address space: " << sc;
             break;
     }
 }
@@ -198,7 +198,7 @@
         out << "atomic_uint";
         return;
     }
-    TINT_ICE(Writer, diagnostics_) << "unhandled atomic type " << atomic->Type()->FriendlyName();
+    TINT_ICE();
 }
 
 void Printer::EmitArrayType(StringStream& out, const type::Array* arr) {
@@ -233,7 +233,7 @@
 
 void Printer::EmitTextureType(StringStream& out, const type::Texture* tex) {
     if (TINT_UNLIKELY(tex->Is<type::ExternalTexture>())) {
-        TINT_ICE(Writer, diagnostics_) << "Multiplanar external texture transform was not run.";
+        TINT_ICE() << "Multiplanar external texture transform was not run.";
         return;
     }
 
@@ -346,8 +346,8 @@
         if (is_host_shareable) {
             if (TINT_UNLIKELY(ir_offset < msl_offset)) {
                 // Unimplementable layout
-                TINT_ICE(Writer, diagnostics_) << "Structure member offset (" << ir_offset
-                                               << ") is behind MSL offset (" << msl_offset << ")";
+                TINT_ICE() << "Structure member offset (" << ir_offset << ") is behind MSL offset ("
+                           << msl_offset << ")";
                 return;
             }
 
@@ -380,7 +380,7 @@
         if (auto location = attributes.location) {
             auto& pipeline_stage_uses = str->PipelineStageUses();
             if (TINT_UNLIKELY(pipeline_stage_uses.size() != 1)) {
-                TINT_ICE(Writer, diagnostics_) << "invalid entry point IO struct uses";
+                TINT_ICE() << "invalid entry point IO struct uses";
                 return;
             }
 
@@ -394,7 +394,7 @@
                            pipeline_stage_uses.count(type::PipelineStageUsage::kFragmentOutput))) {
                 out << " [[color(" + std::to_string(location.value()) + ")]]";
             } else {
-                TINT_ICE(Writer, diagnostics_) << "invalid use of location decoration";
+                TINT_ICE() << "invalid use of location decoration";
                 return;
             }
         }
@@ -419,9 +419,9 @@
             // Calculate new MSL offset
             auto size_align = MslPackedTypeSizeAndAlign(diagnostics_, ty);
             if (TINT_UNLIKELY(msl_offset % size_align.align)) {
-                TINT_ICE(Writer, diagnostics_)
-                    << "Misaligned MSL structure member " << mem_name << " : " << ty->FriendlyName()
-                    << " offset: " << msl_offset << " align: " << size_align.align;
+                TINT_ICE() << "Misaligned MSL structure member " << mem_name << " : "
+                           << ty->FriendlyName() << " offset: " << msl_offset
+                           << " align: " << size_align.align;
                 return;
             }
             msl_offset += size_align.size;
diff --git a/src/tint/lang/msl/writer/printer_support.cc b/src/tint/lang/msl/writer/printer_support.cc
index b664b57..6c5ea87 100644
--- a/src/tint/lang/msl/writer/printer_support.cc
+++ b/src/tint/lang/msl/writer/printer_support.cc
@@ -26,7 +26,7 @@
 #include "src/tint/lang/core/type/struct.h"
 #include "src/tint/lang/core/type/u32.h"
 #include "src/tint/lang/core/type/vector.h"
-#include "src/tint/utils/debug/debug.h"
+#include "src/tint/utils/ice/ice.h"
 #include "src/tint/utils/rtti/switch.h"
 #include "src/tint/utils/text/float_to_string.h"
 
@@ -134,8 +134,7 @@
                     return SizeAndAlign{num_els * el_size_align.size, num_els * el_size_align.size};
                 }
             }
-            TINT_UNREACHABLE(Writer, diagnostics)
-                << "Unhandled vector element type " << el_ty->TypeInfo().name;
+            TINT_UNREACHABLE() << "Unhandled vector element type " << el_ty->TypeInfo().name;
             return SizeAndAlign{};
         },
 
@@ -178,14 +177,13 @@
                 }
             }
 
-            TINT_UNREACHABLE(Writer, diagnostics)
-                << "Unhandled matrix element type " << el_ty->TypeInfo().name;
+            TINT_UNREACHABLE() << "Unhandled matrix element type " << el_ty->TypeInfo().name;
             return SizeAndAlign{};
         },
 
         [&](const type::Array* arr) {
             if (TINT_UNLIKELY(!arr->IsStrideImplicit())) {
-                TINT_ICE(Writer, diagnostics)
+                TINT_ICE()
                     << "arrays with explicit strides should not exist past the SPIR-V reader";
                 return SizeAndAlign{};
             }
@@ -211,7 +209,7 @@
         },
 
         [&](Default) {
-            TINT_UNREACHABLE(Writer, diagnostics) << "Unhandled type " << ty->TypeInfo().name;
+            TINT_UNREACHABLE() << "Unhandled type " << ty->TypeInfo().name;
             return SizeAndAlign{};
         });
 }
diff --git a/src/tint/lang/spirv/reader/ast_parser/ast_parser.cc b/src/tint/lang/spirv/reader/ast_parser/ast_parser.cc
index 80a2b3c..41276fe 100644
--- a/src/tint/lang/spirv/reader/ast_parser/ast_parser.cc
+++ b/src/tint/lang/spirv/reader/ast_parser/ast_parser.cc
@@ -882,8 +882,8 @@
             // Reuse the inner implementation owned by the first entry point.
             inner_implementation_name = where->second[0].inner_name;
         }
-        TINT_ASSERT(Reader, !inner_implementation_name.empty());
-        TINT_ASSERT(Reader, ep_name != inner_implementation_name);
+        TINT_ASSERT(!inner_implementation_name.empty());
+        TINT_ASSERT(ep_name != inner_implementation_name);
 
         UniqueVector<uint32_t, 8> inputs;
         UniqueVector<uint32_t, 8> outputs;
@@ -1490,7 +1490,7 @@
                               << var.type_id();
             }
         }
-        TINT_ASSERT(Reader, ast_store_type != nullptr);
+        TINT_ASSERT(ast_store_type != nullptr);
 
         const ast::Expression* ast_initializer = nullptr;
         if (var.NumInOperands() > 1) {
@@ -1771,7 +1771,7 @@
     builtin::InterpolationSampling sampling = builtin::InterpolationSampling::kUndefined;
 
     for (const auto& deco : decorations) {
-        TINT_ASSERT(Reader, deco.size() > 0);
+        TINT_ASSERT(deco.size() > 0);
         switch (static_cast<spv::Decoration>(deco[0])) {
             case spv::Decoration::Location:
                 if (deco.size() != 2) {
diff --git a/src/tint/lang/spirv/reader/ast_parser/function.cc b/src/tint/lang/spirv/reader/ast_parser/function.cc
index ad14013..e18b4ba 100644
--- a/src/tint/lang/spirv/reader/ast_parser/function.cc
+++ b/src/tint/lang/spirv/reader/ast_parser/function.cc
@@ -834,7 +834,7 @@
 FunctionEmitter::StatementBlock::~StatementBlock() = default;
 
 void FunctionEmitter::StatementBlock::Finalize(ProgramBuilder* pb) {
-    TINT_ASSERT(Reader, !finalized_ /* Finalize() must only be called once */);
+    TINT_ASSERT(!finalized_ /* Finalize() must only be called once */);
 
     for (size_t i = 0; i < statements_.Length(); i++) {
         if (auto* sb = statements_[i]->As<StatementBuilder>()) {
@@ -850,7 +850,7 @@
 }
 
 void FunctionEmitter::StatementBlock::Add(const ast::Statement* statement) {
-    TINT_ASSERT(Reader, !finalized_ /* Add() must not be called after Finalize() */);
+    TINT_ASSERT(!finalized_ /* Add() must not be called after Finalize() */);
     statements_.Push(statement);
 }
 
@@ -861,8 +861,8 @@
 }
 
 void FunctionEmitter::PushGuard(const std::string& guard_name, uint32_t end_id) {
-    TINT_ASSERT(Reader, !statements_stack_.IsEmpty());
-    TINT_ASSERT(Reader, !guard_name.empty());
+    TINT_ASSERT(!statements_stack_.IsEmpty());
+    TINT_ASSERT(!guard_name.empty());
     // Guard control flow by the guard variable.  Introduce a new
     // if-selection with a then-clause ending at the same block
     // as the statement block at the top of the stack.
@@ -877,7 +877,7 @@
 }
 
 void FunctionEmitter::PushTrueGuard(uint32_t end_id) {
-    TINT_ASSERT(Reader, !statements_stack_.IsEmpty());
+    TINT_ASSERT(!statements_stack_.IsEmpty());
     const auto& top = statements_stack_.Back();
 
     auto* cond = MakeTrue(Source{});
@@ -889,14 +889,14 @@
 }
 
 FunctionEmitter::StatementList FunctionEmitter::ast_body() {
-    TINT_ASSERT(Reader, !statements_stack_.IsEmpty());
+    TINT_ASSERT(!statements_stack_.IsEmpty());
     auto& entry = statements_stack_[0];
     entry.Finalize(&builder_);
     return entry.GetStatements();
 }
 
 const ast::Statement* FunctionEmitter::AddStatement(const ast::Statement* statement) {
-    TINT_ASSERT(Reader, !statements_stack_.IsEmpty());
+    TINT_ASSERT(!statements_stack_.IsEmpty());
     if (statement != nullptr) {
         statements_stack_.Back().Add(statement);
     }
@@ -904,9 +904,9 @@
 }
 
 const ast::Statement* FunctionEmitter::LastStatement() {
-    TINT_ASSERT(Reader, !statements_stack_.IsEmpty());
+    TINT_ASSERT(!statements_stack_.IsEmpty());
     auto& statement_list = statements_stack_.Back().GetStatements();
-    TINT_ASSERT(Reader, !statement_list.IsEmpty());
+    TINT_ASSERT(!statement_list.IsEmpty());
     return statement_list.Back();
 }
 
@@ -928,7 +928,7 @@
 
     bool make_body_function = true;
     if (ep_info_) {
-        TINT_ASSERT(Reader, !ep_info_->inner_name.empty());
+        TINT_ASSERT(!ep_info_->inner_name.empty());
         if (ep_info_->owns_inner_implementation) {
             // This is an entry point, and we want to emit it as a wrapper around
             // an implementation function.
@@ -958,7 +958,7 @@
 }
 
 const ast::BlockStatement* FunctionEmitter::MakeFunctionBody() {
-    TINT_ASSERT(Reader, statements_stack_.Length() == 1);
+    TINT_ASSERT(statements_stack_.Length() == 1);
 
     if (!EmitBody()) {
         return nullptr;
@@ -1250,8 +1250,8 @@
     // have already been created.
     for (uint32_t var_id : ep_info_->inputs) {
         const auto* var = def_use_mgr_->GetDef(var_id);
-        TINT_ASSERT(Reader, var != nullptr);
-        TINT_ASSERT(Reader, opcode(var) == spv::Op::OpVariable);
+        TINT_ASSERT(var != nullptr);
+        TINT_ASSERT(opcode(var) == spv::Op::OpVariable);
         auto* store_type = GetVariableStoreType(*var);
         auto* forced_param_type = store_type;
         Attributes param_attrs;
@@ -1275,7 +1275,7 @@
             // In Vulkan SPIR-V, the sample mask is an array. In WGSL it's a scalar.
             // Use the first element only.
             auto* sample_mask_array_type = store_type->UnwrapRef()->UnwrapAlias()->As<Array>();
-            TINT_ASSERT(Reader, sample_mask_array_type);
+            TINT_ASSERT(sample_mask_array_type);
             ok = EmitPipelineInput(var_name, store_type, {0}, sample_mask_array_type->type,
                                    forced_param_type, param_attrs, decl.params, stmts);
         } else {
@@ -1323,8 +1323,8 @@
 
             } else {
                 const auto* var = def_use_mgr_->GetDef(var_id);
-                TINT_ASSERT(Reader, var != nullptr);
-                TINT_ASSERT(Reader, opcode(var) == spv::Op::OpVariable);
+                TINT_ASSERT(var != nullptr);
+                TINT_ASSERT(opcode(var) == spv::Op::OpVariable);
                 const Type* store_type = GetVariableStoreType(*var);
                 const Type* forced_member_type = store_type;
                 Attributes out_attrs;
@@ -1345,7 +1345,7 @@
                     // scalar. Use the first element only.
                     auto* sample_mask_array_type =
                         store_type->UnwrapRef()->UnwrapAlias()->As<Array>();
-                    TINT_ASSERT(Reader, sample_mask_array_type);
+                    TINT_ASSERT(sample_mask_array_type);
                     ok = EmitPipelineOutput(var_name, store_type, {0}, sample_mask_array_type->type,
                                             forced_member_type, out_attrs, return_members,
                                             return_exprs);
@@ -1421,7 +1421,7 @@
     function_.ForEachParam([this, &ast_params](const spvtools::opt::Instruction* param) {
         // Valid SPIR-V requires function call parameters to be non-null
         // instructions.
-        TINT_ASSERT(Reader, param != nullptr);
+        TINT_ASSERT(param != nullptr);
         const Type* const type = IsHandleObj(*param)
                                      ? parser_impl_.GetHandleTypeForSpirvHandle(*param)
                                      : parser_impl_.ConvertType(param->type_id());
@@ -1449,9 +1449,9 @@
 }
 
 bool FunctionEmitter::IsHandleObj(const spvtools::opt::Instruction& obj) {
-    TINT_ASSERT(Reader, obj.type_id() != 0u);
+    TINT_ASSERT(obj.type_id() != 0u);
     auto* spirv_type = type_mgr_->GetType(obj.type_id());
-    TINT_ASSERT(Reader, spirv_type);
+    TINT_ASSERT(spirv_type);
     return spirv_type->AsImage() || spirv_type->AsSampler() ||
            (spirv_type->AsPointer() &&
             (static_cast<spv::StorageClass>(spirv_type->AsPointer()->storage_class()) ==
@@ -1765,7 +1765,7 @@
     //      block. Also mark the the most recent continue target for which we
     //      haven't reached the backedge block.
 
-    TINT_ASSERT(Reader, block_order_.size() > 0);
+    TINT_ASSERT(block_order_.size() > 0);
     constructs_.Clear();
     const auto entry_id = block_order_[0];
 
@@ -1785,8 +1785,8 @@
         // A loop construct is added right after its associated continue construct.
         // In that case, adjust the parent up.
         if (k == Construct::kLoop) {
-            TINT_ASSERT(Reader, parent);
-            TINT_ASSERT(Reader, parent->kind == Construct::kContinue);
+            TINT_ASSERT(parent);
+            TINT_ASSERT(parent->kind == Construct::kContinue);
             scope_end_pos = parent->end_pos;
             parent = parent->parent;
         }
@@ -1804,9 +1804,9 @@
 
     for (uint32_t i = 0; i < block_order_.size(); ++i) {
         const auto block_id = block_order_[i];
-        TINT_ASSERT(Reader, block_id > 0);
+        TINT_ASSERT(block_id > 0);
         auto* block_info = GetBlockInfo(block_id);
-        TINT_ASSERT(Reader, block_info);
+        TINT_ASSERT(block_info);
 
         if (enclosing.IsEmpty()) {
             return Fail() << "internal error: too many merge blocks before block " << block_id;
@@ -1875,7 +1875,7 @@
             }
         }
 
-        TINT_ASSERT(Reader, top);
+        TINT_ASSERT(top);
         block_info->construct = top;
     }
 
@@ -2076,9 +2076,9 @@
     //    NEC(S) is the parent of NEC(T).
 
     for (const auto src : block_order_) {
-        TINT_ASSERT(Reader, src > 0);
+        TINT_ASSERT(src > 0);
         auto* src_info = GetBlockInfo(src);
-        TINT_ASSERT(Reader, src_info);
+        TINT_ASSERT(src_info);
         const auto src_pos = src_info->pos;
         const auto& src_construct = *(src_info->construct);
 
@@ -2115,7 +2115,7 @@
         for (const auto dest : successors) {
             const auto* dest_info = GetBlockInfo(dest);
             // We've already checked terminators are valid.
-            TINT_ASSERT(Reader, dest_info);
+            TINT_ASSERT(dest_info);
             const auto dest_pos = dest_info->pos;
 
             // Insert the edge kind entry and keep a handle to update
@@ -2139,7 +2139,7 @@
                                   << src_construct.begin_id << " (violates post-dominance rule)";
                 }
                 const auto* ct_info = GetBlockInfo(continue_construct->begin_id);
-                TINT_ASSERT(Reader, ct_info);
+                TINT_ASSERT(ct_info);
                 if (ct_info->header_for_continue != dest) {
                     return Fail() << "Invalid backedge (" << src << "->" << dest
                                   << "): does not branch to the corresponding loop header, "
@@ -2422,7 +2422,7 @@
             // The first clause might be a then-clause or an else-clause.
             const auto second_head = std::max(true_head_pos, false_head_pos);
             const auto end_first_clause_pos = second_head - 1;
-            TINT_ASSERT(Reader, end_first_clause_pos < block_order_.size());
+            TINT_ASSERT(end_first_clause_pos < block_order_.size());
             const auto end_first_clause = block_order_[end_first_clause_pos];
             uint32_t premerge_id = 0;
             uint32_t if_break_id = 0;
@@ -2542,7 +2542,7 @@
         case SkipReason::kSinkPointerIntoUse: {
             // Replace the pointer with its source reference expression.
             auto source_expr = GetDefInfo(id)->sink_pointer_source_expr;
-            TINT_ASSERT(Reader, source_expr.type->Is<Reference>());
+            TINT_ASSERT(source_expr.type->Is<Reference>());
             return source_expr;
         }
         case SkipReason::kPointSizeBuiltinValue: {
@@ -2631,15 +2631,15 @@
 
     // Upon entry, the statement stack has one entry representing the whole
     // function.
-    TINT_ASSERT(Reader, !constructs_.IsEmpty());
+    TINT_ASSERT(!constructs_.IsEmpty());
     Construct* function_construct = constructs_[0].get();
-    TINT_ASSERT(Reader, function_construct != nullptr);
-    TINT_ASSERT(Reader, function_construct->kind == Construct::kFunction);
+    TINT_ASSERT(function_construct != nullptr);
+    TINT_ASSERT(function_construct->kind == Construct::kFunction);
     // Make the first entry valid by filling in the construct field, which
     // had not been computed at the time the entry was first created.
     // TODO(dneto): refactor how the first construct is created vs.
     // this statements stack entry is populated.
-    TINT_ASSERT(Reader, statements_stack_.Length() == 1);
+    TINT_ASSERT(statements_stack_.Length() == 1);
     statements_stack_[0].SetConstruct(function_construct);
 
     for (auto block_id : block_order()) {
@@ -2833,8 +2833,8 @@
 bool FunctionEmitter::EmitIfStart(const BlockInfo& block_info) {
     // The block is the if-header block.  So its construct is the if construct.
     auto* construct = block_info.construct;
-    TINT_ASSERT(Reader, construct->kind == Construct::kIfSelection);
-    TINT_ASSERT(Reader, construct->begin_id == block_info.id);
+    TINT_ASSERT(construct->kind == Construct::kIfSelection);
+    TINT_ASSERT(construct->begin_id == block_info.id);
 
     const uint32_t true_head = block_info.true_head;
     const uint32_t false_head = block_info.false_head;
@@ -2968,8 +2968,8 @@
 bool FunctionEmitter::EmitSwitchStart(const BlockInfo& block_info) {
     // The block is the if-header block.  So its construct is the if construct.
     auto* construct = block_info.construct;
-    TINT_ASSERT(Reader, construct->kind == Construct::kSwitchSelection);
-    TINT_ASSERT(Reader, construct->begin_id == block_info.id);
+    TINT_ASSERT(construct->kind == Construct::kSwitchSelection);
+    TINT_ASSERT(construct->begin_id == block_info.id);
     const auto* branch = block_info.basic_block->terminator();
 
     const auto selector_id = branch->GetSingleWordInOperand(0);
@@ -3016,7 +3016,7 @@
             clause_heads[w] = clause_heads[r];
         }
         // We know it's not empty because it always has at least a default clause.
-        TINT_ASSERT(Reader, !clause_heads.IsEmpty());
+        TINT_ASSERT(!clause_heads.IsEmpty());
         clause_heads.Resize(w + 1);
     }
 
@@ -3054,7 +3054,7 @@
             // Generate a default selector
             selectors.Push(create<ast::CaseSelector>(Source{}));
         }
-        TINT_ASSERT(Reader, !selectors.IsEmpty());
+        TINT_ASSERT(!selectors.IsEmpty());
 
         // Where does this clause end?
         const auto end_id =
@@ -3178,8 +3178,8 @@
                 block_info.construct && block_info.construct->kind == Construct::Kind::kContinue) {
                 auto* header = GetBlockInfo(block_info.construct->begin_id);
 
-                TINT_ASSERT(Reader, header->construct &&
-                                        header->construct->kind == Construct::Kind::kContinue);
+                TINT_ASSERT(header->construct &&
+                            header->construct->kind == Construct::Kind::kContinue);
                 if (!header->is_continue_entire_loop) {
                     needs_break_if = true;
                 }
@@ -3249,9 +3249,9 @@
         case EdgeKind::kSwitchBreak: {
             // Don't bother with a break at the end of a case/default clause.
             const auto header = dest_info.header_for_merge;
-            TINT_ASSERT(Reader, header != 0);
+            TINT_ASSERT(header != 0);
             const auto* exiting_construct = GetBlockInfo(header)->construct;
-            TINT_ASSERT(Reader, exiting_construct->kind == Construct::kSwitchSelection);
+            TINT_ASSERT(exiting_construct->kind == Construct::kSwitchSelection);
             const auto candidate_next_case_pos = src_info.pos + 1;
             // Leaving the last block from the last case?
             if (candidate_next_case_pos == dest_info.pos) {
@@ -3349,7 +3349,7 @@
     // Emit declarations of hoisted variables, in index order.
     for (auto id : sorted_by_index(block_info.hoisted_ids)) {
         const auto* def_inst = def_use_mgr_->GetDef(id);
-        TINT_ASSERT(Reader, def_inst);
+        TINT_ASSERT(def_inst);
         // Compute the store type.  Pointers are not storable, so there is
         // no need to remap pointer properties.
         auto* store_type = parser_impl_.ConvertType(def_inst->type_id());
@@ -3514,7 +3514,7 @@
         if (combinatorial_expr.expr != nullptr) {
             // If the expression is combinatorial, then it's not a direct access
             // of a builtin variable.
-            TINT_ASSERT(Reader, def_info->local.has_value());
+            TINT_ASSERT(def_info->local.has_value());
             if (def_info->requires_hoisted_var_def || def_info->requires_named_let_def ||
                 def_info->local->num_uses != 1) {
                 // Generate a const definition or an assignment to a hoisted definition
@@ -3595,7 +3595,7 @@
                     if (auto* arr = lhs.type->As<Array>()) {
                         lhs.type = arr->type;
                     }
-                    TINT_ASSERT(Reader, lhs.type);
+                    TINT_ASSERT(lhs.type);
                     break;
                 default:
                     break;
@@ -3994,7 +3994,7 @@
         switch (ext_opcode) {
             case GLSLstd450Determinant: {
                 auto m = MakeOperand(inst, 2);
-                TINT_ASSERT(Reader, m.type->Is<Matrix>());
+                TINT_ASSERT(m.type->Is<Matrix>());
                 return {ty_.F32(), builder_.Call("determinant", m.expr)};
             }
 
@@ -4012,9 +4012,9 @@
                 auto normal = MakeOperand(inst, 2);
                 auto incident = MakeOperand(inst, 3);
                 auto nref = MakeOperand(inst, 4);
-                TINT_ASSERT(Reader, normal.type->Is<F32>());
-                TINT_ASSERT(Reader, incident.type->Is<F32>());
-                TINT_ASSERT(Reader, nref.type->Is<F32>());
+                TINT_ASSERT(normal.type->Is<F32>());
+                TINT_ASSERT(incident.type->Is<F32>());
+                TINT_ASSERT(nref.type->Is<F32>());
                 return {
                     ty_.F32(),
                     builder_.Call(
@@ -4034,8 +4034,8 @@
                 // Compute  Incident - 2 * Normal * Normal * Incident
                 auto incident = MakeOperand(inst, 2);
                 auto normal = MakeOperand(inst, 3);
-                TINT_ASSERT(Reader, incident.type->Is<F32>());
-                TINT_ASSERT(Reader, normal.type->Is<F32>());
+                TINT_ASSERT(incident.type->Is<F32>());
+                TINT_ASSERT(normal.type->Is<F32>());
                 return {
                     ty_.F32(),
                     builder_.Sub(
@@ -4051,9 +4051,9 @@
                 auto incident = MakeOperand(inst, 2);
                 auto normal = MakeOperand(inst, 3);
                 auto eta = MakeOperand(inst, 4);
-                TINT_ASSERT(Reader, incident.type->Is<F32>());
-                TINT_ASSERT(Reader, normal.type->Is<F32>());
-                TINT_ASSERT(Reader, eta.type->Is<F32>());
+                TINT_ASSERT(incident.type->Is<F32>());
+                TINT_ASSERT(normal.type->Is<F32>());
+                TINT_ASSERT(eta.type->Is<F32>());
                 if (!success()) {
                     return {};
                 }
@@ -4111,8 +4111,8 @@
     const spvtools::opt::Instruction& inst) {
     auto mat = MakeOperand(inst, 2);
     auto* mat_ty = mat.type->As<Matrix>();
-    TINT_ASSERT(Reader, mat_ty);
-    TINT_ASSERT(Reader, mat_ty->columns == mat_ty->rows);
+    TINT_ASSERT(mat_ty);
+    TINT_ASSERT(mat_ty->columns == mat_ty->rows);
     auto& pb = builder_;
 
     auto idx = [&](size_t row, size_t col) {
@@ -4530,7 +4530,7 @@
         }
         const auto pointer_type_id = type_mgr_->FindPointerToType(pointee_type_id, address_space);
         auto* type = parser_impl_.ConvertType(pointer_type_id, PtrAs::Ref);
-        TINT_ASSERT(Reader, type && type->Is<Reference>());
+        TINT_ASSERT(type && type->Is<Reference>());
         current_expr = TypedExpression{type, next_expr};
     }
 
@@ -4712,7 +4712,7 @@
     // Helper to get the name for the component index `i`.
     auto component_name = [](uint32_t i) {
         constexpr const char* names[] = {"x", "y", "z", "w"};
-        TINT_ASSERT(Reader, i < 4);
+        TINT_ASSERT(i < 4);
         return names[i];
     };
 
@@ -4732,7 +4732,7 @@
         } else if (index < vec0_len + vec1_len) {
             vec_id = vec1_id;
             index -= vec0_len;
-            TINT_ASSERT(Reader, index < kMaxVectorLen);
+            TINT_ASSERT(index < kMaxVectorLen);
         } else if (index == 0xFFFFFFFF) {
             // By rule, this maps to OpUndef. Instead, take the first component of the first vector.
             vec_id = vec0_id;
@@ -4905,7 +4905,7 @@
             default:
                 break;
         }
-        TINT_ASSERT(Reader, false && "expected a memory object declaration");
+        TINT_UNREACHABLE() << "expected a memory object declaration";
         return {};
     };
 
@@ -4929,7 +4929,7 @@
         return info->pointer;
     }
     const auto* inst = def_use_mgr_->GetDef(id);
-    TINT_ASSERT(Reader, inst);
+    TINT_ASSERT(inst);
     return get_from_root_identifier(*inst);
 }
 
@@ -5151,7 +5151,7 @@
 
 const Construct* FunctionEmitter::GetEnclosingScope(uint32_t first_pos, uint32_t last_pos) const {
     const auto* enclosing_construct = GetBlockInfo(block_order_[first_pos])->construct;
-    TINT_ASSERT(Reader, enclosing_construct != nullptr);
+    TINT_ASSERT(enclosing_construct != nullptr);
     // Constructs are strictly nesting, so follow parent pointers
     while (enclosing_construct && !enclosing_construct->ScopeContainsPos(last_pos)) {
         // The scope of a continue construct is enclosed in its associated loop
@@ -5161,7 +5161,7 @@
         enclosing_construct = sibling_loop ? sibling_loop : enclosing_construct->parent;
     }
     // At worst, we go all the way out to the function construct.
-    TINT_ASSERT(Reader, enclosing_construct != nullptr);
+    TINT_ASSERT(enclosing_construct != nullptr);
     return enclosing_construct;
 }
 
@@ -5420,7 +5420,7 @@
         Fail();
         return {};
     }
-    TINT_ASSERT(Reader, type != nullptr);
+    TINT_ASSERT(type != nullptr);
     if (auto* result = type->UnwrapAll()->As<Texture>()) {
         return result;
     }
@@ -6095,9 +6095,9 @@
 
     // The texel type is always a 4-element vector.
     const uint32_t dest_count = 4u;
-    TINT_ASSERT(Reader, dest_type->Is<Vector>() && dest_type->As<Vector>()->size == dest_count);
-    TINT_ASSERT(Reader, dest_type->IsFloatVector() || dest_type->IsUnsignedIntegerVector() ||
-                            dest_type->IsSignedIntegerVector());
+    TINT_ASSERT(dest_type->Is<Vector>() && dest_type->As<Vector>()->size == dest_count);
+    TINT_ASSERT(dest_type->IsFloatVector() || dest_type->IsUnsignedIntegerVector() ||
+                dest_type->IsSignedIntegerVector());
 
     if (src_type == dest_type) {
         return texel.expr;
@@ -6115,7 +6115,7 @@
     }
 
     const auto required_count = parser_impl_.GetChannelCountForFormat(format);
-    TINT_ASSERT(Reader, 0 < required_count && required_count <= 4);
+    TINT_ASSERT(0 < required_count && required_count <= 4);
 
     const uint32_t src_count = src_type->IsScalar() ? 1 : src_type->As<Vector>()->size;
     if (src_count < required_count) {
diff --git a/src/tint/lang/spirv/reader/ast_parser/function.h b/src/tint/lang/spirv/reader/ast_parser/function.h
index 91544ab..29ad3da 100644
--- a/src/tint/lang/spirv/reader/ast_parser/function.h
+++ b/src/tint/lang/spirv/reader/ast_parser/function.h
@@ -1159,7 +1159,7 @@
     /// @return the built StatementBuilder
     template <typename T, typename... ARGS>
     T* AddStatementBuilder(ARGS&&... args) {
-        TINT_ASSERT(Reader, !statements_stack_.IsEmpty());
+        TINT_ASSERT(!statements_stack_.IsEmpty());
         return statements_stack_.Back().AddStatementBuilder<T>(std::forward<ARGS>(args)...);
     }
 
diff --git a/src/tint/lang/spirv/reader/ast_parser/namer.cc b/src/tint/lang/spirv/reader/ast_parser/namer.cc
index e48bc65..38581b5 100644
--- a/src/tint/lang/spirv/reader/ast_parser/namer.cc
+++ b/src/tint/lang/spirv/reader/ast_parser/namer.cc
@@ -18,7 +18,7 @@
 #include <unordered_set>
 
 #include "src/tint/lang/core/builtin/function.h"
-#include "src/tint/utils/debug/debug.h"
+#include "src/tint/utils/ice/ice.h"
 #include "src/tint/utils/text/string_stream.h"
 
 namespace tint::spirv::reader {
@@ -234,14 +234,14 @@
         }
         i++;
     }
-    TINT_ASSERT(Reader, false /* FindUnusedDerivedName() overflowed u32 */);
+    TINT_UNREACHABLE() << "FindUnusedDerivedName() overflowed u32";
     return "<u32 overflow>";
 }
 
 std::string Namer::MakeDerivedName(const std::string& base_name) {
     auto result = FindUnusedDerivedName(base_name);
     const bool registered = RegisterWithoutId(result);
-    TINT_ASSERT(Reader, registered);
+    TINT_ASSERT(registered);
     return result;
 }
 
diff --git a/src/tint/lang/spirv/writer/ast_printer/builder.cc b/src/tint/lang/spirv/writer/ast_printer/builder.cc
index f317a93..4eadf19 100644
--- a/src/tint/lang/spirv/writer/ast_printer/builder.cc
+++ b/src/tint/lang/spirv/writer/ast_printer/builder.cc
@@ -301,8 +301,7 @@
 uint32_t Builder::LookupVariableID(const sem::Variable* var) {
     auto it = var_to_id_.find(var);
     if (it == var_to_id_.end()) {
-        TINT_ICE(Writer, builder_.Diagnostics())
-            << "unable to find ID for variable: " + var->Declaration()->name->symbol.Name();
+        TINT_ICE() << "unable to find ID for variable: " + var->Declaration()->name->symbol.Name();
         return 0;
     }
     return it->second;
@@ -376,7 +375,7 @@
 
 bool Builder::GenerateBreakStatement(const ast::BreakStatement*) {
     if (merge_stack_.empty()) {
-        TINT_ICE(Writer, builder_.Diagnostics()) << "Attempted to break without a merge block";
+        TINT_ICE() << "Attempted to break without a merge block";
         return false;
     }
     if (!push_function_inst(spv::Op::OpBranch, {Operand(merge_stack_.back())})) {
@@ -386,7 +385,7 @@
 }
 
 bool Builder::GenerateBreakIfStatement(const ast::BreakIfStatement* stmt) {
-    TINT_ASSERT(Writer, !backedge_stack_.empty());
+    TINT_ASSERT(!backedge_stack_.empty());
     const auto cond_id = GenerateExpression(stmt->condition);
     if (!cond_id) {
         return false;
@@ -400,8 +399,7 @@
 
 bool Builder::GenerateContinueStatement(const ast::ContinueStatement*) {
     if (continue_stack_.empty()) {
-        TINT_ICE(Writer, builder_.Diagnostics())
-            << "Attempted to continue without a continue block";
+        TINT_ICE() << "Attempted to continue without a continue block";
         return false;
     }
     if (!push_function_inst(spv::Op::OpBranch, {Operand(continue_stack_.back())})) {
@@ -423,7 +421,7 @@
 bool Builder::GenerateEntryPoint(const ast::Function* func, uint32_t id) {
     auto stage = pipeline_stage_to_execution_model(func->PipelineStage());
     if (stage == SpvExecutionModelMax) {
-        TINT_ICE(Writer, builder_.Diagnostics()) << "Unknown pipeline stage provided";
+        TINT_ICE() << "Unknown pipeline stage provided";
         return false;
     }
 
@@ -440,8 +438,8 @@
 
         uint32_t var_id = LookupVariableID(var);
         if (var_id == 0) {
-            TINT_ICE(Writer, builder_.Diagnostics()) << "unable to find ID for global variable: " +
-                                                            var->Declaration()->name->symbol.Name();
+            TINT_ICE() << "unable to find ID for global variable: " +
+                              var->Declaration()->name->symbol.Name();
             return false;
         }
 
@@ -464,7 +462,7 @@
 
         // Check if the workgroup_size uses pipeline-overridable constants.
         if (!wgsize[0].has_value() || !wgsize[1].has_value() || !wgsize[2].has_value()) {
-            TINT_ICE(Writer, builder_.Diagnostics())
+            TINT_ICE()
                 << "override-expressions should have been removed with the SubstituteOverride "
                    "transform";
             return false;
@@ -509,8 +507,7 @@
         [&](const ast::LiteralExpression* l) { return GenerateLiteralIfNeeded(l); },
         [&](const ast::UnaryOpExpression* u) { return GenerateUnaryOpExpression(u); },
         [&](Default) {
-            TINT_ICE(Writer, builder_.Diagnostics())
-                << "unknown expression type: " + std::string(expr->TypeInfo().name);
+            TINT_ICE() << "unknown expression type: " + std::string(expr->TypeInfo().name);
             return 0;
         });
 }
@@ -642,7 +639,7 @@
 
     if (v->Is<ast::Let>()) {
         if (!v->initializer) {
-            TINT_ICE(Writer, builder_.Diagnostics()) << "missing initializer for let";
+            TINT_ICE() << "missing initializer for let";
             return false;
         }
         RegisterVariable(sem, init_id);
@@ -693,8 +690,7 @@
 
     auto* sem = builder_.Sem().Get<sem::GlobalVariable>(v);
     if (TINT_UNLIKELY(!sem)) {
-        TINT_ICE(Writer, builder_.Diagnostics())
-            << "attempted to generate a global from a non-global variable";
+        TINT_ICE() << "attempted to generate a global from a non-global variable";
         return false;
     }
     auto* type = sem->Type()->UnwrapRef();
@@ -829,7 +825,7 @@
                 return true;  // ignored
             },
             [&](Default) {
-                TINT_ICE(Writer, builder_.Diagnostics()) << "unknown attribute";
+                TINT_ICE() << "unknown attribute";
                 return false;
             });
         if (!ok) {
@@ -898,7 +894,7 @@
         return true;
     }
 
-    TINT_ICE(Writer, builder_.Diagnostics()) << "unsupported index accessor expression";
+    TINT_ICE() << "unsupported index accessor expression";
     return false;
 }
 
@@ -1020,8 +1016,7 @@
             return true;
         },
         [&](Default) {
-            TINT_ICE(Writer, builder_.Diagnostics())
-                << "unhandled member index type: " << expr_sem->TypeInfo().name;
+            TINT_ICE() << "unhandled member index type: " << expr_sem->TypeInfo().name;
             return false;
         });
 }
@@ -1069,8 +1064,7 @@
                 return GenerateMemberAccessor(member, &info);
             },
             [&](Default) {
-                TINT_ICE(Writer, builder_.Diagnostics())
-                    << "invalid accessor in list: " + std::string(accessor->TypeInfo().name);
+                TINT_ICE() << "invalid accessor in list: " + std::string(accessor->TypeInfo().name);
                 return false;
             });
         if (!ok) {
@@ -1108,8 +1102,8 @@
             return LookupVariableID(user->Variable());
         }
     }
-    TINT_ICE(Writer, builder_.Diagnostics())
-        << "identifier '" + expr->identifier->symbol.Name() + "' does not resolve to a variable";
+    TINT_ICE() << "identifier '" + expr->identifier->symbol.Name() +
+                      "' does not resolve to a variable";
     return 0;
 }
 
@@ -1203,13 +1197,13 @@
             return GenerateValueConstructorOrConversion(call, var);
         }
     }
-    TINT_ICE(Writer, builder_.Diagnostics()) << "unknown constructor expression";
+    TINT_ICE() << "unknown constructor expression";
     return 0;
 }
 
 bool Builder::IsConstructorConst(const ast::Expression* expr) {
     bool is_const = true;
-    ast::TraverseExpressions(expr, builder_.Diagnostics(), [&](const ast::Expression* e) {
+    ast::TraverseExpressions(expr, [&](const ast::Expression* e) {
         if (e->Is<ast::LiteralExpression>()) {
             return ast::TraverseAction::Descend;
         }
@@ -1366,7 +1360,7 @@
                 ops.push_back(Operand(extract_id));
             }
         } else {
-            TINT_ICE(Writer, builder_.Diagnostics()) << "Unhandled type cast value type";
+            TINT_ICE() << "Unhandled type cast value type";
             return 0;
         }
     }
@@ -1409,9 +1403,8 @@
     // This should not happen as we rely on constant folding to obviate
     // casts/conversions for module-scope variables
     if (TINT_UNLIKELY(is_global_init)) {
-        TINT_ICE(Writer, builder_.Diagnostics())
-            << "Module-level conversions are not supported. Conversions should "
-               "have already been constant-folded by the FoldConstants transform.";
+        TINT_ICE() << "Module-level conversions are not supported. Conversions should "
+                      "have already been constant-folded by the FoldConstants transform.";
         return 0;
     }
 
@@ -1506,8 +1499,7 @@
             zero_id = GenerateConstantIfNeeded(ScalarConstant::I32(0));
             one_id = GenerateConstantIfNeeded(ScalarConstant::I32(1));
         } else {
-            TINT_ICE(Writer, builder_.Diagnostics())
-                << "invalid destination type for bool conversion";
+            TINT_ICE() << "invalid destination type for bool conversion";
             return false;
         }
         if (auto* to_vec = to_type->As<type::Vector>()) {
@@ -1535,17 +1527,15 @@
         if (TINT_LIKELY(from_mat == to_mat)) {
             return val_id;
         }
-        TINT_ICE(Writer, builder_.Diagnostics())
-            << "matrix conversion is not supported and should have been handled by "
-               "VectorizeMatrixConversions";
+        TINT_ICE() << "matrix conversion is not supported and should have been handled by "
+                      "VectorizeMatrixConversions";
     } else {
-        TINT_ICE(Writer, builder_.Diagnostics()) << "Invalid from_type";
+        TINT_ICE() << "Invalid from_type";
     }
 
     if (op == spv::Op::OpNop) {
-        TINT_ICE(Writer, builder_.Diagnostics())
-            << "unable to determine conversion type for cast, from: " + from_type->FriendlyName() +
-                   " to: " + to_type->FriendlyName();
+        TINT_ICE() << "unable to determine conversion type for cast, from: " +
+                          from_type->FriendlyName() + " to: " + to_type->FriendlyName();
         return 0;
     }
 
@@ -1590,7 +1580,7 @@
                     return;
             }
         },
-        [&](Default) { TINT_ICE(Writer, builder_.Diagnostics()) << "unknown literal type"; });
+        [&](Default) { TINT_ICE() << "unknown literal type"; });
 
     if (has_error()) {
         return false;
@@ -1663,15 +1653,14 @@
         [&](const type::Array* a) {
             auto count = a->ConstantCount();
             if (!count) {
-                TINT_ICE(Writer, builder_.Diagnostics()) << type::Array::kErrExpectedConstantCount;
+                TINT_ICE() << type::Array::kErrExpectedConstantCount;
                 return static_cast<uint32_t>(0);
             }
             return composite(count.value());
         },
         [&](const type::Struct* s) { return composite(s->Members().Length()); },
         [&](Default) {
-            TINT_ICE(Writer, builder_.Diagnostics())
-                << "unhandled constant type: " + ty->FriendlyName();
+            TINT_ICE() << "unhandled constant type: " + ty->FriendlyName();
             return 0;
         });
 }
@@ -1982,8 +1971,7 @@
 
         // This should already have been validated by resolver
         if (lhs_mat->rows() != rhs_mat->rows() || lhs_mat->columns() != rhs_mat->columns()) {
-            TINT_ICE(Writer, builder_.Diagnostics())
-                << "matrices must have same dimensionality for add or subtract";
+            TINT_ICE() << "matrices must have same dimensionality for add or subtract";
             return 0;
         }
 
@@ -2028,7 +2016,7 @@
         } else if (lhs_is_bool_or_vec) {
             op = spv::Op::OpLogicalAnd;
         } else {
-            TINT_ICE(Writer, builder_.Diagnostics()) << "invalid and expression";
+            TINT_ICE() << "invalid and expression";
             return 0;
         }
     } else if (expr->IsAdd()) {
@@ -2049,7 +2037,7 @@
         } else if (lhs_is_integer_or_vec) {
             op = spv::Op::OpIEqual;
         } else {
-            TINT_ICE(Writer, builder_.Diagnostics()) << "invalid equal expression";
+            TINT_ICE() << "invalid equal expression";
             return 0;
         }
     } else if (expr->IsGreaterThan()) {
@@ -2129,7 +2117,7 @@
             // float matrix * matrix
             op = spv::Op::OpMatrixTimesMatrix;
         } else {
-            TINT_ICE(Writer, builder_.Diagnostics()) << "invalid multiply expression";
+            TINT_ICE() << "invalid multiply expression";
             return 0;
         }
     } else if (expr->IsNotEqual()) {
@@ -2140,7 +2128,7 @@
         } else if (lhs_is_integer_or_vec) {
             op = spv::Op::OpINotEqual;
         } else {
-            TINT_ICE(Writer, builder_.Diagnostics()) << "invalid not-equal expression";
+            TINT_ICE() << "invalid not-equal expression";
             return 0;
         }
     } else if (expr->IsOr()) {
@@ -2149,7 +2137,7 @@
         } else if (lhs_is_bool_or_vec) {
             op = spv::Op::OpLogicalOr;
         } else {
-            TINT_ICE(Writer, builder_.Diagnostics()) << "invalid and expression";
+            TINT_ICE() << "invalid and expression";
             return 0;
         }
     } else if (expr->IsShiftLeft()) {
@@ -2164,7 +2152,7 @@
     } else if (expr->IsXor()) {
         op = spv::Op::OpBitwiseXor;
     } else {
-        TINT_ICE(Writer, builder_.Diagnostics()) << "unknown binary expression";
+        TINT_ICE() << "unknown binary expression";
         return 0;
     }
 
@@ -2203,8 +2191,7 @@
             return GenerateValueConstructorOrConversion(call, nullptr);
         },
         [&](Default) {
-            TINT_ICE(Writer, builder_.Diagnostics())
-                << "unhandled call target: " << target->TypeInfo().name;
+            TINT_ICE() << "unhandled call target: " << target->TypeInfo().name;
             return 0;
         });
 }
@@ -2225,8 +2212,7 @@
 
     auto func_id = func_symbol_to_id_[ident->symbol];
     if (func_id == 0) {
-        TINT_ICE(Writer, builder_.Diagnostics())
-            << "unable to find called function: " + ident->symbol.Name();
+        TINT_ICE() << "unable to find called function: " + ident->symbol.Name();
         return 0;
     }
     ops.push_back(Operand(func_id));
@@ -2330,18 +2316,16 @@
         case builtin::Function::kArrayLength: {
             auto* address_of = call->Arguments()[0]->Declaration()->As<ast::UnaryOpExpression>();
             if (!address_of || address_of->op != ast::UnaryOp::kAddressOf) {
-                TINT_ICE(Writer, builder_.Diagnostics())
-                    << "arrayLength() expected pointer to member access, got " +
-                           std::string(address_of->TypeInfo().name);
+                TINT_ICE() << "arrayLength() expected pointer to member access, got " +
+                                  std::string(address_of->TypeInfo().name);
                 return 0;
             }
             auto* array_expr = address_of->expr;
 
             auto* accessor = array_expr->As<ast::MemberAccessorExpression>();
             if (!accessor) {
-                TINT_ICE(Writer, builder_.Diagnostics())
-                    << "arrayLength() expected pointer to member access, got pointer to " +
-                           std::string(array_expr->TypeInfo().name);
+                TINT_ICE() << "arrayLength() expected pointer to member access, got pointer to " +
+                                  std::string(array_expr->TypeInfo().name);
                 return 0;
             }
 
@@ -2353,8 +2337,8 @@
 
             auto* type = TypeOf(accessor->object)->UnwrapRef();
             if (!type->Is<type::Struct>()) {
-                TINT_ICE(Writer, builder_.Diagnostics())
-                    << "invalid type (" + type->FriendlyName() + ") for runtime array length";
+                TINT_ICE() << "invalid type (" + type->FriendlyName() +
+                                  ") for runtime array length";
                 return 0;
             }
             // Runtime array must be the last member in the structure
@@ -2551,8 +2535,7 @@
         default: {
             auto inst_id = builtin_to_glsl_method(builtin);
             if (inst_id == 0) {
-                TINT_ICE(Writer, builder_.Diagnostics())
-                    << "unknown method " + std::string(builtin->str());
+                TINT_ICE() << "unknown method " + std::string(builtin->str());
                 return 0;
             }
             glsl_std450(inst_id);
@@ -2561,8 +2544,7 @@
     }
 
     if (op == spv::Op::OpNop) {
-        TINT_ICE(Writer, builder_.Diagnostics())
-            << "unable to determine operator for: " + std::string(builtin->str());
+        TINT_ICE() << "unable to determine operator for: " + std::string(builtin->str());
         return 0;
     }
 
@@ -2603,15 +2585,14 @@
     auto gen_arg = [&](Usage usage) {
         auto* argument = arg(usage);
         if (TINT_UNLIKELY(!argument)) {
-            TINT_ICE(Writer, builder_.Diagnostics())
-                << "missing argument " << static_cast<int>(usage);
+            TINT_ICE() << "missing argument " << static_cast<int>(usage);
         }
         return gen(argument);
     };
 
     auto* texture = arg(Usage::kTexture);
     if (TINT_UNLIKELY(!texture)) {
-        TINT_ICE(Writer, builder_.Diagnostics()) << "missing texture argument";
+        TINT_ICE() << "missing texture argument";
     }
 
     auto* texture_type = texture->Type()->UnwrapRef()->As<type::Texture>();
@@ -2753,7 +2734,7 @@
             uint32_t spirv_dims = 0;
             switch (texture_type->dim()) {
                 case type::TextureDimension::kNone:
-                    TINT_ICE(Writer, builder_.Diagnostics()) << "texture dimension is kNone";
+                    TINT_ICE() << "texture dimension is kNone";
                     return false;
                 case type::TextureDimension::k1d:
                 case type::TextureDimension::k2d:
@@ -2790,7 +2771,7 @@
             uint32_t spirv_dims = 0;
             switch (texture_type->dim()) {
                 default:
-                    TINT_ICE(Writer, builder_.Diagnostics()) << "texture is not arrayed";
+                    TINT_ICE() << "texture is not arrayed";
                     return false;
                 case type::TextureDimension::k2dArray:
                 case type::TextureDimension::kCubeArray:
@@ -2958,7 +2939,7 @@
             break;
         }
         default:
-            TINT_UNREACHABLE(Writer, builder_.Diagnostics());
+            TINT_UNREACHABLE();
             return false;
     }
 
@@ -2980,8 +2961,7 @@
     }
 
     if (op == spv::Op::OpNop) {
-        TINT_ICE(Writer, builder_.Diagnostics())
-            << "unable to determine operator for: " + std::string(builtin->str());
+        TINT_ICE() << "unable to determine operator for: " + std::string(builtin->str());
         return false;
     }
 
@@ -3011,8 +2991,7 @@
         semantics = static_cast<uint32_t>(spv::MemorySemanticsMask::AcquireRelease) |
                     static_cast<uint32_t>(spv::MemorySemanticsMask::UniformMemory);
     } else {
-        TINT_ICE(Writer, builder_.Diagnostics())
-            << "unexpected barrier builtin type " << builtin::str(builtin->Type());
+        TINT_ICE() << "unexpected barrier builtin type " << builtin::str(builtin->Type());
         return false;
     }
 
@@ -3049,8 +3028,7 @@
                 ScalarConstant::U32(static_cast<uint32_t>(spv::Scope::Device)));
             break;
         default:
-            TINT_UNREACHABLE(Writer, builder_.Diagnostics())
-                << "unhandled atomic address space " << address_space;
+            TINT_UNREACHABLE() << "unhandled atomic address space " << address_space;
             return false;
     }
     if (memory_id == 0) {
@@ -3232,8 +3210,7 @@
                                                                      });
         }
         default:
-            TINT_UNREACHABLE(Writer, builder_.Diagnostics())
-                << "unhandled atomic builtin " << builtin->Type();
+            TINT_UNREACHABLE() << "unhandled atomic builtin " << builtin->Type();
             return false;
     }
 }
@@ -3555,7 +3532,7 @@
     }
 
     // Generate the backedge.
-    TINT_ASSERT(Writer, !backedge_stack_.empty());
+    TINT_ASSERT(!backedge_stack_.empty());
     const Backedge& backedge = backedge_stack_.back();
     if (!push_function_inst(backedge.opcode, backedge.operands)) {
         return false;
@@ -3586,8 +3563,7 @@
             return true;  // Not emitted
         },
         [&](Default) {
-            TINT_ICE(Writer, builder_.Diagnostics())
-                << "unknown statement type: " + std::string(stmt->TypeInfo().name);
+            TINT_ICE() << "unknown statement type: " + std::string(stmt->TypeInfo().name);
             return false;
         });
 }
@@ -3598,7 +3574,7 @@
 
 uint32_t Builder::GenerateTypeIfNeeded(const type::Type* type) {
     if (type == nullptr) {
-        TINT_ICE(Writer, builder_.Diagnostics()) << "attempting to generate type from null type";
+        TINT_ICE() << "attempting to generate type from null type";
         return 0;
     }
 
@@ -3714,8 +3690,7 @@
                 return true;
             },
             [&](Default) {
-                TINT_ICE(Writer, builder_.Diagnostics())
-                    << "unable to convert type: " + type->FriendlyName();
+                TINT_ICE() << "unable to convert type: " + type->FriendlyName();
                 return false;
             });
 
@@ -3729,8 +3704,7 @@
 
 bool Builder::GenerateTextureType(const type::Texture* texture, const Operand& result) {
     if (TINT_UNLIKELY(texture->Is<type::ExternalTexture>())) {
-        TINT_ICE(Writer, builder_.Diagnostics())
-            << "Multiplanar external texture transform was not run.";
+        TINT_ICE() << "Multiplanar external texture transform was not run.";
         return false;
     }
 
@@ -3819,7 +3793,7 @@
     } else {
         auto count = arr->ConstantCount();
         if (!count) {
-            TINT_ICE(Writer, builder_.Diagnostics()) << type::Array::kErrExpectedConstantCount;
+            TINT_ICE() << type::Array::kErrExpectedConstantCount;
             return static_cast<uint32_t>(0);
         }
 
@@ -3857,7 +3831,7 @@
 
     auto stg_class = ConvertAddressSpace(ptr->AddressSpace());
     if (stg_class == SpvStorageClassMax) {
-        TINT_ICE(Writer, builder_.Diagnostics()) << "invalid address space for pointer";
+        TINT_ICE() << "invalid address space for pointer";
         return false;
     }
 
@@ -3874,7 +3848,7 @@
 
     auto stg_class = ConvertAddressSpace(ref->AddressSpace());
     if (stg_class == SpvStorageClassMax) {
-        TINT_ICE(Writer, builder_.Diagnostics()) << "invalid address space for reference";
+        TINT_ICE() << "invalid address space for reference";
         return false;
     }
 
@@ -3991,7 +3965,7 @@
             } else if (TINT_LIKELY(storage == builtin::AddressSpace::kOut)) {
                 return SpvBuiltInPosition;
             } else {
-                TINT_ICE(Writer, builder_.Diagnostics()) << "invalid address space for builtin";
+                TINT_ICE() << "invalid address space for builtin";
                 break;
             }
         case builtin::BuiltinValue::kVertexIndex:
@@ -4058,8 +4032,7 @@
 SpvImageFormat Builder::convert_texel_format_to_spv(const builtin::TexelFormat format) {
     switch (format) {
         case builtin::TexelFormat::kBgra8Unorm:
-            TINT_ICE(Writer, builder_.Diagnostics())
-                << "bgra8unorm should have been polyfilled to rgba8unorm";
+            TINT_ICE() << "bgra8unorm should have been polyfilled to rgba8unorm";
             return SpvImageFormatUnknown;
         case builtin::TexelFormat::kR32Uint:
             return SpvImageFormatR32ui;
@@ -4107,7 +4080,7 @@
         StringStream ss;
         ss << "Internal error: trying to add SPIR-V instruction " << int(op)
            << " outside a function";
-        TINT_ICE(Writer, builder_.Diagnostics()) << ss.str();
+        TINT_ICE() << ss.str();
         return false;
     }
     current_function_.push_inst(op, operands);
@@ -4146,9 +4119,9 @@
                                         uint32_t loop_id,
                                         uint32_t break_id)
     : last_statement(the_last_statement), loop_header_id(loop_id), break_target_id(break_id) {
-    TINT_ASSERT(Writer, last_statement != nullptr);
-    TINT_ASSERT(Writer, loop_header_id != 0u);
-    TINT_ASSERT(Writer, break_target_id != 0u);
+    TINT_ASSERT(last_statement != nullptr);
+    TINT_ASSERT(loop_header_id != 0u);
+    TINT_ASSERT(break_target_id != 0u);
 }
 
 Builder::Backedge::Backedge(spv::Op the_opcode, OperandList the_operands)
diff --git a/src/tint/lang/spirv/writer/ast_printer/builder.h b/src/tint/lang/spirv/writer/ast_printer/builder.h
index bebec35..b3d0ec6 100644
--- a/src/tint/lang/spirv/writer/ast_printer/builder.h
+++ b/src/tint/lang/spirv/writer/ast_printer/builder.h
@@ -116,8 +116,7 @@
     /// @param operands the variable operands
     void push_function_var(const OperandList& operands) {
         if (TINT_UNLIKELY(!current_function_)) {
-            TINT_ICE(Writer, builder_.Diagnostics())
-                << "push_function_var() called without a function";
+            TINT_ICE() << "push_function_var() called without a function";
         }
         current_function_.push_var(operands);
     }
diff --git a/src/tint/lang/spirv/writer/printer/printer.cc b/src/tint/lang/spirv/writer/printer/printer.cc
index 9457d67..83e702d 100644
--- a/src/tint/lang/spirv/writer/printer/printer.cc
+++ b/src/tint/lang/spirv/writer/printer/printer.cc
@@ -302,7 +302,7 @@
                 module_.PushType(spv::Op::OpConstantComposite, operands);
             },
             [&](const type::Array* arr) {
-                TINT_ASSERT(Writer, arr->ConstantCount());
+                TINT_ASSERT(arr->ConstantCount());
                 OperandList operands = {Type(ty), id};
                 for (uint32_t i = 0; i < arr->ConstantCount(); i++) {
                     operands.push_back(Constant(constant->Index(i)));
@@ -316,9 +316,7 @@
                 }
                 module_.PushType(spv::Op::OpConstantComposite, operands);
             },
-            [&](Default) {
-                TINT_ICE(Writer, diagnostics_) << "unhandled constant type: " << ty->FriendlyName();
-            });
+            [&](Default) { TINT_ICE() << "unhandled constant type: " << ty->FriendlyName(); });
         return id;
     });
 }
@@ -376,7 +374,7 @@
                     module_.PushType(spv::Op::OpTypeArray,
                                      {id, Type(arr->ElemType()), Constant(count)});
                 } else {
-                    TINT_ASSERT(Writer, arr->Count()->Is<type::RuntimeArrayCount>());
+                    TINT_ASSERT(arr->Count()->Is<type::RuntimeArrayCount>());
                     module_.PushType(spv::Op::OpTypeRuntimeArray, {id, Type(arr->ElemType())});
                 }
                 module_.PushAnnot(spv::Op::OpDecorate,
@@ -393,9 +391,7 @@
             [&](const ir::transform::BuiltinPolyfillSpirv::SampledImage* s) {
                 module_.PushType(spv::Op::OpTypeSampledImage, {id, Type(s->Image())});
             },
-            [&](Default) {
-                TINT_ICE(Writer, diagnostics_) << "unhandled type: " << ty->FriendlyName();
-            });
+            [&](Default) { TINT_ICE() << "unhandled type: " << ty->FriendlyName(); });
         return id;
     });
 }
@@ -663,7 +659,7 @@
             break;
         }
         case ir::Function::PipelineStage::kUndefined:
-            TINT_ICE(Writer, diagnostics_) << "undefined pipeline stage for entry point";
+            TINT_ICE() << "undefined pipeline stage for entry point";
             return;
     }
 
@@ -721,8 +717,7 @@
             inst,  //
             [&](ir::Var* v) { return EmitVar(v); },
             [&](Default) {
-                TINT_ICE(Writer, diagnostics_)
-                    << "unimplemented root block instruction: " << inst->TypeInfo().name;
+                TINT_ICE() << "unimplemented root block instruction: " << inst->TypeInfo().name;
             });
     }
 }
@@ -790,10 +785,7 @@
             [&](ir::Let* l) { EmitLet(l); },                                //
             [&](ir::If* i) { EmitIf(i); },                                  //
             [&](ir::Terminator* t) { EmitTerminator(t); },                  //
-            [&](Default) {
-                TINT_ICE(Writer, diagnostics_)
-                    << "unimplemented instruction: " << inst->TypeInfo().name;
-            });
+            [&](Default) { TINT_ICE() << "unimplemented instruction: " << inst->TypeInfo().name; });
 
         // Set the name for the SPIR-V result ID if provided in the module.
         if (inst->Result() && !inst->Is<ir::Var>()) {
@@ -814,7 +806,7 @@
         t,         //
         [&](ir::Return*) {
             if (!t->Args().IsEmpty()) {
-                TINT_ASSERT(Writer, t->Args().Length() == 1u);
+                TINT_ASSERT(t->Args().Length() == 1u);
                 OperandList operands;
                 operands.push_back(Value(t->Args()[0]));
                 current_function_.push_inst(spv::Op::OpReturnValue, operands);
@@ -845,9 +837,7 @@
         [&](ir::TerminateInvocation*) { current_function_.push_inst(spv::Op::OpKill, {}); },
         [&](ir::Unreachable*) { current_function_.push_inst(spv::Op::OpUnreachable, {}); },
 
-        [&](Default) {
-            TINT_ICE(Writer, diagnostics_) << "unimplemented branch: " << t->TypeInfo().name;
-        });
+        [&](Default) { TINT_ICE() << "unimplemented branch: " << t->TypeInfo().name; });
 }
 
 void Printer::EmitIf(ir::If* i) {
@@ -920,7 +910,7 @@
         } else {
             // The VarForDynamicIndex transform ensures that only value types that are vectors
             // will be dynamically indexed, as we can use OpVectorExtractDynamic for this case.
-            TINT_ASSERT(Writer, source_ty->Is<type::Vector>());
+            TINT_ASSERT(source_ty->Is<type::Vector>());
 
             // If this wasn't the first access in the chain then emit the chain so far as an
             // OpCompositeExtract, creating a new result ID for the resulting vector.
@@ -1417,9 +1407,9 @@
                                                       spv::MemorySemanticsMask::AcquireRelease))));
             break;
         default:
-            TINT_ICE(Writer, diagnostics_) << "unimplemented builtin function: " << builtin->Func();
+            TINT_ICE() << "unimplemented builtin function: " << builtin->Func();
     }
-    TINT_ASSERT(Writer, op != spv::Op::Max);
+    TINT_ASSERT(op != spv::Op::Max);
 
     // Add the arguments to the builtin call.
     for (auto* arg : builtin->Args()) {
@@ -1510,7 +1500,7 @@
                 one = ir_->constant_values.Get(1_u);
                 zero = ir_->constant_values.Get(0_u);
             });
-        TINT_ASSERT_OR_RETURN(Writer, one && zero);
+        TINT_ASSERT_OR_RETURN(one && zero);
 
         if (auto* vec = res_ty->As<type::Vector>()) {
             // Splat the scalars into vectors.
@@ -1522,7 +1512,7 @@
         operands.push_back(Constant(one));
         operands.push_back(Constant(zero));
     } else {
-        TINT_ICE(Writer, diagnostics_) << "unhandled convert instruction";
+        TINT_ICE() << "unhandled convert instruction";
     }
 
     current_function_.push_inst(op, std::move(operands));
@@ -1718,7 +1708,7 @@
             }
         }
     }
-    TINT_ASSERT(Writer, default_label != 0u);
+    TINT_ASSERT(default_label != 0u);
 
     // Build the operands to the OpSwitch instruction.
     OperandList switch_operands = {Value(swtch->Condition()), default_label};
@@ -1813,7 +1803,7 @@
 
     switch (ptr->AddressSpace()) {
         case builtin::AddressSpace::kFunction: {
-            TINT_ASSERT(Writer, current_function_);
+            TINT_ASSERT(current_function_);
             current_function_.push_var({ty, id, U32Operand(SpvStorageClassFunction)});
             if (var->Initializer()) {
                 current_function_.push_inst(spv::Op::OpStore, {id, Value(var->Initializer())});
@@ -1821,35 +1811,35 @@
             break;
         }
         case builtin::AddressSpace::kIn: {
-            TINT_ASSERT(Writer, !current_function_);
+            TINT_ASSERT(!current_function_);
             module_.PushType(spv::Op::OpVariable, {ty, id, U32Operand(SpvStorageClassInput)});
             break;
         }
         case builtin::AddressSpace::kPrivate: {
-            TINT_ASSERT(Writer, !current_function_);
+            TINT_ASSERT(!current_function_);
             OperandList operands = {ty, id, U32Operand(SpvStorageClassPrivate)};
             if (var->Initializer()) {
-                TINT_ASSERT(Writer, var->Initializer()->Is<ir::Constant>());
+                TINT_ASSERT(var->Initializer()->Is<ir::Constant>());
                 operands.push_back(Value(var->Initializer()));
             }
             module_.PushType(spv::Op::OpVariable, operands);
             break;
         }
         case builtin::AddressSpace::kPushConstant: {
-            TINT_ASSERT(Writer, !current_function_);
+            TINT_ASSERT(!current_function_);
             module_.PushType(spv::Op::OpVariable,
                              {ty, id, U32Operand(SpvStorageClassPushConstant)});
             break;
         }
         case builtin::AddressSpace::kOut: {
-            TINT_ASSERT(Writer, !current_function_);
+            TINT_ASSERT(!current_function_);
             module_.PushType(spv::Op::OpVariable, {ty, id, U32Operand(SpvStorageClassOutput)});
             break;
         }
         case builtin::AddressSpace::kHandle:
         case builtin::AddressSpace::kStorage:
         case builtin::AddressSpace::kUniform: {
-            TINT_ASSERT(Writer, !current_function_);
+            TINT_ASSERT(!current_function_);
             module_.PushType(spv::Op::OpVariable,
                              {ty, id, U32Operand(StorageClass(ptr->AddressSpace()))});
             auto bp = var->BindingPoint().value();
@@ -1860,7 +1850,7 @@
             break;
         }
         case builtin::AddressSpace::kWorkgroup: {
-            TINT_ASSERT(Writer, !current_function_);
+            TINT_ASSERT(!current_function_);
             OperandList operands = {ty, id, U32Operand(SpvStorageClassWorkgroup)};
             if (zero_init_workgroup_memory_) {
                 // If requested, use the VK_KHR_zero_initialize_workgroup_memory to zero-initialize
@@ -1871,8 +1861,7 @@
             break;
         }
         default: {
-            TINT_ICE(Writer, diagnostics_)
-                << "unimplemented variable address space " << ptr->AddressSpace();
+            TINT_ICE() << "unimplemented variable address space " << ptr->AddressSpace();
         }
     }
 
@@ -1922,8 +1911,7 @@
 uint32_t Printer::TexelFormat(const builtin::TexelFormat format) {
     switch (format) {
         case builtin::TexelFormat::kBgra8Unorm:
-            TINT_ICE(Writer, diagnostics_)
-                << "bgra8unorm should have been polyfilled to rgba8unorm";
+            TINT_ICE() << "bgra8unorm should have been polyfilled to rgba8unorm";
             return SpvImageFormatUnknown;
         case builtin::TexelFormat::kR32Uint:
             return SpvImageFormatR32ui;
diff --git a/src/tint/lang/wgsl/ast/accessor_expression.cc b/src/tint/lang/wgsl/ast/accessor_expression.cc
index 377466f..67c3728 100644
--- a/src/tint/lang/wgsl/ast/accessor_expression.cc
+++ b/src/tint/lang/wgsl/ast/accessor_expression.cc
@@ -25,8 +25,8 @@
                                        const Source& src,
                                        const Expression* obj)
     : Base(pid, nid, src), object(obj) {
-    TINT_ASSERT(AST, object);
-    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(AST, object, generation_id);
+    TINT_ASSERT(object);
+    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(object, generation_id);
 }
 
 AccessorExpression::~AccessorExpression() = default;
diff --git a/src/tint/lang/wgsl/ast/alias.cc b/src/tint/lang/wgsl/ast/alias.cc
index dfb563d..79c2374 100644
--- a/src/tint/lang/wgsl/ast/alias.cc
+++ b/src/tint/lang/wgsl/ast/alias.cc
@@ -22,7 +22,7 @@
 
 Alias::Alias(GenerationID pid, NodeID nid, const Source& src, const Identifier* n, Type subtype)
     : Base(pid, nid, src, n), type(subtype) {
-    TINT_ASSERT(AST, type);
+    TINT_ASSERT(type);
 }
 
 Alias::~Alias() = default;
diff --git a/src/tint/lang/wgsl/ast/assignment_statement.cc b/src/tint/lang/wgsl/ast/assignment_statement.cc
index 173bbca..39307eb 100644
--- a/src/tint/lang/wgsl/ast/assignment_statement.cc
+++ b/src/tint/lang/wgsl/ast/assignment_statement.cc
@@ -26,10 +26,10 @@
                                          const Expression* l,
                                          const Expression* r)
     : Base(pid, nid, src), lhs(l), rhs(r) {
-    TINT_ASSERT(AST, lhs);
-    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(AST, lhs, generation_id);
-    TINT_ASSERT(AST, rhs);
-    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(AST, rhs, generation_id);
+    TINT_ASSERT(lhs);
+    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(lhs, generation_id);
+    TINT_ASSERT(rhs);
+    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(rhs, generation_id);
 }
 
 AssignmentStatement::~AssignmentStatement() = default;
diff --git a/src/tint/lang/wgsl/ast/binary_expression.cc b/src/tint/lang/wgsl/ast/binary_expression.cc
index dd1fdb4..4a58f1c 100644
--- a/src/tint/lang/wgsl/ast/binary_expression.cc
+++ b/src/tint/lang/wgsl/ast/binary_expression.cc
@@ -27,11 +27,11 @@
                                    const Expression* l,
                                    const Expression* r)
     : Base(pid, nid, src), op(o), lhs(l), rhs(r) {
-    TINT_ASSERT(AST, lhs);
-    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(AST, lhs, generation_id);
-    TINT_ASSERT(AST, rhs);
-    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(AST, rhs, generation_id);
-    TINT_ASSERT(AST, op != BinaryOp::kNone);
+    TINT_ASSERT(lhs);
+    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(lhs, generation_id);
+    TINT_ASSERT(rhs);
+    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(rhs, generation_id);
+    TINT_ASSERT(op != BinaryOp::kNone);
 }
 
 BinaryExpression::~BinaryExpression() = default;
diff --git a/src/tint/lang/wgsl/ast/bitcast_expression.cc b/src/tint/lang/wgsl/ast/bitcast_expression.cc
index 9fd5024..f943eca 100644
--- a/src/tint/lang/wgsl/ast/bitcast_expression.cc
+++ b/src/tint/lang/wgsl/ast/bitcast_expression.cc
@@ -26,9 +26,9 @@
                                      Type t,
                                      const Expression* e)
     : Base(pid, nid, src), type(t), expr(e) {
-    TINT_ASSERT(AST, type);
-    TINT_ASSERT(AST, expr);
-    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(AST, expr, generation_id);
+    TINT_ASSERT(type);
+    TINT_ASSERT(expr);
+    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(expr, generation_id);
 }
 
 BitcastExpression::~BitcastExpression() = default;
diff --git a/src/tint/lang/wgsl/ast/block_statement.cc b/src/tint/lang/wgsl/ast/block_statement.cc
index 7bbec98..a49d07e 100644
--- a/src/tint/lang/wgsl/ast/block_statement.cc
+++ b/src/tint/lang/wgsl/ast/block_statement.cc
@@ -27,12 +27,12 @@
                                VectorRef<const Attribute*> attrs)
     : Base(pid, nid, src), statements(std::move(stmts)), attributes(attrs) {
     for (auto* stmt : statements) {
-        TINT_ASSERT(AST, stmt);
-        TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(AST, stmt, generation_id);
+        TINT_ASSERT(stmt);
+        TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(stmt, generation_id);
     }
     for (auto* attr : attributes) {
-        TINT_ASSERT(AST, attr);
-        TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(AST, attr, generation_id);
+        TINT_ASSERT(attr);
+        TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(attr, generation_id);
     }
 }
 
diff --git a/src/tint/lang/wgsl/ast/break_if_statement.cc b/src/tint/lang/wgsl/ast/break_if_statement.cc
index 3421b54..19431ef 100644
--- a/src/tint/lang/wgsl/ast/break_if_statement.cc
+++ b/src/tint/lang/wgsl/ast/break_if_statement.cc
@@ -25,8 +25,8 @@
                                    const Source& src,
                                    const Expression* cond)
     : Base(pid, nid, src), condition(cond) {
-    TINT_ASSERT(AST, condition);
-    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(AST, condition, generation_id);
+    TINT_ASSERT(condition);
+    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(condition, generation_id);
 }
 
 BreakIfStatement::~BreakIfStatement() = default;
diff --git a/src/tint/lang/wgsl/ast/builtin_attribute.cc b/src/tint/lang/wgsl/ast/builtin_attribute.cc
index 4cfe251..22602ef 100644
--- a/src/tint/lang/wgsl/ast/builtin_attribute.cc
+++ b/src/tint/lang/wgsl/ast/builtin_attribute.cc
@@ -27,7 +27,7 @@
                                    const Source& src,
                                    const Expression* b)
     : Base(pid, nid, src), builtin(b) {
-    TINT_ASSERT_GENERATION_IDS_EQUAL(AST, b, generation_id);
+    TINT_ASSERT_GENERATION_IDS_EQUAL(b, generation_id);
 }
 
 BuiltinAttribute::~BuiltinAttribute() = default;
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 1536b14..cb7b4eb 100644
--- a/src/tint/lang/wgsl/ast/builtin_texture_helper_test.cc
+++ b/src/tint/lang/wgsl/ast/builtin_texture_helper_test.cc
@@ -151,7 +151,7 @@
             return b->ty.i32();
     }
 
-    TINT_UNREACHABLE(AST, b->Diagnostics());
+    TINT_UNREACHABLE();
     return {};
 }
 
@@ -185,7 +185,7 @@
         }
     }
 
-    TINT_UNREACHABLE(AST, b->Diagnostics());
+    TINT_UNREACHABLE();
     return nullptr;
 }
 
diff --git a/src/tint/lang/wgsl/ast/call_expression.cc b/src/tint/lang/wgsl/ast/call_expression.cc
index 1eee4f9..7541e82 100644
--- a/src/tint/lang/wgsl/ast/call_expression.cc
+++ b/src/tint/lang/wgsl/ast/call_expression.cc
@@ -28,11 +28,11 @@
                                const IdentifierExpression* t,
                                VectorRef<const Expression*> a)
     : Base(pid, nid, src), target(t), args(std::move(a)) {
-    TINT_ASSERT(AST, target);
-    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(AST, target, generation_id);
+    TINT_ASSERT(target);
+    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(target, generation_id);
     for (auto* arg : args) {
-        TINT_ASSERT(AST, arg);
-        TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(AST, arg, generation_id);
+        TINT_ASSERT(arg);
+        TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(arg, generation_id);
     }
 }
 
diff --git a/src/tint/lang/wgsl/ast/call_statement.cc b/src/tint/lang/wgsl/ast/call_statement.cc
index f19071f..abd8a038 100644
--- a/src/tint/lang/wgsl/ast/call_statement.cc
+++ b/src/tint/lang/wgsl/ast/call_statement.cc
@@ -25,8 +25,8 @@
                              const Source& src,
                              const CallExpression* call)
     : Base(pid, nid, src), expr(call) {
-    TINT_ASSERT(AST, expr);
-    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(AST, expr, generation_id);
+    TINT_ASSERT(expr);
+    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(expr, generation_id);
 }
 
 CallStatement::~CallStatement() = default;
diff --git a/src/tint/lang/wgsl/ast/case_statement.cc b/src/tint/lang/wgsl/ast/case_statement.cc
index 0a4e3c2..f5f5e1f 100644
--- a/src/tint/lang/wgsl/ast/case_statement.cc
+++ b/src/tint/lang/wgsl/ast/case_statement.cc
@@ -28,12 +28,12 @@
                              VectorRef<const CaseSelector*> s,
                              const BlockStatement* b)
     : Base(pid, nid, src), selectors(std::move(s)), body(b) {
-    TINT_ASSERT(AST, body);
-    TINT_ASSERT(AST, !selectors.IsEmpty());
-    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(AST, body, generation_id);
+    TINT_ASSERT(body);
+    TINT_ASSERT(!selectors.IsEmpty());
+    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(body, generation_id);
     for (auto* selector : selectors) {
-        TINT_ASSERT(AST, selector);
-        TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(AST, selector, generation_id);
+        TINT_ASSERT(selector);
+        TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(selector, generation_id);
     }
 }
 
diff --git a/src/tint/lang/wgsl/ast/clone_context.cc b/src/tint/lang/wgsl/ast/clone_context.cc
index b25a56e..5bc57ab 100644
--- a/src/tint/lang/wgsl/ast/clone_context.cc
+++ b/src/tint/lang/wgsl/ast/clone_context.cc
@@ -97,10 +97,10 @@
     return object->Clone(this);
 }
 
-void CloneContext::CheckedCastFailure(const Cloneable* got, const tint::TypeInfo& expected) {
-    TINT_ICE(Clone, Diagnostics()) << "Cloned object was not of the expected type\n"
-                                   << "got:      " << got->TypeInfo().name << "\n"
-                                   << "expected: " << expected.name;
+void CloneContext::CheckedCastFailure(const Cloneable* got, const TypeInfo& expected) {
+    TINT_ICE() << "Cloned object was not of the expected type\n"
+               << "got:      " << got->TypeInfo().name << "\n"
+               << "expected: " << expected.name;
 }
 
 diag::List& CloneContext::Diagnostics() const {
diff --git a/src/tint/lang/wgsl/ast/clone_context.h b/src/tint/lang/wgsl/ast/clone_context.h
index a4850de..92f6030 100644
--- a/src/tint/lang/wgsl/ast/clone_context.h
+++ b/src/tint/lang/wgsl/ast/clone_context.h
@@ -24,8 +24,10 @@
 #include "src/tint/utils/containers/hashmap.h"
 #include "src/tint/utils/containers/hashset.h"
 #include "src/tint/utils/containers/vector.h"
-#include "src/tint/utils/debug/debug.h"
+#include "src/tint/utils/diagnostic/diagnostic.h"
+#include "src/tint/utils/diagnostic/source.h"
 #include "src/tint/utils/generation_id.h"
+#include "src/tint/utils/ice/ice.h"
 #include "src/tint/utils/macros/compiler.h"
 #include "src/tint/utils/rtti/castable.h"
 #include "src/tint/utils/text/symbol.h"
@@ -109,11 +111,11 @@
     template <typename T>
     const T* Clone(const T* object) {
         if (src) {
-            TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(Clone, src, object);
+            TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(src, object);
         }
         if (auto* cloned = CloneCloneable(object)) {
             auto* out = CheckedCast<T>(cloned);
-            TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(Clone, dst, out);
+            TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(dst, out);
             return out;
         }
         return nullptr;
@@ -137,7 +139,7 @@
             return nullptr;
         }
         if (src) {
-            TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(Clone, src, a);
+            TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(src, a);
         }
         auto* c = a->Clone(this);
         return CheckedCast<T>(c);
@@ -310,10 +312,10 @@
             bool already_registered = transform.typeinfo->Is(&tint::TypeInfo::Of<T>()) ||
                                       tint::TypeInfo::Of<T>().Is(transform.typeinfo);
             if (TINT_UNLIKELY(already_registered)) {
-                TINT_ICE(Clone, Diagnostics()) << "ReplaceAll() called with a handler for type "
-                                               << tint::TypeInfo::Of<T>().name
-                                               << " that is already handled by a handler for type "
-                                               << transform.typeinfo->name;
+                TINT_ICE() << "ReplaceAll() called with a handler for type "
+                           << TypeInfo::Of<T>().name
+                           << " that is already handled by a handler for type "
+                           << transform.typeinfo->name;
                 return *this;
             }
         }
@@ -335,8 +337,8 @@
     /// @returns this CloneContext so calls can be chained
     CloneContext& ReplaceAll(const SymbolTransform& replacer) {
         if (TINT_UNLIKELY(symbol_transform_)) {
-            TINT_ICE(Clone, Diagnostics()) << "ReplaceAll(const SymbolTransform&) called "
-                                              "multiple times on the same CloneContext";
+            TINT_ICE() << "ReplaceAll(const SymbolTransform&) called multiple times on the same "
+                          "CloneContext";
             return *this;
         }
         symbol_transform_ = replacer;
@@ -359,8 +361,8 @@
               typename WITH,
               typename = tint::traits::EnableIfIsType<WITH, Cloneable>>
     CloneContext& Replace(const WHAT* what, const WITH* with) {
-        TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(Clone, src, what);
-        TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(Clone, dst, with);
+        TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(src, what);
+        TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(dst, with);
         replacements_.Replace(what, [with]() -> const Cloneable* { return with; });
         return *this;
     }
@@ -380,7 +382,7 @@
     /// @returns this CloneContext so calls can be chained
     template <typename WHAT, typename WITH, typename = std::invoke_result_t<WITH>>
     CloneContext& Replace(const WHAT* what, WITH&& with) {
-        TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(Clone, src, what);
+        TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(src, what);
         replacements_.Replace(what, with);
         return *this;
     }
@@ -391,11 +393,10 @@
     /// the cloned vector.
     /// @returns this CloneContext so calls can be chained
     template <typename T, size_t N, typename OBJECT>
-    CloneContext& Remove(const tint::Vector<T, N>& vector, OBJECT* object) {
-        TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(Clone, src, object);
+    CloneContext& Remove(const Vector<T, N>& vector, OBJECT* object) {
+        TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(src, object);
         if (TINT_UNLIKELY((std::find(vector.begin(), vector.end(), object) == vector.end()))) {
-            TINT_ICE(Clone, Diagnostics())
-                << "CloneContext::Remove() vector does not contain object";
+            TINT_ICE() << "CloneContext::Remove() vector does not contain object";
             return *this;
         }
 
@@ -409,8 +410,8 @@
     /// front of the vector
     /// @returns this CloneContext so calls can be chained
     template <typename T, size_t N, typename OBJECT>
-    CloneContext& InsertFront(const tint::Vector<T, N>& vector, OBJECT* object) {
-        TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(Clone, dst, object);
+    CloneContext& InsertFront(const Vector<T, N>& vector, OBJECT* object) {
+        TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(dst, object);
         return InsertFront(vector, [object] { return object; });
     }
 
@@ -431,8 +432,8 @@
     /// end of the vector
     /// @returns this CloneContext so calls can be chained
     template <typename T, size_t N, typename OBJECT>
-    CloneContext& InsertBack(const tint::Vector<T, N>& vector, OBJECT* object) {
-        TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(Clone, dst, object);
+    CloneContext& InsertBack(const Vector<T, N>& vector, OBJECT* object) {
+        TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(dst, object);
         return InsertBack(vector, [object] { return object; });
     }
 
@@ -458,11 +459,10 @@
     CloneContext& InsertBefore(const tint::Vector<T, N>& vector,
                                const BEFORE* before,
                                const OBJECT* object) {
-        TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(Clone, src, before);
-        TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(Clone, dst, object);
+        TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(src, before);
+        TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(dst, object);
         if (TINT_UNLIKELY((std::find(vector.begin(), vector.end(), before) == vector.end()))) {
-            TINT_ICE(Clone, Diagnostics())
-                << "CloneContext::InsertBefore() vector does not contain before";
+            TINT_ICE() << "CloneContext::InsertBefore() vector does not contain before";
             return *this;
         }
 
@@ -500,11 +500,10 @@
     CloneContext& InsertAfter(const tint::Vector<T, N>& vector,
                               const AFTER* after,
                               const OBJECT* object) {
-        TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(Clone, src, after);
-        TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(Clone, dst, object);
+        TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(src, after);
+        TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(dst, object);
         if (TINT_UNLIKELY((std::find(vector.begin(), vector.end(), after) == vector.end()))) {
-            TINT_ICE(Clone, Diagnostics())
-                << "CloneContext::InsertAfter() vector does not contain after";
+            TINT_ICE() << "CloneContext::InsertAfter() vector does not contain after";
             return *this;
         }
 
diff --git a/src/tint/lang/wgsl/ast/clone_context_test.cc b/src/tint/lang/wgsl/ast/clone_context_test.cc
index 936ca00..17d6e5f 100644
--- a/src/tint/lang/wgsl/ast/clone_context_test.cc
+++ b/src/tint/lang/wgsl/ast/clone_context_test.cc
@@ -1268,7 +1268,7 @@
             Allocator allocator;
             ctx.Clone(allocator.Create<ProgramNode>(GenerationID::New(), dst.ID()));
         },
-        R"(internal compiler error: TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(Clone, src, object))");
+        R"(internal compiler error: TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(src, object))");
 }
 
 TEST_F(CloneContextTest, GenerationIDs_Clone_ObjectNotOwnedByDst) {
@@ -1280,7 +1280,7 @@
             Allocator allocator;
             ctx.Clone(allocator.Create<ProgramNode>(src.ID(), GenerationID::New()));
         },
-        R"(internal compiler error: TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(Clone, dst, out))");
+        R"(internal compiler error: TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(dst, out))");
 }
 
 }  // namespace
diff --git a/src/tint/lang/wgsl/ast/compound_assignment_statement.cc b/src/tint/lang/wgsl/ast/compound_assignment_statement.cc
index d235bc6..7050a2c 100644
--- a/src/tint/lang/wgsl/ast/compound_assignment_statement.cc
+++ b/src/tint/lang/wgsl/ast/compound_assignment_statement.cc
@@ -27,10 +27,10 @@
                                                          const Expression* r,
                                                          BinaryOp o)
     : Base(pid, nid, src), lhs(l), rhs(r), op(o) {
-    TINT_ASSERT(AST, lhs);
-    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(AST, lhs, generation_id);
-    TINT_ASSERT(AST, rhs);
-    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(AST, rhs, generation_id);
+    TINT_ASSERT(lhs);
+    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(lhs, generation_id);
+    TINT_ASSERT(rhs);
+    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(rhs, generation_id);
 }
 
 CompoundAssignmentStatement::~CompoundAssignmentStatement() = default;
diff --git a/src/tint/lang/wgsl/ast/const.cc b/src/tint/lang/wgsl/ast/const.cc
index 7a7c7e9..62ab73b 100644
--- a/src/tint/lang/wgsl/ast/const.cc
+++ b/src/tint/lang/wgsl/ast/const.cc
@@ -30,7 +30,7 @@
              const Expression* init,
              VectorRef<const Attribute*> attrs)
     : Base(pid, nid, src, n, ty, init, std::move(attrs)) {
-    TINT_ASSERT(AST, init != nullptr);
+    TINT_ASSERT(init != nullptr);
 }
 
 Const::~Const() = default;
diff --git a/src/tint/lang/wgsl/ast/const_assert.cc b/src/tint/lang/wgsl/ast/const_assert.cc
index 59c1cf8..5775d94 100644
--- a/src/tint/lang/wgsl/ast/const_assert.cc
+++ b/src/tint/lang/wgsl/ast/const_assert.cc
@@ -22,8 +22,8 @@
 
 ConstAssert::ConstAssert(GenerationID pid, NodeID nid, const Source& src, const Expression* cond)
     : Base(pid, nid, src), condition(cond) {
-    TINT_ASSERT(AST, cond);
-    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(AST, cond, generation_id);
+    TINT_ASSERT(cond);
+    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(cond, generation_id);
 }
 
 ConstAssert::~ConstAssert() = default;
diff --git a/src/tint/lang/wgsl/ast/diagnostic_control.cc b/src/tint/lang/wgsl/ast/diagnostic_control.cc
index c4e72be..f5e31df 100644
--- a/src/tint/lang/wgsl/ast/diagnostic_control.cc
+++ b/src/tint/lang/wgsl/ast/diagnostic_control.cc
@@ -27,7 +27,7 @@
 DiagnosticControl::DiagnosticControl(builtin::DiagnosticSeverity sev,
                                      const DiagnosticRuleName* rule)
     : severity(sev), rule_name(rule) {
-    TINT_ASSERT(AST, rule != nullptr);
+    TINT_ASSERT(rule != nullptr);
 }
 
 DiagnosticControl::DiagnosticControl(DiagnosticControl&&) = default;
diff --git a/src/tint/lang/wgsl/ast/diagnostic_rule_name.cc b/src/tint/lang/wgsl/ast/diagnostic_rule_name.cc
index 22ca445..0c3e180 100644
--- a/src/tint/lang/wgsl/ast/diagnostic_rule_name.cc
+++ b/src/tint/lang/wgsl/ast/diagnostic_rule_name.cc
@@ -27,11 +27,11 @@
                                        const Source& src,
                                        const Identifier* n)
     : Base(pid, nid, src), name(n) {
-    TINT_ASSERT(AST, name != nullptr);
-    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(AST, name, generation_id);
+    TINT_ASSERT(name != nullptr);
+    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(name, generation_id);
     if (name) {
         // It is invalid for a diagnostic rule name to be templated
-        TINT_ASSERT(AST, !name->Is<TemplatedIdentifier>());
+        TINT_ASSERT(!name->Is<TemplatedIdentifier>());
     }
 }
 
@@ -41,16 +41,16 @@
                                        const Identifier* c,
                                        const Identifier* n)
     : Base(pid, nid, src), category(c), name(n) {
-    TINT_ASSERT(AST, name != nullptr);
-    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(AST, name, generation_id);
+    TINT_ASSERT(name != nullptr);
+    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(name, generation_id);
     if (name) {
         // It is invalid for a diagnostic rule name to be templated
-        TINT_ASSERT(AST, !name->Is<TemplatedIdentifier>());
+        TINT_ASSERT(!name->Is<TemplatedIdentifier>());
     }
     if (category) {
-        TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(AST, category, generation_id);
+        TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(category, generation_id);
         // It is invalid for a diagnostic rule category to be templated
-        TINT_ASSERT(AST, !category->Is<TemplatedIdentifier>());
+        TINT_ASSERT(!category->Is<TemplatedIdentifier>());
     }
 }
 
diff --git a/src/tint/lang/wgsl/ast/for_loop_statement.cc b/src/tint/lang/wgsl/ast/for_loop_statement.cc
index 474c749..0f976e9 100644
--- a/src/tint/lang/wgsl/ast/for_loop_statement.cc
+++ b/src/tint/lang/wgsl/ast/for_loop_statement.cc
@@ -36,15 +36,15 @@
       continuing(cont),
       body(b),
       attributes(std::move(attrs)) {
-    TINT_ASSERT(AST, body);
+    TINT_ASSERT(body);
 
-    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(AST, initializer, generation_id);
-    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(AST, condition, generation_id);
-    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(AST, continuing, generation_id);
-    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(AST, body, generation_id);
+    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(initializer, generation_id);
+    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(condition, generation_id);
+    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(continuing, generation_id);
+    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(body, generation_id);
     for (auto* attr : attributes) {
-        TINT_ASSERT(AST, attr);
-        TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(AST, attr, generation_id);
+        TINT_ASSERT(attr);
+        TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(attr, generation_id);
     }
 }
 
diff --git a/src/tint/lang/wgsl/ast/function.cc b/src/tint/lang/wgsl/ast/function.cc
index 103f247..144a4a8 100644
--- a/src/tint/lang/wgsl/ast/function.cc
+++ b/src/tint/lang/wgsl/ast/function.cc
@@ -38,22 +38,22 @@
       body(b),
       attributes(std::move(attrs)),
       return_type_attributes(std::move(return_type_attrs)) {
-    TINT_ASSERT(AST, name);
+    TINT_ASSERT(name);
     if (name) {
-        TINT_ASSERT(AST, !name->Is<TemplatedIdentifier>());
+        TINT_ASSERT(!name->Is<TemplatedIdentifier>());
     }
-    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(AST, name, generation_id);
-    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(AST, return_ty, generation_id);
-    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(AST, body, generation_id);
+    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(name, generation_id);
+    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(return_ty, generation_id);
+    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(body, generation_id);
     for (auto* param : params) {
-        TINT_ASSERT(AST, tint::Is<Parameter>(param));
-        TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(AST, param, generation_id);
+        TINT_ASSERT(tint::Is<Parameter>(param));
+        TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(param, generation_id);
     }
     for (auto* attr : attributes) {
-        TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(AST, attr, generation_id);
+        TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(attr, generation_id);
     }
     for (auto* attr : return_type_attributes) {
-        TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(AST, attr, generation_id);
+        TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(attr, generation_id);
     }
 }
 
diff --git a/src/tint/lang/wgsl/ast/identifier.cc b/src/tint/lang/wgsl/ast/identifier.cc
index d31b9ad..827487b 100644
--- a/src/tint/lang/wgsl/ast/identifier.cc
+++ b/src/tint/lang/wgsl/ast/identifier.cc
@@ -22,8 +22,8 @@
 
 Identifier::Identifier(GenerationID pid, NodeID nid, const Source& src, Symbol sym)
     : Base(pid, nid, src), symbol(sym) {
-    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(AST, symbol, generation_id);
-    TINT_ASSERT(AST, symbol.IsValid());
+    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(symbol, generation_id);
+    TINT_ASSERT(symbol.IsValid());
 }
 
 Identifier::~Identifier() = default;
diff --git a/src/tint/lang/wgsl/ast/identifier_expression.cc b/src/tint/lang/wgsl/ast/identifier_expression.cc
index 8666a10..028600e 100644
--- a/src/tint/lang/wgsl/ast/identifier_expression.cc
+++ b/src/tint/lang/wgsl/ast/identifier_expression.cc
@@ -25,8 +25,8 @@
                                            const Source& src,
                                            const Identifier* ident)
     : Base(pid, nid, src), identifier(ident) {
-    TINT_ASSERT(AST, identifier != nullptr);
-    TINT_ASSERT_GENERATION_IDS_EQUAL(AST, identifier, generation_id);
+    TINT_ASSERT(identifier != nullptr);
+    TINT_ASSERT_GENERATION_IDS_EQUAL(identifier, generation_id);
 }
 
 IdentifierExpression::~IdentifierExpression() = default;
diff --git a/src/tint/lang/wgsl/ast/if_statement.cc b/src/tint/lang/wgsl/ast/if_statement.cc
index 006c0dc..4168b63 100644
--- a/src/tint/lang/wgsl/ast/if_statement.cc
+++ b/src/tint/lang/wgsl/ast/if_statement.cc
@@ -32,17 +32,17 @@
       body(b),
       else_statement(else_stmt),
       attributes(std::move(attrs)) {
-    TINT_ASSERT(AST, condition);
-    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(AST, condition, generation_id);
-    TINT_ASSERT(AST, body);
-    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(AST, body, generation_id);
+    TINT_ASSERT(condition);
+    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(condition, generation_id);
+    TINT_ASSERT(body);
+    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(body, generation_id);
     if (else_statement) {
-        TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(AST, else_statement, generation_id);
-        TINT_ASSERT(AST, (else_statement->IsAnyOf<IfStatement, BlockStatement>()));
+        TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(else_statement, generation_id);
+        TINT_ASSERT((else_statement->IsAnyOf<IfStatement, BlockStatement>()));
     }
     for (auto* attr : attributes) {
-        TINT_ASSERT(AST, attr);
-        TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(AST, attr, generation_id);
+        TINT_ASSERT(attr);
+        TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(attr, generation_id);
     }
 }
 
diff --git a/src/tint/lang/wgsl/ast/increment_decrement_statement.cc b/src/tint/lang/wgsl/ast/increment_decrement_statement.cc
index fc0bc29..4e90671 100644
--- a/src/tint/lang/wgsl/ast/increment_decrement_statement.cc
+++ b/src/tint/lang/wgsl/ast/increment_decrement_statement.cc
@@ -26,7 +26,7 @@
                                                          const Expression* l,
                                                          bool inc)
     : Base(pid, nid, src), lhs(l), increment(inc) {
-    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(AST, lhs, generation_id);
+    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(lhs, generation_id);
 }
 
 IncrementDecrementStatement::~IncrementDecrementStatement() = default;
diff --git a/src/tint/lang/wgsl/ast/index_accessor_expression.cc b/src/tint/lang/wgsl/ast/index_accessor_expression.cc
index 456f635..1419497 100644
--- a/src/tint/lang/wgsl/ast/index_accessor_expression.cc
+++ b/src/tint/lang/wgsl/ast/index_accessor_expression.cc
@@ -26,8 +26,8 @@
                                                  const Expression* obj,
                                                  const Expression* idx)
     : Base(pid, nid, src, obj), index(idx) {
-    TINT_ASSERT(AST, idx);
-    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(AST, idx, generation_id);
+    TINT_ASSERT(idx);
+    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(idx, generation_id);
 }
 
 IndexAccessorExpression::~IndexAccessorExpression() = default;
diff --git a/src/tint/lang/wgsl/ast/let.cc b/src/tint/lang/wgsl/ast/let.cc
index f7f5e56..5f9d90b 100644
--- a/src/tint/lang/wgsl/ast/let.cc
+++ b/src/tint/lang/wgsl/ast/let.cc
@@ -30,7 +30,7 @@
          const Expression* init,
          VectorRef<const Attribute*> attrs)
     : Base(pid, nid, src, n, ty, init, std::move(attrs)) {
-    TINT_ASSERT(AST, init != nullptr);
+    TINT_ASSERT(init != nullptr);
 }
 
 Let::~Let() = default;
diff --git a/src/tint/lang/wgsl/ast/loop_statement.cc b/src/tint/lang/wgsl/ast/loop_statement.cc
index feebce2..0da9ad5 100644
--- a/src/tint/lang/wgsl/ast/loop_statement.cc
+++ b/src/tint/lang/wgsl/ast/loop_statement.cc
@@ -29,12 +29,12 @@
                              const BlockStatement* cont,
                              VectorRef<const ast::Attribute*> attrs)
     : Base(pid, nid, src), body(b), continuing(cont), attributes(std::move(attrs)) {
-    TINT_ASSERT(AST, body);
-    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(AST, body, generation_id);
-    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(AST, continuing, generation_id);
+    TINT_ASSERT(body);
+    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(body, generation_id);
+    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(continuing, generation_id);
     for (auto* attr : attributes) {
-        TINT_ASSERT(AST, attr);
-        TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(AST, attr, generation_id);
+        TINT_ASSERT(attr);
+        TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(attr, generation_id);
     }
 }
 
diff --git a/src/tint/lang/wgsl/ast/member_accessor_expression.cc b/src/tint/lang/wgsl/ast/member_accessor_expression.cc
index 4fc6f21..d9ec1a4 100644
--- a/src/tint/lang/wgsl/ast/member_accessor_expression.cc
+++ b/src/tint/lang/wgsl/ast/member_accessor_expression.cc
@@ -26,12 +26,12 @@
                                                    const Expression* obj,
                                                    const Identifier* mem)
     : Base(pid, nid, src, obj), member(mem) {
-    TINT_ASSERT(AST, member);
-    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(AST, member, generation_id);
+    TINT_ASSERT(member);
+    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(member, generation_id);
 
     // It is currently invalid for a structure to hold a templated member
     if (member) {
-        TINT_ASSERT(AST, !member->Is<TemplatedIdentifier>());
+        TINT_ASSERT(!member->Is<TemplatedIdentifier>());
     }
 }
 
diff --git a/src/tint/lang/wgsl/ast/module.cc b/src/tint/lang/wgsl/ast/module.cc
index edc1771..a5b2797 100644
--- a/src/tint/lang/wgsl/ast/module.cc
+++ b/src/tint/lang/wgsl/ast/module.cc
@@ -32,8 +32,7 @@
         if (decl == nullptr) {
             continue;
         }
-        diag::List diags;
-        BinGlobalDeclaration(decl, diags);
+        BinGlobalDeclaration(decl);
     }
 }
 
@@ -49,79 +48,78 @@
 }
 
 void Module::AddGlobalDeclaration(const tint::ast::Node* decl) {
-    diag::List diags;
-    BinGlobalDeclaration(decl, diags);
+    BinGlobalDeclaration(decl);
     global_declarations_.Push(decl);
 }
 
-void Module::BinGlobalDeclaration(const tint::ast::Node* decl, diag::List& diags) {
+void Module::BinGlobalDeclaration(const tint::ast::Node* decl) {
     Switch(
         decl,  //
         [&](const TypeDecl* type) {
-            TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(AST, type, generation_id);
+            TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(type, generation_id);
             type_decls_.Push(type);
         },
         [&](const Function* func) {
-            TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(AST, func, generation_id);
+            TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(func, generation_id);
             functions_.Push(func);
         },
         [&](const Variable* var) {
-            TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(AST, var, generation_id);
+            TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(var, generation_id);
             global_variables_.Push(var);
         },
         [&](const DiagnosticDirective* diagnostic) {
-            TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(AST, diagnostic, generation_id);
+            TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(diagnostic, generation_id);
             diagnostic_directives_.Push(diagnostic);
         },
         [&](const Enable* enable) {
-            TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(AST, enable, generation_id);
+            TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(enable, generation_id);
             enables_.Push(enable);
         },
         [&](const ConstAssert* assertion) {
-            TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(AST, assertion, generation_id);
+            TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(assertion, generation_id);
             const_asserts_.Push(assertion);
         },
-        [&](Default) { TINT_ICE(AST, diags) << "Unknown global declaration type"; });
+        [&](Default) { TINT_ICE() << "Unknown global declaration type"; });
 }
 
 void Module::AddDiagnosticDirective(const DiagnosticDirective* directive) {
-    TINT_ASSERT(AST, directive);
-    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(AST, directive, generation_id);
+    TINT_ASSERT(directive);
+    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(directive, generation_id);
     global_declarations_.Push(directive);
     diagnostic_directives_.Push(directive);
 }
 
 void Module::AddEnable(const Enable* enable) {
-    TINT_ASSERT(AST, enable);
-    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(AST, enable, generation_id);
+    TINT_ASSERT(enable);
+    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(enable, generation_id);
     global_declarations_.Push(enable);
     enables_.Push(enable);
 }
 
 void Module::AddGlobalVariable(const Variable* var) {
-    TINT_ASSERT(AST, var);
-    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(AST, var, generation_id);
+    TINT_ASSERT(var);
+    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(var, generation_id);
     global_variables_.Push(var);
     global_declarations_.Push(var);
 }
 
 void Module::AddConstAssert(const ConstAssert* assertion) {
-    TINT_ASSERT(AST, assertion);
-    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(AST, assertion, generation_id);
+    TINT_ASSERT(assertion);
+    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(assertion, generation_id);
     const_asserts_.Push(assertion);
     global_declarations_.Push(assertion);
 }
 
 void Module::AddTypeDecl(const TypeDecl* type) {
-    TINT_ASSERT(AST, type);
-    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(AST, type, generation_id);
+    TINT_ASSERT(type);
+    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(type, generation_id);
     type_decls_.Push(type);
     global_declarations_.Push(type);
 }
 
 void Module::AddFunction(const Function* func) {
-    TINT_ASSERT(AST, func);
-    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(AST, func, generation_id);
+    TINT_ASSERT(func);
+    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(func, generation_id);
     functions_.Push(func);
     global_declarations_.Push(func);
 }
@@ -145,10 +143,10 @@
 
     for (auto* decl : global_declarations_) {
         if (TINT_UNLIKELY(!decl)) {
-            TINT_ICE(AST, ctx->dst->Diagnostics()) << "src global declaration was nullptr";
+            TINT_ICE() << "src global declaration was nullptr";
             continue;
         }
-        BinGlobalDeclaration(decl, ctx->dst->Diagnostics());
+        BinGlobalDeclaration(decl);
     }
 }
 
diff --git a/src/tint/lang/wgsl/ast/module.h b/src/tint/lang/wgsl/ast/module.h
index 23e33e6..b0516bd 100644
--- a/src/tint/lang/wgsl/ast/module.h
+++ b/src/tint/lang/wgsl/ast/module.h
@@ -144,7 +144,7 @@
     /// * #global_declarations_
     /// * #type_decls_
     /// * #functions_
-    void BinGlobalDeclaration(const tint::ast::Node* decl, diag::List& diags);
+    void BinGlobalDeclaration(const tint::ast::Node* decl);
 
     tint::Vector<const Node*, 64> global_declarations_;
     tint::Vector<const TypeDecl*, 16> type_decls_;
diff --git a/src/tint/lang/wgsl/ast/return_statement.cc b/src/tint/lang/wgsl/ast/return_statement.cc
index ec3122e..b3ae820 100644
--- a/src/tint/lang/wgsl/ast/return_statement.cc
+++ b/src/tint/lang/wgsl/ast/return_statement.cc
@@ -28,7 +28,7 @@
                                  const Source& src,
                                  const Expression* val)
     : Base(pid, nid, src), value(val) {
-    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(AST, value, generation_id);
+    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(value, generation_id);
 }
 
 ReturnStatement::~ReturnStatement() = default;
diff --git a/src/tint/lang/wgsl/ast/struct.cc b/src/tint/lang/wgsl/ast/struct.cc
index a471a83..266b3a4 100644
--- a/src/tint/lang/wgsl/ast/struct.cc
+++ b/src/tint/lang/wgsl/ast/struct.cc
@@ -30,12 +30,12 @@
                VectorRef<const Attribute*> attrs)
     : Base(pid, nid, src, n), members(std::move(m)), attributes(std::move(attrs)) {
     for (auto* mem : members) {
-        TINT_ASSERT(AST, mem);
-        TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(AST, mem, generation_id);
+        TINT_ASSERT(mem);
+        TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(mem, generation_id);
     }
     for (auto* attr : attributes) {
-        TINT_ASSERT(AST, attr);
-        TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(AST, attr, generation_id);
+        TINT_ASSERT(attr);
+        TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(attr, generation_id);
     }
 }
 
diff --git a/src/tint/lang/wgsl/ast/struct_member.cc b/src/tint/lang/wgsl/ast/struct_member.cc
index 1c1c3b1..4ec5e7d 100644
--- a/src/tint/lang/wgsl/ast/struct_member.cc
+++ b/src/tint/lang/wgsl/ast/struct_member.cc
@@ -28,14 +28,14 @@
                            VectorRef<const Attribute*> attrs)
 
     : Base(pid, nid, src), name(n), type(ty), attributes(std::move(attrs)) {
-    TINT_ASSERT(AST, name);
+    TINT_ASSERT(name);
     if (name) {
-        TINT_ASSERT(AST, !name->Is<TemplatedIdentifier>());
+        TINT_ASSERT(!name->Is<TemplatedIdentifier>());
     }
-    TINT_ASSERT(AST, type);
+    TINT_ASSERT(type);
     for (auto* attr : attributes) {
-        TINT_ASSERT(AST, attr);
-        TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(AST, attr, generation_id);
+        TINT_ASSERT(attr);
+        TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(attr, generation_id);
     }
 }
 
diff --git a/src/tint/lang/wgsl/ast/switch_statement.cc b/src/tint/lang/wgsl/ast/switch_statement.cc
index a8b9f65..a830f3e 100644
--- a/src/tint/lang/wgsl/ast/switch_statement.cc
+++ b/src/tint/lang/wgsl/ast/switch_statement.cc
@@ -34,19 +34,19 @@
       body(std::move(b)),
       attributes(std::move(stmt_attrs)),
       body_attributes(std::move(body_attrs)) {
-    TINT_ASSERT(AST, condition);
-    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(AST, condition, generation_id);
+    TINT_ASSERT(condition);
+    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(condition, generation_id);
     for (auto* stmt : body) {
-        TINT_ASSERT(AST, stmt);
-        TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(AST, stmt, generation_id);
+        TINT_ASSERT(stmt);
+        TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(stmt, generation_id);
     }
     for (auto* attr : attributes) {
-        TINT_ASSERT(AST, attr);
-        TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(AST, attr, generation_id);
+        TINT_ASSERT(attr);
+        TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(attr, generation_id);
     }
     for (auto* attr : body_attributes) {
-        TINT_ASSERT(AST, attr);
-        TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(AST, attr, generation_id);
+        TINT_ASSERT(attr);
+        TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(attr, generation_id);
     }
 }
 
diff --git a/src/tint/lang/wgsl/ast/templated_identifier.cc b/src/tint/lang/wgsl/ast/templated_identifier.cc
index 8d9bf5a..72d54f0 100644
--- a/src/tint/lang/wgsl/ast/templated_identifier.cc
+++ b/src/tint/lang/wgsl/ast/templated_identifier.cc
@@ -29,12 +29,12 @@
                                          VectorRef<const Expression*> args,
                                          VectorRef<const Attribute*> attrs)
     : Base(pid, nid, src, sym), arguments(std::move(args)), attributes(std::move(attrs)) {
-    TINT_ASSERT(AST, !arguments.IsEmpty());  // Should have been an Identifier if this fires.
+    TINT_ASSERT(!arguments.IsEmpty());  // Should have been an Identifier if this fires.
     for (auto* arg : arguments) {
-        TINT_ASSERT_GENERATION_IDS_EQUAL(AST, arg, generation_id);
+        TINT_ASSERT_GENERATION_IDS_EQUAL(arg, generation_id);
     }
     for (auto* attr : attributes) {
-        TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(AST, attr, generation_id);
+        TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(attr, generation_id);
     }
 }
 
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 53ef521..cb44940 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
@@ -156,9 +156,8 @@
             } else if (auto* arr = storage_buffer_type->As<type::Array>()) {
                 array_type = arr;
             } else {
-                TINT_ICE(Transform, b.Diagnostics())
-                    << "expected form of arrayLength argument to be &array_var or "
-                       "&struct_var.array_member";
+                TINT_ICE() << "expected form of arrayLength argument to be &array_var or "
+                              "&struct_var.array_member";
                 return;
             }
             auto* array_length = b.Div(total_size, u32(array_type->Stride()));
@@ -224,9 +223,8 @@
             //   arrayLength(&array_var)
             auto* param = call_expr->args[0]->As<UnaryOpExpression>();
             if (TINT_UNLIKELY(!param || param->op != UnaryOp::kAddressOf)) {
-                TINT_ICE(Transform, b.Diagnostics())
-                    << "expected form of arrayLength argument to be &array_var or "
-                       "&struct_var.array_member";
+                TINT_ICE() << "expected form of arrayLength argument to be &array_var or "
+                              "&struct_var.array_member";
                 break;
             }
             auto* storage_buffer_expr = param->expr;
@@ -235,16 +233,15 @@
             }
             auto* storage_buffer_sem = sem.Get<sem::VariableUser>(storage_buffer_expr);
             if (TINT_UNLIKELY(!storage_buffer_sem)) {
-                TINT_ICE(Transform, b.Diagnostics())
-                    << "expected form of arrayLength argument to be &array_var or "
-                       "&struct_var.array_member";
+                TINT_ICE() << "expected form of arrayLength argument to be &array_var or "
+                              "&struct_var.array_member";
                 break;
             }
 
             // Get the index to use for the buffer size array.
             auto* var = tint::As<sem::GlobalVariable>(storage_buffer_sem->Variable());
             if (TINT_UNLIKELY(!var)) {
-                TINT_ICE(Transform, b.Diagnostics()) << "storage buffer is not a global variable";
+                TINT_ICE() << "storage buffer is not a global variable";
                 break;
             }
             functor(call_expr, storage_buffer_sem, var);
diff --git a/src/tint/lang/wgsl/ast/transform/builtin_polyfill.cc b/src/tint/lang/wgsl/ast/transform/builtin_polyfill.cc
index 839fbf2..8bf324b 100644
--- a/src/tint/lang/wgsl/ast/transform/builtin_polyfill.cc
+++ b/src/tint/lang/wgsl/ast/transform/builtin_polyfill.cc
@@ -193,8 +193,7 @@
                 break;
             }
             default:
-                TINT_ICE(Transform, b.Diagnostics())
-                    << "unhandled polyfill level: " << static_cast<int>(cfg.builtins.acosh);
+                TINT_ICE() << "unhandled polyfill level: " << static_cast<int>(cfg.builtins.acosh);
                 return {};
         }
 
@@ -246,8 +245,7 @@
                                           b.GreaterThanEqual("x", V(1.0_a)))));
                 break;
             default:
-                TINT_ICE(Transform, b.Diagnostics())
-                    << "unhandled polyfill level: " << static_cast<int>(cfg.builtins.acosh);
+                TINT_ICE() << "unhandled polyfill level: " << static_cast<int>(cfg.builtins.acosh);
                 return {};
         }
 
@@ -436,8 +434,8 @@
                 body.Push(b.Return(b.Call("extractBits", "v", "s", b.Sub("e", "s"))));
                 break;
             default:
-                TINT_ICE(Transform, b.Diagnostics())
-                    << "unhandled polyfill level: " << static_cast<int>(cfg.builtins.extract_bits);
+                TINT_ICE() << "unhandled polyfill level: "
+                           << static_cast<int>(cfg.builtins.extract_bits);
                 return {};
         }
 
@@ -592,7 +590,7 @@
 
         // Currently in WGSL parameters of insertBits must be i32, u32, vecN<i32> or vecN<u32>
         if (TINT_UNLIKELY(((!ty->DeepestElement()->IsAnyOf<type::I32, type::U32>())))) {
-            TINT_ICE(Transform, b.Diagnostics())
+            TINT_ICE()
                 << "insertBits polyfill only support i32, u32, and vector of i32 or u32, got "
                 << ty->FriendlyName();
             return {};
@@ -674,8 +672,8 @@
                 body.Push(b.Return(b.Call("insertBits", "v", "n", "s", b.Sub("e", "s"))));
                 break;
             default:
-                TINT_ICE(Transform, b.Diagnostics())
-                    << "unhandled polyfill level: " << static_cast<int>(cfg.builtins.insert_bits);
+                TINT_ICE() << "unhandled polyfill level: "
+                           << static_cast<int>(cfg.builtins.insert_bits);
                 return {};
         }
 
diff --git a/src/tint/lang/wgsl/ast/transform/calculate_array_length.cc b/src/tint/lang/wgsl/ast/transform/calculate_array_length.cc
index 01abe0d..abbe9a5 100644
--- a/src/tint/lang/wgsl/ast/transform/calculate_array_length.cc
+++ b/src/tint/lang/wgsl/ast/transform/calculate_array_length.cc
@@ -150,7 +150,7 @@
                     auto* arg = call_expr->args[0];
                     auto* address_of = arg->As<UnaryOpExpression>();
                     if (TINT_UNLIKELY(!address_of || address_of->op != UnaryOp::kAddressOf)) {
-                        TINT_ICE(Transform, b.Diagnostics())
+                        TINT_ICE()
                             << "arrayLength() expected address-of, got " << arg->TypeInfo().name;
                     }
                     auto* storage_buffer_expr = address_of->expr;
@@ -159,9 +159,8 @@
                     }
                     auto* storage_buffer_sem = sem.Get<sem::VariableUser>(storage_buffer_expr);
                     if (TINT_UNLIKELY(!storage_buffer_sem)) {
-                        TINT_ICE(Transform, b.Diagnostics())
-                            << "expected form of arrayLength argument to be &array_var or "
-                               "&struct_var.array_member";
+                        TINT_ICE() << "expected form of arrayLength argument to be &array_var or "
+                                      "&struct_var.array_member";
                         break;
                     }
                     auto* storage_buffer_var = storage_buffer_sem->Variable();
@@ -210,9 +209,8 @@
                                 [&](const type::Array* arr) { return arr; });
 
                             if (TINT_UNLIKELY(!array_type)) {
-                                TINT_ICE(Transform, b.Diagnostics())
-                                    << "expected form of arrayLength argument to be "
-                                       "&array_var or &struct_var.array_member";
+                                TINT_ICE() << "expected form of arrayLength argument to be "
+                                              "&array_var or &struct_var.array_member";
                                 return 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 f7dd53f..4dfce6a 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
@@ -191,8 +191,7 @@
             // Obtain the builtin value from the semantic info.
             return ctx.src->Sem().Get(attr)->Value();
         }
-        TINT_ICE(Resolver, ctx.dst->Diagnostics())
-            << "could not obtain builtin value from attribute";
+        TINT_ICE() << "could not obtain builtin value from attribute";
         return builtin::BuiltinValue::kUndefined;
     }
 
@@ -375,7 +374,7 @@
         tint::Vector<const Expression*, 8> inner_struct_values;
         for (auto* member : str->Members()) {
             if (TINT_UNLIKELY(member->Type()->Is<type::Struct>())) {
-                TINT_ICE(Transform, ctx.dst->Diagnostics()) << "nested IO struct";
+                TINT_ICE() << "nested IO struct";
                 continue;
             }
 
@@ -404,7 +403,7 @@
         if (auto* str = inner_ret_type->As<sem::Struct>()) {
             for (auto* member : str->Members()) {
                 if (TINT_UNLIKELY(member->Type()->Is<type::Struct>())) {
-                    TINT_ICE(Transform, ctx.dst->Diagnostics()) << "nested IO struct";
+                    TINT_ICE() << "nested IO struct";
                     continue;
                 }
 
diff --git a/src/tint/lang/wgsl/ast/transform/clamp_frag_depth.cc b/src/tint/lang/wgsl/ast/transform/clamp_frag_depth.cc
index 9374f71..ccdd747 100644
--- a/src/tint/lang/wgsl/ast/transform/clamp_frag_depth.cc
+++ b/src/tint/lang/wgsl/ast/transform/clamp_frag_depth.cc
@@ -54,7 +54,7 @@
             if (auto* var = global->As<Var>()) {
                 auto* v = src->Sem().Get(var);
                 if (TINT_UNLIKELY(v->AddressSpace() == builtin::AddressSpace::kPushConstant)) {
-                    TINT_ICE(Transform, b.Diagnostics())
+                    TINT_ICE()
                         << "ClampFragDepth doesn't know how to handle module that already use push "
                            "constants";
                     return Program(std::move(b));
diff --git a/src/tint/lang/wgsl/ast/transform/decompose_memory_access.cc b/src/tint/lang/wgsl/ast/transform/decompose_memory_access.cc
index f74656f..fd5aa24 100644
--- a/src/tint/lang/wgsl/ast/transform/decompose_memory_access.cc
+++ b/src/tint/lang/wgsl/ast/transform/decompose_memory_access.cc
@@ -288,9 +288,8 @@
             op = DecomposeMemoryAccess::Intrinsic::Op::kAtomicCompareExchangeWeak;
             break;
         default:
-            TINT_ICE(Transform, builder->Diagnostics())
-                << "invalid IntrinsicType for DecomposeMemoryAccess::Intrinsic: "
-                << ty->TypeInfo().name;
+            TINT_ICE() << "invalid IntrinsicType for DecomposeMemoryAccess::Intrinsic: "
+                       << ty->TypeInfo().name;
             break;
     }
 
@@ -433,7 +432,7 @@
     /// @param expr the expression that performs the access
     /// @param access the access
     void AddAccess(const Expression* expr, const BufferAccess& access) {
-        TINT_ASSERT(Transform, access.type);
+        TINT_ASSERT(access.type);
         accesses.emplace(expr, access);
         expression_order.emplace_back(expr);
     }
@@ -495,7 +494,7 @@
                     // * Override-expression counts can only be applied to workgroup arrays, and
                     //   this method only handles storage and uniform.
                     // * Runtime-sized arrays are not loadable.
-                    TINT_ICE(Transform, b.Diagnostics()) << "unexpected non-constant array count";
+                    TINT_ICE() << "unexpected non-constant array count";
                     arr_cnt = 1;
                 }
                 auto* for_cond = b.create<BinaryExpression>(BinaryOp::kLessThan, b.Expr(i),
@@ -581,8 +580,7 @@
                             // * Override-expression counts can only be applied to workgroup
                             //   arrays, and this method only handles storage and uniform.
                             // * Runtime-sized arrays are not storable.
-                            TINT_ICE(Transform, b.Diagnostics())
-                                << "unexpected non-constant array count";
+                            TINT_ICE() << "unexpected non-constant array count";
                             arr_cnt = 1;
                         }
                         auto* for_cond = b.create<BinaryExpression>(BinaryOp::kLessThan, b.Expr(i),
@@ -651,9 +649,8 @@
 
             auto* atomic = IntrinsicAtomicFor(ctx.dst, op, el_ty, buffer);
             if (TINT_UNLIKELY(!atomic)) {
-                TINT_ICE(Transform, b.Diagnostics())
-                    << "IntrinsicAtomicFor() returned nullptr for op " << op << " and type "
-                    << el_ty->TypeInfo().name;
+                TINT_ICE() << "IntrinsicAtomicFor() returned nullptr for op " << op << " and type "
+                           << el_ty->TypeInfo().name;
             }
 
             Type ret_ty = CreateASTTypeFor(ctx, intrinsic->ReturnType());
diff --git a/src/tint/lang/wgsl/ast/transform/demote_to_helper.cc b/src/tint/lang/wgsl/ast/transform/demote_to_helper.cc
index 0caacab..2e950d9 100644
--- a/src/tint/lang/wgsl/ast/transform/demote_to_helper.cc
+++ b/src/tint/lang/wgsl/ast/transform/demote_to_helper.cc
@@ -134,7 +134,7 @@
                         // Skip these.
                         return;
                     default:
-                        TINT_UNREACHABLE(Transform, b.Diagnostics())
+                        TINT_UNREACHABLE()
                             << "write to unhandled address space: " << ref->AddressSpace();
                 }
 
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 9e651fa..7cfc434 100644
--- a/src/tint/lang/wgsl/ast/transform/direct_variable_access.cc
+++ b/src/tint/lang/wgsl/ast/transform/direct_variable_access.cc
@@ -1103,7 +1103,7 @@
                 continue;
             }
 
-            TINT_ICE(Transform, b.Diagnostics()) << "unhandled variant for access chain";
+            TINT_ICE() << "unhandled variant for access chain";
             break;
         }
         return ss.str();
@@ -1151,7 +1151,7 @@
             return b.MemberAccessor(expr, ctx.Clone(*member));
         }
 
-        TINT_ICE(Transform, b.Diagnostics()) << "unhandled variant type for access chain";
+        TINT_ICE() << "unhandled variant type for access chain";
         return nullptr;
     }
 
diff --git a/src/tint/lang/wgsl/ast/transform/fold_trivial_lets.cc b/src/tint/lang/wgsl/ast/transform/fold_trivial_lets.cc
index a7cbd26..2d81ceb 100644
--- a/src/tint/lang/wgsl/ast/transform/fold_trivial_lets.cc
+++ b/src/tint/lang/wgsl/ast/transform/fold_trivial_lets.cc
@@ -56,11 +56,11 @@
 
         // Helper that folds pending let declarations into `expr` if possible.
         auto fold_lets = [&](const Expression* expr) {
-            TraverseExpressions(expr, b.Diagnostics(), [&](const IdentifierExpression* ident) {
+            TraverseExpressions(expr, [&](const IdentifierExpression* ident) {
                 if (auto* user = sem.Get<sem::VariableUser>(ident)) {
                     auto itr = pending_lets.Find(user->Variable());
                     if (itr) {
-                        TINT_ASSERT(Transform, itr->remaining_uses > 0);
+                        TINT_ASSERT(itr->remaining_uses > 0);
 
                         // We found a reference to a pending let, so replace it with the inlined
                         // initializer expression.
diff --git a/src/tint/lang/wgsl/ast/transform/localize_struct_array_assignment.cc b/src/tint/lang/wgsl/ast/transform/localize_struct_array_assignment.cc
index 1e7160e..1e617bf 100644
--- a/src/tint/lang/wgsl/ast/transform/localize_struct_array_assignment.cc
+++ b/src/tint/lang/wgsl/ast/transform/localize_struct_array_assignment.cc
@@ -161,7 +161,7 @@
     /// structure member of array type.
     bool ContainsStructArrayIndex(const Expression* expr) {
         bool result = false;
-        TraverseExpressions(expr, b.Diagnostics(), [&](const IndexAccessorExpression* ia) {
+        TraverseExpressions(expr, [&](const IndexAccessorExpression* ia) {
             // Indexing using a runtime value?
             auto* idx_sem = src->Sem().GetVal(ia->index);
             if (!idx_sem->ConstantValue()) {
@@ -187,9 +187,8 @@
         const AssignmentStatement* assign_stmt) {
         auto* root_ident = src->Sem().GetVal(assign_stmt->lhs)->RootIdentifier();
         if (TINT_UNLIKELY(!root_ident)) {
-            TINT_ICE(Transform, b.Diagnostics())
-                << "Unable to determine originating variable for lhs of assignment "
-                   "statement";
+            TINT_ICE() << "Unable to determine originating variable for lhs of assignment "
+                          "statement";
             return {};
         }
 
@@ -202,9 +201,8 @@
                 return std::make_pair(ptr->StoreType(), ptr->AddressSpace());
             },
             [&](Default) {
-                TINT_ICE(Transform, b.Diagnostics())
-                    << "Expecting to find variable of type pointer or reference on lhs "
-                       "of assignment statement";
+                TINT_ICE() << "Expecting to find variable of type pointer or reference on lhs "
+                              "of assignment statement";
                 return std::pair<const type::Type*, builtin::AddressSpace>{};
             });
     }
diff --git a/src/tint/lang/wgsl/ast/transform/merge_return.cc b/src/tint/lang/wgsl/ast/transform/merge_return.cc
index 478d09e..ec25627 100644
--- a/src/tint/lang/wgsl/ast/transform/merge_return.cc
+++ b/src/tint/lang/wgsl/ast/transform/merge_return.cc
@@ -140,7 +140,7 @@
                 TINT_SCOPED_ASSIGNMENT(is_in_loop_or_switch, true);
                 ProcessStatement(w->body);
             },
-            [&](Default) { TINT_ICE(Transform, b.Diagnostics()) << "unhandled statement type"; });
+            [&](Default) { TINT_ICE() << "unhandled statement type"; });
     }
 
     void ProcessBlock(const BlockStatement* block) {
diff --git a/src/tint/lang/wgsl/ast/transform/module_scope_var_to_entry_point_param.cc b/src/tint/lang/wgsl/ast/transform/module_scope_var_to_entry_point_param.cc
index 4b3eb50..b29ed3f 100644
--- a/src/tint/lang/wgsl/ast/transform/module_scope_var_to_entry_point_param.cc
+++ b/src/tint/lang/wgsl/ast/transform/module_scope_var_to_entry_point_param.cc
@@ -205,8 +205,7 @@
                 break;
             }
             default: {
-                TINT_ICE(Transform, ctx.dst->Diagnostics())
-                    << "unhandled module-scope address space (" << sc << ")";
+                TINT_ICE() << "unhandled module-scope address space (" << sc << ")";
                 break;
             }
         }
@@ -241,8 +240,7 @@
                 break;
             }
             default: {
-                TINT_ICE(Transform, ctx.dst->Diagnostics())
-                    << "unhandled module-scope address space (" << sc << ")";
+                TINT_ICE() << "unhandled module-scope address space (" << sc << ")";
             }
         }
 
diff --git a/src/tint/lang/wgsl/ast/transform/multiplanar_external_texture.cc b/src/tint/lang/wgsl/ast/transform/multiplanar_external_texture.cc
index e059ba1..6689242 100644
--- a/src/tint/lang/wgsl/ast/transform/multiplanar_external_texture.cc
+++ b/src/tint/lang/wgsl/ast/transform/multiplanar_external_texture.cc
@@ -353,7 +353,7 @@
                 plane_1_call = b.Call("textureLoad", "plane1", "coord1", 0_a);
                 break;
             default:
-                TINT_ICE(Transform, b.Diagnostics()) << "unhandled builtin: " << call_type;
+                TINT_ICE() << "unhandled builtin: " << call_type;
         }
 
         // var color: vec3<f32>;
@@ -402,10 +402,9 @@
         const Expression* plane_0_binding_param = ctx.Clone(expr->args[0]);
 
         if (TINT_UNLIKELY(expr->args.Length() != 3)) {
-            TINT_ICE(Transform, b.Diagnostics())
-                << "expected textureSampleBaseClampToEdge call with a "
-                   "texture_external to have 3 parameters, found "
-                << expr->args.Length() << " parameters";
+            TINT_ICE() << "expected textureSampleBaseClampToEdge call with a "
+                          "texture_external to have 3 parameters, found "
+                       << expr->args.Length() << " parameters";
         }
 
         // TextureSampleExternal calls the gammaCorrection function, so ensure it
@@ -447,7 +446,7 @@
     /// @returns a call expression to textureLoadExternal
     const CallExpression* createTextureLoad(const sem::Call* call, NewBindingSymbols syms) {
         if (TINT_UNLIKELY(call->Arguments().Length() != 2)) {
-            TINT_ICE(Transform, b.Diagnostics())
+            TINT_ICE()
                 << "expected textureLoad call with a texture_external to have 2 arguments, found "
                 << call->Arguments().Length() << " arguments";
         }
diff --git a/src/tint/lang/wgsl/ast/transform/packed_vec3.cc b/src/tint/lang/wgsl/ast/transform/packed_vec3.cc
index 3042898..688a778 100644
--- a/src/tint/lang/wgsl/ast/transform/packed_vec3.cc
+++ b/src/tint/lang/wgsl/ast/transform/packed_vec3.cc
@@ -96,7 +96,7 @@
     /// @returns the new AST type
     Type MakePackedVec3(const type::Type* ty) {
         auto* vec = ty->As<type::Vector>();
-        TINT_ASSERT(Transform, vec != nullptr && vec->Width() == 3);
+        TINT_ASSERT(vec != nullptr && vec->Width() == 3);
         return b.ty(builtin::Builtin::kPackedVec3, CreateASTTypeFor(ctx, vec->type()));
     }
 
@@ -152,8 +152,7 @@
                     } else if (auto count = arr->ConstantCount()) {
                         return b.ty.array(new_type, u32(count.value()), std::move(attrs));
                     } else {
-                        TINT_ICE(Transform, b.Diagnostics())
-                            << type::Array::kErrExpectedConstantCount;
+                        TINT_ICE() << type::Array::kErrExpectedConstantCount;
                         return {};
                     }
                 }
@@ -247,7 +246,7 @@
         Switch(
             ty,
             [&](const type::Array* arr) {
-                TINT_ASSERT(Transform, arr->ConstantCount());
+                TINT_ASSERT(arr->ConstantCount());
                 copy_array_elements(arr->ConstantCount().value(), arr->ElemType());
             },
             [&](const type::Matrix* mat) {
@@ -461,7 +460,7 @@
 
         // Apply all of the pending unpack operations that we have collected.
         for (auto* expr : to_unpack_sorted) {
-            TINT_ASSERT(Transform, ContainsVec3(expr->Type()));
+            TINT_ASSERT(ContainsVec3(expr->Type()));
             auto* packed = ctx.Clone(expr->Declaration());
             const Expression* unpacked = nullptr;
             if (IsVec3(expr->Type())) {
@@ -476,13 +475,13 @@
                 // Use a helper function to unpack an array or matrix.
                 unpacked = UnpackComposite(packed, expr->Type());
             }
-            TINT_ASSERT(Transform, unpacked != nullptr);
+            TINT_ASSERT(unpacked != nullptr);
             ctx.Replace(expr->Declaration(), unpacked);
         }
 
         // Apply all of the pending pack operations that we have collected.
         for (auto* expr : to_pack_sorted) {
-            TINT_ASSERT(Transform, ContainsVec3(expr->Type()));
+            TINT_ASSERT(ContainsVec3(expr->Type()));
             auto* unpacked = ctx.Clone(expr->Declaration());
             const Expression* packed = nullptr;
             if (IsVec3(expr->Type())) {
@@ -492,7 +491,7 @@
                 // Use a helper function to pack an array or matrix.
                 packed = PackComposite(unpacked, expr->Type());
             }
-            TINT_ASSERT(Transform, packed != nullptr);
+            TINT_ASSERT(packed != nullptr);
             ctx.Replace(expr->Declaration(), packed);
         }
 
diff --git a/src/tint/lang/wgsl/ast/transform/preserve_padding.cc b/src/tint/lang/wgsl/ast/transform/preserve_padding.cc
index d4fb411..4dda687 100644
--- a/src/tint/lang/wgsl/ast/transform/preserve_padding.cc
+++ b/src/tint/lang/wgsl/ast/transform/preserve_padding.cc
@@ -174,7 +174,7 @@
                 });
             },
             [&](Default) {
-                TINT_ICE(Transform, b.Diagnostics()) << "unhandled type with padding";
+                TINT_ICE() << "unhandled type with padding";
                 return nullptr;
             });
     }
diff --git a/src/tint/lang/wgsl/ast/transform/promote_initializers_to_let.cc b/src/tint/lang/wgsl/ast/transform/promote_initializers_to_let.cc
index 7a520bb..4bb5bee 100644
--- a/src/tint/lang/wgsl/ast/transform/promote_initializers_to_let.cc
+++ b/src/tint/lang/wgsl/ast/transform/promote_initializers_to_let.cc
@@ -104,7 +104,7 @@
                 // visit leaf-expressions first, this means the content of const_chains only
                 // contains the outer-most constant expressions.
                 auto* expr = sem->Declaration();
-                bool ok = TraverseExpressions(expr, b.Diagnostics(), [&](const Expression* child) {
+                bool ok = TraverseExpressions(expr, [&](const Expression* child) {
                     const_chains.Remove(child);
                     return child == expr ? TraverseAction::Descend : TraverseAction::Skip;
                 });
diff --git a/src/tint/lang/wgsl/ast/transform/promote_side_effects_to_decl.cc b/src/tint/lang/wgsl/ast/transform/promote_side_effects_to_decl.cc
index 2aa2cd0..1e989f9 100644
--- a/src/tint/lang/wgsl/ast/transform/promote_side_effects_to_decl.cc
+++ b/src/tint/lang/wgsl/ast/transform/promote_side_effects_to_decl.cc
@@ -166,7 +166,7 @@
                 return false;
             },
             [&](Default) {
-                TINT_ICE(Transform, b.Diagnostics()) << "Unhandled expression type";
+                TINT_ICE() << "Unhandled expression type";
                 return false;
             });
     }
@@ -328,7 +328,7 @@
                 return false;
             },
             [&](Default) {
-                TINT_ICE(Transform, b.Diagnostics()) << "Unhandled expression type";
+                TINT_ICE() << "Unhandled expression type";
                 return false;
             });
     }
@@ -511,8 +511,7 @@
                 return clone_maybe_hoisted(phony);  // Leaf expression, just clone as is
             },
             [&](Default) {
-                TINT_ICE(AST, b.Diagnostics())
-                    << "unhandled expression type: " << expr->TypeInfo().name;
+                TINT_ICE() << "unhandled expression type: " << expr->TypeInfo().name;
                 return nullptr;
             });
     }
diff --git a/src/tint/lang/wgsl/ast/transform/remove_phonies.cc b/src/tint/lang/wgsl/ast/transform/remove_phonies.cc
index 92e6526..2f51084 100644
--- a/src/tint/lang/wgsl/ast/transform/remove_phonies.cc
+++ b/src/tint/lang/wgsl/ast/transform/remove_phonies.cc
@@ -58,25 +58,24 @@
                     made_changes = true;
 
                     std::vector<const Expression*> side_effects;
-                    if (!TraverseExpressions(
-                            stmt->rhs, b.Diagnostics(), [&](const CallExpression* expr) {
-                                // CallExpression may map to a function or builtin call
-                                // (both may have side-effects), or a value constructor or value
-                                // conversion (both do not have side effects).
-                                auto* call = sem.Get<sem::Call>(expr);
-                                if (!call) {
-                                    // Semantic node must be a Materialize, in which case the
-                                    // expression was creation-time (compile time), so could not
-                                    // have side effects. Just skip.
-                                    return TraverseAction::Skip;
-                                }
-                                if (call->Target()->IsAnyOf<sem::Function, sem::Builtin>() &&
-                                    call->HasSideEffects()) {
-                                    side_effects.push_back(expr);
-                                    return TraverseAction::Skip;
-                                }
-                                return TraverseAction::Descend;
-                            })) {
+                    if (!TraverseExpressions(stmt->rhs, [&](const CallExpression* expr) {
+                            // CallExpression may map to a function or builtin call
+                            // (both may have side-effects), or a value constructor or value
+                            // conversion (both do not have side effects).
+                            auto* call = sem.Get<sem::Call>(expr);
+                            if (!call) {
+                                // Semantic node must be a Materialize, in which case the
+                                // expression was creation-time (compile time), so could not
+                                // have side effects. Just skip.
+                                return TraverseAction::Skip;
+                            }
+                            if (call->Target()->IsAnyOf<sem::Function, sem::Builtin>() &&
+                                call->HasSideEffects()) {
+                                side_effects.push_back(expr);
+                                return TraverseAction::Skip;
+                            }
+                            return TraverseAction::Descend;
+                        })) {
                         return;
                     }
 
diff --git a/src/tint/lang/wgsl/ast/transform/robustness.cc b/src/tint/lang/wgsl/ast/transform/robustness.cc
index ecebc7d..3f3e93f 100644
--- a/src/tint/lang/wgsl/ast/transform/robustness.cc
+++ b/src/tint/lang/wgsl/ast/transform/robustness.cc
@@ -261,9 +261,8 @@
                 return nullptr;
             },
             [&](Default) -> const Expression* {
-                TINT_ICE(Transform, b.Diagnostics())
-                    << "unhandled object type in robustness of array index: "
-                    << obj_type->UnwrapRef()->FriendlyName();
+                TINT_ICE() << "unhandled object type in robustness of array index: "
+                           << obj_type->UnwrapRef()->FriendlyName();
                 return nullptr;
             });
     }
@@ -641,7 +640,7 @@
             default:
                 break;
         }
-        TINT_UNREACHABLE(Transform, b.Diagnostics()) << "unhandled address space" << address_space;
+        TINT_UNREACHABLE() << "unhandled address space" << address_space;
         return Action::kDefault;
     }
 
diff --git a/src/tint/lang/wgsl/ast/transform/single_entry_point.cc b/src/tint/lang/wgsl/ast/transform/single_entry_point.cc
index 35723ef..4019eb7 100644
--- a/src/tint/lang/wgsl/ast/transform/single_entry_point.cc
+++ b/src/tint/lang/wgsl/ast/transform/single_entry_point.cc
@@ -117,8 +117,7 @@
             [&](const Enable* ext) { b.AST().AddEnable(ctx.Clone(ext)); },
             [&](const DiagnosticDirective* d) { b.AST().AddDiagnosticDirective(ctx.Clone(d)); },
             [&](Default) {
-                TINT_UNREACHABLE(Transform, b.Diagnostics())
-                    << "unhandled global declaration: " << decl->TypeInfo().name;
+                TINT_UNREACHABLE() << "unhandled global declaration: " << decl->TypeInfo().name;
             });
     }
 
diff --git a/src/tint/lang/wgsl/ast/transform/spirv_atomic.cc b/src/tint/lang/wgsl/ast/transform/spirv_atomic.cc
index d5a64f2..96d5525 100644
--- a/src/tint/lang/wgsl/ast/transform/spirv_atomic.cc
+++ b/src/tint/lang/wgsl/ast/transform/spirv_atomic.cc
@@ -220,7 +220,7 @@
             },
             [&](const type::Reference* ref) { return AtomicTypeFor(ref->StoreType()); },
             [&](Default) {
-                TINT_ICE(Transform, b.Diagnostics()) << "unhandled type: " << ty->FriendlyName();
+                TINT_ICE();
                 return Type{};
             });
     }
diff --git a/src/tint/lang/wgsl/ast/transform/std140.cc b/src/tint/lang/wgsl/ast/transform/std140.cc
index 0b7939c..0a18620 100644
--- a/src/tint/lang/wgsl/ast/transform/std140.cc
+++ b/src/tint/lang/wgsl/ast/transform/std140.cc
@@ -437,8 +437,7 @@
                         // * Override-expression counts can only be applied to workgroup arrays, and
                         //   this method only handles types transitively used as uniform buffers.
                         // * Runtime-sized arrays cannot be used in uniform buffers.
-                        TINT_ICE(Transform, b.Diagnostics())
-                            << "unexpected non-constant array count";
+                        TINT_ICE() << "unexpected non-constant array count";
                         count = 1;
                     }
                     return b.ty.array(std140, b.Expr(u32(count.value())), std::move(attrs));
@@ -523,9 +522,8 @@
                         expr = user->Variable()->Initializer();
                         return Action::kContinue;
                     }
-                    TINT_ICE(Transform, b.Diagnostics())
-                        << "unexpected variable found walking access chain: "
-                        << user->Variable()->Declaration()->name->symbol.Name();
+                    TINT_ICE() << "unexpected variable found walking access chain: "
+                               << user->Variable()->Declaration()->name->symbol.Name();
                     return Action::kError;
                 },
                 [&](const sem::StructMemberAccess* a) {
@@ -580,18 +578,16 @@
                                               expr = sem.GetVal(u->expr);
                                               return Action::kContinue;
                                           default:
-                                              TINT_ICE(Transform, b.Diagnostics())
-                                                  << "unhandled unary op for access chain: "
-                                                  << u->op;
+                                              TINT_ICE() << "unhandled unary op for access chain: "
+                                                         << u->op;
                                               return Action::kError;
                                       }
                                   });
                 },
                 [&](Default) {
-                    TINT_ICE(Transform, b.Diagnostics())
-                        << "unhandled expression type for access chain\n"
-                        << "AST: " << expr->Declaration()->TypeInfo().name << "\n"
-                        << "SEM: " << expr->TypeInfo().name;
+                    TINT_ICE() << "unhandled expression type for access chain\n"
+                               << "AST: " << expr->Declaration()->TypeInfo().name << "\n"
+                               << "SEM: " << expr->TypeInfo().name;
                     return Action::kError;
                 });
 
@@ -636,7 +632,7 @@
                     // * Override-expression counts can only be applied to workgroup arrays, and
                     //   this method only handles types transitively used as uniform buffers.
                     // * Runtime-sized arrays cannot be used in uniform buffers.
-                    TINT_ICE(Transform, b.Diagnostics()) << "unexpected non-constant array count";
+                    TINT_ICE() << "unexpected non-constant array count";
                     count = 1;
                 }
                 return "arr" + std::to_string(count.value()) + "_" + ConvertSuffix(arr->ElemType());
@@ -648,8 +644,7 @@
             [&](const type::F32*) { return "f32"; },  //
             [&](const type::F16*) { return "f16"; },
             [&](Default) {
-                TINT_ICE(Transform, b.Diagnostics())
-                    << "unhandled type for conversion name: " << ty->FriendlyName();
+                TINT_ICE() << "unhandled type for conversion name: " << ty->FriendlyName();
                 return "";
             });
     }
@@ -724,7 +719,7 @@
                         });
                         stmts.Push(b.Return(b.Call(mat_ty, std::move(mat_args))));
                     } else {
-                        TINT_ICE(Transform, b.Diagnostics())
+                        TINT_ICE()
                             << "failed to find std140 matrix info for: " << ty->FriendlyName();
                     }
                 },  //
@@ -742,8 +737,7 @@
                         // * Override-expression counts can only be applied to workgroup arrays, and
                         //   this method only handles types transitively used as uniform buffers.
                         // * Runtime-sized arrays cannot be used in uniform buffers.
-                        TINT_ICE(Transform, b.Diagnostics())
-                            << "unexpected non-constant array count";
+                        TINT_ICE() << "unexpected non-constant array count";
                         count = 1;
                     }
                     stmts.Push(b.Decl(var));
@@ -754,8 +748,7 @@
                     stmts.Push(b.Return(var));
                 },
                 [&](Default) {
-                    TINT_ICE(Transform, b.Diagnostics())
-                        << "unhandled type for conversion: " << ty->FriendlyName();
+                    TINT_ICE() << "unhandled type for conversion: " << ty->FriendlyName();
                 });
 
             // Generate the function
@@ -1100,8 +1093,7 @@
                     return {expr, vec->type(), name};
                 },  //
                 [&](Default) -> ExprTypeName {
-                    TINT_ICE(Transform, b.Diagnostics())
-                        << "unhandled type for access chain: " << ty->FriendlyName();
+                    TINT_ICE() << "unhandled type for access chain: " << ty->FriendlyName();
                     return {};
                 });
         }
@@ -1121,8 +1113,7 @@
                     return {expr, swizzle_ty, rhs};
                 },  //
                 [&](Default) -> ExprTypeName {
-                    TINT_ICE(Transform, b.Diagnostics())
-                        << "unhandled type for access chain: " << ty->FriendlyName();
+                    TINT_ICE() << "unhandled type for access chain: " << ty->FriendlyName();
                     return {};
                 });
         }
@@ -1150,8 +1141,7 @@
                 return {expr, vec->type(), std::to_string(idx)};
             },  //
             [&](Default) -> ExprTypeName {
-                TINT_ICE(Transform, b.Diagnostics())
-                    << "unhandled type for access chain: " << ty->FriendlyName();
+                TINT_ICE() << "unhandled type for access chain: " << ty->FriendlyName();
                 return {};
             });
     }
diff --git a/src/tint/lang/wgsl/ast/transform/transform.cc b/src/tint/lang/wgsl/ast/transform/transform.cc
index ab0bdfb..5b561bb 100644
--- a/src/tint/lang/wgsl/ast/transform/transform.cc
+++ b/src/tint/lang/wgsl/ast/transform/transform.cc
@@ -59,8 +59,7 @@
         ctx.Replace(stmt, static_cast<Expression*>(nullptr));
         return;
     }
-    TINT_ICE(Transform, ctx.dst->Diagnostics())
-        << "unable to remove statement from parent of type " << sem->TypeInfo().name;
+    TINT_ICE() << "unable to remove statement from parent of type " << sem->TypeInfo().name;
 }
 
 Type Transform::CreateASTTypeFor(CloneContext& ctx, const type::Type* ty) {
@@ -89,7 +88,7 @@
     if (auto* v = ty->As<type::Vector>()) {
         auto el = CreateASTTypeFor(ctx, v->type());
         if (v->Packed()) {
-            TINT_ASSERT(Transform, v->Width() == 3u);
+            TINT_ASSERT(v->Width() == 3u);
             return ctx.dst->ty(builtin::Builtin::kPackedVec3, el);
         } else {
             return ctx.dst->ty.vec(el, v->Width());
@@ -127,7 +126,7 @@
         }
         auto count = a->ConstantCount();
         if (TINT_UNLIKELY(!count)) {
-            TINT_ICE(Transform, ctx.dst->Diagnostics()) << type::Array::kErrExpectedConstantCount;
+            TINT_ICE() << 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));
@@ -171,8 +170,7 @@
                           : builtin::Access::kUndefined;
         return ctx.dst->ty.ptr(address_space, CreateASTTypeFor(ctx, p->StoreType()), access);
     }
-    TINT_UNREACHABLE(Transform, ctx.dst->Diagnostics())
-        << "Unhandled type: " << ty->TypeInfo().name;
+    TINT_UNREACHABLE() << "Unhandled type: " << ty->TypeInfo().name;
     return Type{};
 }
 
diff --git a/src/tint/lang/wgsl/ast/transform/truncate_interstage_variables.cc b/src/tint/lang/wgsl/ast/transform/truncate_interstage_variables.cc
index 5f076f6..1e6f3e4 100644
--- a/src/tint/lang/wgsl/ast/transform/truncate_interstage_variables.cc
+++ b/src/tint/lang/wgsl/ast/transform/truncate_interstage_variables.cc
@@ -86,10 +86,9 @@
         // This transform is run after CanonicalizeEntryPointIO transform,
         // So it is guaranteed that entry point inputs are already grouped in a struct.
         if (TINT_UNLIKELY(!str)) {
-            TINT_ICE(Transform, ctx.dst->Diagnostics())
-                << "Entrypoint function return type is non-struct.\n"
-                << "TruncateInterstageVariables transform needs to run after "
-                   "CanonicalizeEntryPointIO transform.";
+            TINT_ICE() << "Entrypoint function return type is non-struct.\n"
+                       << "TruncateInterstageVariables transform needs to run after "
+                          "CanonicalizeEntryPointIO transform.";
             continue;
         }
 
diff --git a/src/tint/lang/wgsl/ast/transform/unshadow.cc b/src/tint/lang/wgsl/ast/transform/unshadow.cc
index 09ba661..17da2d1 100644
--- a/src/tint/lang/wgsl/ast/transform/unshadow.cc
+++ b/src/tint/lang/wgsl/ast/transform/unshadow.cc
@@ -74,8 +74,7 @@
                     return b.Param(source, symbol, type, attributes);
                 },
                 [&](Default) {
-                    TINT_ICE(Transform, b.Diagnostics())
-                        << "unexpected variable type: " << decl->TypeInfo().name;
+                    TINT_ICE() << "unexpected variable type: " << decl->TypeInfo().name;
                     return nullptr;
                 });
         };
diff --git a/src/tint/lang/wgsl/ast/transform/utils/get_insertion_point.cc b/src/tint/lang/wgsl/ast/transform/utils/get_insertion_point.cc
index d5f541e..641028d 100644
--- a/src/tint/lang/wgsl/ast/transform/utils/get_insertion_point.cc
+++ b/src/tint/lang/wgsl/ast/transform/utils/get_insertion_point.cc
@@ -14,15 +14,14 @@
 
 #include "src/tint/lang/wgsl/ast/transform/utils/get_insertion_point.h"
 #include "src/tint/lang/wgsl/sem/for_loop_statement.h"
-#include "src/tint/utils/debug/debug.h"
 #include "src/tint/utils/diagnostic/diagnostic.h"
+#include "src/tint/utils/ice/ice.h"
 #include "src/tint/utils/rtti/switch.h"
 
 namespace tint::ast::transform::utils {
 
 InsertionPoint GetInsertionPoint(CloneContext& ctx, const Statement* stmt) {
     auto& sem = ctx.src->Sem();
-    auto& diag = ctx.dst->Diagnostics();
     using RetType = std::pair<const sem::BlockStatement*, const Statement*>;
 
     if (auto* sem_stmt = sem.Get(stmt)) {
@@ -46,8 +45,8 @@
                 return {};
             },
             [&](Default) -> RetType {
-                TINT_ICE(Transform, diag) << "expected parent of statement to be "
-                                             "either a block or for loop";
+                TINT_ICE() << "expected parent of statement to be "
+                              "either a block or for loop";
                 return {};
             });
     }
diff --git a/src/tint/lang/wgsl/ast/transform/utils/get_insertion_point_test.cc b/src/tint/lang/wgsl/ast/transform/utils/get_insertion_point_test.cc
index 5e8deb4..8a779ce 100644
--- a/src/tint/lang/wgsl/ast/transform/utils/get_insertion_point_test.cc
+++ b/src/tint/lang/wgsl/ast/transform/utils/get_insertion_point_test.cc
@@ -18,7 +18,7 @@
 #include "src/tint/lang/wgsl/ast/transform/test_helper.h"
 #include "src/tint/lang/wgsl/ast/transform/utils/get_insertion_point.h"
 #include "src/tint/lang/wgsl/program/program_builder.h"
-#include "src/tint/utils/debug/debug.h"
+#include "src/tint/utils/ice/ice.h"
 
 using namespace tint::number_suffixes;  // NOLINT
 
@@ -41,8 +41,7 @@
     ProgramBuilder cloned_b;
     CloneContext ctx(&cloned_b, &original);
 
-    // Can insert in block containing the variable, above or below the input
-    // statement.
+    // Can insert in block containing the variable, above or below the input statement.
     auto ip = utils::GetInsertionPoint(ctx, var);
     ASSERT_EQ(ip.first->Declaration(), block);
     ASSERT_EQ(ip.second, var);
@@ -85,8 +84,7 @@
     ProgramBuilder cloned_b;
     CloneContext ctx(&cloned_b, &original);
 
-    // Can't insert before/after for loop continue statement (would ned to be
-    // converted to loop).
+    // Can't insert before/after for loop continue statement (would ned to be converted to loop).
     auto ip = utils::GetInsertionPoint(ctx, var);
     ASSERT_EQ(ip.first, nullptr);
     ASSERT_EQ(ip.second, nullptr);
diff --git a/src/tint/lang/wgsl/ast/transform/utils/hoist_to_decl_before.cc b/src/tint/lang/wgsl/ast/transform/utils/hoist_to_decl_before.cc
index 8f81f37..49a2950 100644
--- a/src/tint/lang/wgsl/ast/transform/utils/hoist_to_decl_before.cc
+++ b/src/tint/lang/wgsl/ast/transform/utils/hoist_to_decl_before.cc
@@ -45,7 +45,7 @@
         switch (kind) {
             case VariableKind::kLet: {
                 auto* ty = ctx.src->Sem().GetVal(expr)->Type();
-                TINT_ASSERT(Transform, !ty->HoldsAbstract());
+                TINT_ASSERT(!ty->HoldsAbstract());
                 auto builder = [this, expr, name, ty] {
                     return b.Decl(b.Let(name, Transform::CreateASTTypeFor(ctx, ty),
                                         ctx.CloneWithoutTransform(expr)));
@@ -58,7 +58,7 @@
 
             case VariableKind::kVar: {
                 auto* ty = ctx.src->Sem().GetVal(expr)->Type();
-                TINT_ASSERT(Transform, !ty->HoldsAbstract());
+                TINT_ASSERT(!ty->HoldsAbstract());
                 auto builder = [this, expr, name, ty] {
                     return b.Decl(b.Var(name, Transform::CreateASTTypeFor(ctx, ty),
                                         ctx.CloneWithoutTransform(expr)));
@@ -397,12 +397,11 @@
                 return true;
             }
 
-            TINT_ICE(Transform, b.Diagnostics()) << "unhandled use of expression in for-loop";
+            TINT_ICE() << "unhandled use of expression in for-loop";
             return false;
         }
 
-        TINT_ICE(Transform, b.Diagnostics())
-            << "unhandled expression parent statement type: " << parent->TypeInfo().name;
+        TINT_ICE() << "unhandled expression parent statement type: " << parent->TypeInfo().name;
         return false;
     }
 };
diff --git a/src/tint/lang/wgsl/ast/transform/vectorize_matrix_conversions.cc b/src/tint/lang/wgsl/ast/transform/vectorize_matrix_conversions.cc
index 482abfe..05d89a8 100644
--- a/src/tint/lang/wgsl/ast/transform/vectorize_matrix_conversions.cc
+++ b/src/tint/lang/wgsl/ast/transform/vectorize_matrix_conversions.cc
@@ -96,8 +96,7 @@
         // The source and destination type of a matrix conversion must have a same shape.
         if (TINT_UNLIKELY(!(src_type->rows() == dst_type->rows() &&
                             src_type->columns() == dst_type->columns()))) {
-            TINT_ICE(Transform, b.Diagnostics())
-                << "source and destination matrix has different shape in matrix conversion";
+            TINT_ICE() << "source and destination matrix has different shape in matrix conversion";
             return nullptr;
         }
 
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 bb55628..cbdcfc3 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
@@ -134,8 +134,7 @@
             });
         }
 
-        TINT_ICE(Transform, b.Diagnostics())
-            << "matrix initializer has unexpected number of arguments";
+        TINT_ICE() << "matrix initializer has unexpected number of arguments";
         return nullptr;
     });
 
diff --git a/src/tint/lang/wgsl/ast/transform/vertex_pulling.cc b/src/tint/lang/wgsl/ast/transform/vertex_pulling.cc
index 17bcf6f..40630d3 100644
--- a/src/tint/lang/wgsl/ast/transform/vertex_pulling.cc
+++ b/src/tint/lang/wgsl/ast/transform/vertex_pulling.cc
@@ -426,7 +426,7 @@
                             value = b.MemberAccessor(fetch, "xyz");
                             break;
                         default:
-                            TINT_UNREACHABLE(Transform, b.Diagnostics()) << var_dt.width;
+                            TINT_UNREACHABLE() << var_dt.width;
                             return nullptr;
                     }
                 } else if (var_dt.width > fmt_dt.width) {
@@ -668,7 +668,7 @@
                                          b.Call("unpack2x16float", load_next_u32()));
         }
 
-        TINT_UNREACHABLE(Transform, b.Diagnostics()) << "format " << static_cast<int>(format);
+        TINT_UNREACHABLE();
         return nullptr;
     }
 
@@ -721,8 +721,7 @@
             default:
                 break;
         }
-        TINT_UNREACHABLE(Transform, b.Diagnostics())
-            << "invalid format for LoadPrimitive" << static_cast<int>(format);
+        TINT_UNREACHABLE() << "invalid format for LoadPrimitive" << static_cast<int>(format);
         return nullptr;
     }
 
@@ -772,14 +771,14 @@
             info.type = sem->Type();
 
             if (TINT_UNLIKELY(!sem->Location().has_value())) {
-                TINT_ICE(Transform, b.Diagnostics()) << "Location missing value";
+                TINT_ICE() << "Location missing value";
                 return;
             }
             location_info[sem->Location().value()] = info;
         } else {
             auto* builtin_attr = GetAttribute<BuiltinAttribute>(param->attributes);
             if (TINT_UNLIKELY(!builtin_attr)) {
-                TINT_ICE(Transform, b.Diagnostics()) << "Invalid entry point parameter";
+                TINT_ICE() << "Invalid entry point parameter";
                 return;
             }
             auto builtin = src->Sem().Get(builtin_attr)->Value();
@@ -827,13 +826,13 @@
                 auto* sem = src->Sem().Get(member);
                 info.type = sem->Type();
 
-                TINT_ASSERT(Transform, sem->Attributes().location.has_value());
+                TINT_ASSERT(sem->Attributes().location.has_value());
                 location_info[sem->Attributes().location.value()] = info;
                 has_locations = true;
             } else {
                 auto* builtin_attr = GetAttribute<BuiltinAttribute>(member->attributes);
                 if (TINT_UNLIKELY(!builtin_attr)) {
-                    TINT_ICE(Transform, b.Diagnostics()) << "Invalid entry point parameter";
+                    TINT_ICE() << "Invalid entry point parameter";
                     return;
                 }
                 auto builtin = src->Sem().Get(builtin_attr)->Value();
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 c8772d6..eec3828 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
@@ -359,8 +359,7 @@
             return BuildZeroingStatements(arr->ElemType(), get_el);
         }
 
-        TINT_UNREACHABLE(Transform, b.Diagnostics())
-            << "could not zero workgroup type: " << ty->FriendlyName();
+        TINT_UNREACHABLE() << "could not zero workgroup type: " << ty->FriendlyName();
         return false;
     }
 
diff --git a/src/tint/lang/wgsl/ast/traverse_expressions.h b/src/tint/lang/wgsl/ast/traverse_expressions.h
index f3ecd3c..17688c2 100644
--- a/src/tint/lang/wgsl/ast/traverse_expressions.h
+++ b/src/tint/lang/wgsl/ast/traverse_expressions.h
@@ -55,15 +55,14 @@
 /// from `root`, calling `callback` for each of the visited expressions that
 /// match the predicate parameter type, in pre-ordering (root first).
 /// @param root the root expression node
-/// @param diags the diagnostics used for error messages
 /// @param callback the callback function. Must be of the signature:
 ///        `TraverseAction(const T* expr)` or `TraverseAction(const T* expr, size_t depth)` where T
 ///        is an Expression type.
 /// @return true on success, false on error
 template <TraverseOrder ORDER = TraverseOrder::LeftToRight, typename CALLBACK>
-bool TraverseExpressions(const Expression* root, diag::List& diags, CALLBACK&& callback) {
-    using EXPR_TYPE = std::remove_pointer_t<tint::traits::ParameterType<CALLBACK, 0>>;
-    constexpr static bool kHasDepthArg = tint::traits::SignatureOfT<CALLBACK>::parameter_count == 2;
+bool TraverseExpressions(const Expression* root, CALLBACK&& callback) {
+    using EXPR_TYPE = std::remove_pointer_t<traits::ParameterType<CALLBACK, 0>>;
+    constexpr static bool kHasDepthArg = traits::SignatureOfT<CALLBACK>::parameter_count == 2;
 
     struct Pending {
         const Expression* expr;
@@ -147,8 +146,8 @@
                                                PhonyExpression>()))) {
                     return true;  // Leaf expression
                 }
-                TINT_ICE(AST, diags)
-                    << "unhandled expression type: " << (expr ? expr->TypeInfo().name : "<null>");
+                TINT_ICE() << "unhandled expression type: "
+                           << (expr ? expr->TypeInfo().name : "<null>");
                 return false;
             });
         if (!ok) {
diff --git a/src/tint/lang/wgsl/ast/traverse_expressions_test.cc b/src/tint/lang/wgsl/ast/traverse_expressions_test.cc
index 7fd864a..4f9d567 100644
--- a/src/tint/lang/wgsl/ast/traverse_expressions_test.cc
+++ b/src/tint/lang/wgsl/ast/traverse_expressions_test.cc
@@ -31,20 +31,18 @@
     auto* root = IndexAccessor(i[0], i[1]);
     {
         std::vector<const Expression*> l2r;
-        TraverseExpressions<TraverseOrder::LeftToRight>(root, Diagnostics(),
-                                                        [&](const Expression* expr) {
-                                                            l2r.push_back(expr);
-                                                            return TraverseAction::Descend;
-                                                        });
+        TraverseExpressions<TraverseOrder::LeftToRight>(root, [&](const Expression* expr) {
+            l2r.push_back(expr);
+            return TraverseAction::Descend;
+        });
         EXPECT_THAT(l2r, ElementsAre(root, i[0], e[0], e[1], i[1], e[2], e[3]));
     }
     {
         std::vector<const Expression*> r2l;
-        TraverseExpressions<TraverseOrder::RightToLeft>(root, Diagnostics(),
-                                                        [&](const Expression* expr) {
-                                                            r2l.push_back(expr);
-                                                            return TraverseAction::Descend;
-                                                        });
+        TraverseExpressions<TraverseOrder::RightToLeft>(root, [&](const Expression* expr) {
+            r2l.push_back(expr);
+            return TraverseAction::Descend;
+        });
         EXPECT_THAT(r2l, ElementsAre(root, i[1], e[3], e[2], i[0], e[1], e[0]));
     }
 }
@@ -55,20 +53,18 @@
     auto* root = Mul(i[0], i[1]);
     {
         std::vector<const Expression*> l2r;
-        TraverseExpressions<TraverseOrder::LeftToRight>(root, Diagnostics(),
-                                                        [&](const Expression* expr) {
-                                                            l2r.push_back(expr);
-                                                            return TraverseAction::Descend;
-                                                        });
+        TraverseExpressions<TraverseOrder::LeftToRight>(root, [&](const Expression* expr) {
+            l2r.push_back(expr);
+            return TraverseAction::Descend;
+        });
         EXPECT_THAT(l2r, ElementsAre(root, i[0], e[0], e[1], i[1], e[2], e[3]));
     }
     {
         std::vector<const Expression*> r2l;
-        TraverseExpressions<TraverseOrder::RightToLeft>(root, Diagnostics(),
-                                                        [&](const Expression* expr) {
-                                                            r2l.push_back(expr);
-                                                            return TraverseAction::Descend;
-                                                        });
+        TraverseExpressions<TraverseOrder::RightToLeft>(root, [&](const Expression* expr) {
+            r2l.push_back(expr);
+            return TraverseAction::Descend;
+        });
         EXPECT_THAT(r2l, ElementsAre(root, i[1], e[3], e[2], i[0], e[1], e[0]));
     }
 }
@@ -82,7 +78,7 @@
     size_t depths[] = {0, 1, 2, 2, 1, 2, 2};
     {
         TraverseExpressions<TraverseOrder::LeftToRight>(  //
-            root, Diagnostics(), [&](const Expression* expr, size_t depth) {
+            root, [&](const Expression* expr, size_t depth) {
                 (void)expr;
                 EXPECT_THAT(depth, depths[j++]);
                 return TraverseAction::Descend;
@@ -97,21 +93,19 @@
     auto* b2 = Bitcast<i32>(b1);
     auto* root = Bitcast<i32>(b2);
     {
-        tint::Vector<const Expression*, 8> l2r;
-        TraverseExpressions<TraverseOrder::LeftToRight>(root, Diagnostics(),
-                                                        [&](const Expression* expr) {
-                                                            l2r.Push(expr);
-                                                            return TraverseAction::Descend;
-                                                        });
+        Vector<const Expression*, 8> l2r;
+        TraverseExpressions<TraverseOrder::LeftToRight>(root, [&](const Expression* expr) {
+            l2r.Push(expr);
+            return TraverseAction::Descend;
+        });
         EXPECT_THAT(l2r, ElementsAre(root, b2, b1, b0, e));
     }
     {
-        tint::Vector<const Expression*, 8> r2l;
-        TraverseExpressions<TraverseOrder::RightToLeft>(root, Diagnostics(),
-                                                        [&](const Expression* expr) {
-                                                            r2l.Push(expr);
-                                                            return TraverseAction::Descend;
-                                                        });
+        Vector<const Expression*, 8> r2l;
+        TraverseExpressions<TraverseOrder::RightToLeft>(root, [&](const Expression* expr) {
+            r2l.Push(expr);
+            return TraverseAction::Descend;
+        });
         EXPECT_THAT(r2l, ElementsAre(root, b2, b1, b0, e));
     }
 }
@@ -121,21 +115,19 @@
     tint::Vector c{Call("a", e[0], e[1]), Call("b", e[2], e[3])};
     auto* root = Call("c", c[0], c[1]);
     {
-        tint::Vector<const Expression*, 8> l2r;
-        TraverseExpressions<TraverseOrder::LeftToRight>(root, Diagnostics(),
-                                                        [&](const Expression* expr) {
-                                                            l2r.Push(expr);
-                                                            return TraverseAction::Descend;
-                                                        });
+        Vector<const Expression*, 8> l2r;
+        TraverseExpressions<TraverseOrder::LeftToRight>(root, [&](const Expression* expr) {
+            l2r.Push(expr);
+            return TraverseAction::Descend;
+        });
         EXPECT_THAT(l2r, ElementsAre(root, c[0], e[0], e[1], c[1], e[2], e[3]));
     }
     {
-        tint::Vector<const Expression*, 8> r2l;
-        TraverseExpressions<TraverseOrder::RightToLeft>(root, Diagnostics(),
-                                                        [&](const Expression* expr) {
-                                                            r2l.Push(expr);
-                                                            return TraverseAction::Descend;
-                                                        });
+        Vector<const Expression*, 8> r2l;
+        TraverseExpressions<TraverseOrder::RightToLeft>(root, [&](const Expression* expr) {
+            r2l.Push(expr);
+            return TraverseAction::Descend;
+        });
         EXPECT_THAT(r2l, ElementsAre(root, c[1], e[3], e[2], c[0], e[1], e[0]));
     }
 }
@@ -146,20 +138,18 @@
     auto* root = MemberAccessor(m, "b");
     {
         std::vector<const Expression*> l2r;
-        TraverseExpressions<TraverseOrder::LeftToRight>(root, Diagnostics(),
-                                                        [&](const Expression* expr) {
-                                                            l2r.push_back(expr);
-                                                            return TraverseAction::Descend;
-                                                        });
+        TraverseExpressions<TraverseOrder::LeftToRight>(root, [&](const Expression* expr) {
+            l2r.push_back(expr);
+            return TraverseAction::Descend;
+        });
         EXPECT_THAT(l2r, ElementsAre(root, m, e));
     }
     {
         std::vector<const Expression*> r2l;
-        TraverseExpressions<TraverseOrder::RightToLeft>(root, Diagnostics(),
-                                                        [&](const Expression* expr) {
-                                                            r2l.push_back(expr);
-                                                            return TraverseAction::Descend;
-                                                        });
+        TraverseExpressions<TraverseOrder::RightToLeft>(root, [&](const Expression* expr) {
+            r2l.push_back(expr);
+            return TraverseAction::Descend;
+        });
         EXPECT_THAT(r2l, ElementsAre(root, m, e));
     }
 }
@@ -174,20 +164,18 @@
     auto* root = IndexAccessor(c, f);
     {
         std::vector<const Expression*> l2r;
-        TraverseExpressions<TraverseOrder::LeftToRight>(root, Diagnostics(),
-                                                        [&](const Expression* expr) {
-                                                            l2r.push_back(expr);
-                                                            return TraverseAction::Descend;
-                                                        });
+        TraverseExpressions<TraverseOrder::LeftToRight>(root, [&](const Expression* expr) {
+            l2r.push_back(expr);
+            return TraverseAction::Descend;
+        });
         EXPECT_THAT(l2r, ElementsAre(root, c, a, b, f, d, e));
     }
     {
         std::vector<const Expression*> r2l;
-        TraverseExpressions<TraverseOrder::RightToLeft>(root, Diagnostics(),
-                                                        [&](const Expression* expr) {
-                                                            r2l.push_back(expr);
-                                                            return TraverseAction::Descend;
-                                                        });
+        TraverseExpressions<TraverseOrder::RightToLeft>(root, [&](const Expression* expr) {
+            r2l.push_back(expr);
+            return TraverseAction::Descend;
+        });
         EXPECT_THAT(r2l, ElementsAre(root, f, e, d, c, b, a));
     }
 }
@@ -200,20 +188,18 @@
     auto* root = Deref(u2);
     {
         std::vector<const Expression*> l2r;
-        TraverseExpressions<TraverseOrder::LeftToRight>(root, Diagnostics(),
-                                                        [&](const Expression* expr) {
-                                                            l2r.push_back(expr);
-                                                            return TraverseAction::Descend;
-                                                        });
+        TraverseExpressions<TraverseOrder::LeftToRight>(root, [&](const Expression* expr) {
+            l2r.push_back(expr);
+            return TraverseAction::Descend;
+        });
         EXPECT_THAT(l2r, ElementsAre(root, u2, u1, u0, e));
     }
     {
         std::vector<const Expression*> r2l;
-        TraverseExpressions<TraverseOrder::RightToLeft>(root, Diagnostics(),
-                                                        [&](const Expression* expr) {
-                                                            r2l.push_back(expr);
-                                                            return TraverseAction::Descend;
-                                                        });
+        TraverseExpressions<TraverseOrder::RightToLeft>(root, [&](const Expression* expr) {
+            r2l.push_back(expr);
+            return TraverseAction::Descend;
+        });
         EXPECT_THAT(r2l, ElementsAre(root, u2, u1, u0, e));
     }
 }
@@ -223,11 +209,10 @@
     std::vector<const Expression*> i = {IndexAccessor(e[0], e[1]), IndexAccessor(e[2], e[3])};
     auto* root = IndexAccessor(i[0], i[1]);
     std::vector<const Expression*> order;
-    TraverseExpressions<TraverseOrder::LeftToRight>(
-        root, Diagnostics(), [&](const Expression* expr) {
-            order.push_back(expr);
-            return expr == i[0] ? TraverseAction::Skip : TraverseAction::Descend;
-        });
+    TraverseExpressions<TraverseOrder::LeftToRight>(root, [&](const Expression* expr) {
+        order.push_back(expr);
+        return expr == i[0] ? TraverseAction::Skip : TraverseAction::Descend;
+    });
     EXPECT_THAT(order, ElementsAre(root, i[0], i[1], e[2], e[3]));
 }
 
@@ -236,11 +221,10 @@
     std::vector<const Expression*> i = {IndexAccessor(e[0], e[1]), IndexAccessor(e[2], e[3])};
     auto* root = IndexAccessor(i[0], i[1]);
     std::vector<const Expression*> order;
-    TraverseExpressions<TraverseOrder::LeftToRight>(
-        root, Diagnostics(), [&](const Expression* expr) {
-            order.push_back(expr);
-            return expr == i[0] ? TraverseAction::Stop : TraverseAction::Descend;
-        });
+    TraverseExpressions<TraverseOrder::LeftToRight>(root, [&](const Expression* expr) {
+        order.push_back(expr);
+        return expr == i[0] ? TraverseAction::Stop : TraverseAction::Descend;
+    });
     EXPECT_THAT(order, ElementsAre(root, i[0]));
 }
 
diff --git a/src/tint/lang/wgsl/ast/type_decl.cc b/src/tint/lang/wgsl/ast/type_decl.cc
index 0581f85..ed4d6b1 100644
--- a/src/tint/lang/wgsl/ast/type_decl.cc
+++ b/src/tint/lang/wgsl/ast/type_decl.cc
@@ -22,9 +22,9 @@
 
 TypeDecl::TypeDecl(GenerationID pid, NodeID nid, const Source& src, const Identifier* n)
     : Base(pid, nid, src), name(n) {
-    TINT_ASSERT(AST, name);
+    TINT_ASSERT(name);
     if (name) {
-        TINT_ASSERT(AST, !name->Is<TemplatedIdentifier>());
+        TINT_ASSERT(!name->Is<TemplatedIdentifier>());
     }
 }
 
diff --git a/src/tint/lang/wgsl/ast/unary_op_expression.cc b/src/tint/lang/wgsl/ast/unary_op_expression.cc
index 9defa6b..6ed63c0 100644
--- a/src/tint/lang/wgsl/ast/unary_op_expression.cc
+++ b/src/tint/lang/wgsl/ast/unary_op_expression.cc
@@ -26,8 +26,8 @@
                                      UnaryOp o,
                                      const Expression* e)
     : Base(pid, nid, src), op(o), expr(e) {
-    TINT_ASSERT(AST, expr);
-    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(AST, expr, generation_id);
+    TINT_ASSERT(expr);
+    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(expr, generation_id);
 }
 
 UnaryOpExpression::~UnaryOpExpression() = default;
diff --git a/src/tint/lang/wgsl/ast/variable.cc b/src/tint/lang/wgsl/ast/variable.cc
index a2cfc5e..72395f7 100644
--- a/src/tint/lang/wgsl/ast/variable.cc
+++ b/src/tint/lang/wgsl/ast/variable.cc
@@ -29,11 +29,11 @@
                    const Expression* init,
                    VectorRef<const Attribute*> attrs)
     : Base(pid, nid, src), name(n), type(ty), initializer(init), attributes(std::move(attrs)) {
-    TINT_ASSERT(AST, name);
+    TINT_ASSERT(name);
     if (name) {
-        TINT_ASSERT(AST, !name->Is<TemplatedIdentifier>());
+        TINT_ASSERT(!name->Is<TemplatedIdentifier>());
     }
-    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(AST, initializer, generation_id);
+    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(initializer, generation_id);
 }
 
 Variable::~Variable() = default;
diff --git a/src/tint/lang/wgsl/ast/variable_decl_statement.cc b/src/tint/lang/wgsl/ast/variable_decl_statement.cc
index 1f830e3..b9717a9 100644
--- a/src/tint/lang/wgsl/ast/variable_decl_statement.cc
+++ b/src/tint/lang/wgsl/ast/variable_decl_statement.cc
@@ -25,8 +25,8 @@
                                              const Source& src,
                                              const Variable* var)
     : Base(pid, nid, src), variable(var) {
-    TINT_ASSERT(AST, variable);
-    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(AST, variable, generation_id);
+    TINT_ASSERT(variable);
+    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(variable, generation_id);
 }
 
 VariableDeclStatement::~VariableDeclStatement() = default;
diff --git a/src/tint/lang/wgsl/ast/while_statement.cc b/src/tint/lang/wgsl/ast/while_statement.cc
index 0019916..3b29852 100644
--- a/src/tint/lang/wgsl/ast/while_statement.cc
+++ b/src/tint/lang/wgsl/ast/while_statement.cc
@@ -29,14 +29,14 @@
                                const BlockStatement* b,
                                VectorRef<const ast::Attribute*> attrs)
     : Base(pid, nid, src), condition(cond), body(b), attributes(std::move(attrs)) {
-    TINT_ASSERT(AST, cond);
-    TINT_ASSERT(AST, body);
+    TINT_ASSERT(cond);
+    TINT_ASSERT(body);
 
-    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(AST, condition, generation_id);
-    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(AST, body, generation_id);
+    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(condition, generation_id);
+    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(body, generation_id);
     for (auto* attr : attributes) {
-        TINT_ASSERT(AST, attr);
-        TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(AST, attr, generation_id);
+        TINT_ASSERT(attr);
+        TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(attr, generation_id);
     }
 }
 
diff --git a/src/tint/lang/wgsl/helpers/append_vector.cc b/src/tint/lang/wgsl/helpers/append_vector.cc
index 221001f..24be535 100644
--- a/src/tint/lang/wgsl/helpers/append_vector.cc
+++ b/src/tint/lang/wgsl/helpers/append_vector.cc
@@ -58,8 +58,7 @@
     } else if (ty->Is<type::Bool>()) {
         expr = b.Expr(false);
     } else {
-        TINT_UNREACHABLE(Writer, b.Diagnostics())
-            << "unsupported vector element type: " << ty->TypeInfo().name;
+        TINT_UNREACHABLE() << "unsupported vector element type: " << ty->TypeInfo().name;
         return nullptr;
     }
     auto* sem = b.create<sem::ValueExpression>(expr, ty, sem::EvaluationStage::kRuntime, stmt,
@@ -94,8 +93,8 @@
         [&](const type::F32*) { return b->ty.f32(); },
         [&](const type::Bool*) { return b->ty.bool_(); },
         [&](Default) {
-            TINT_UNREACHABLE(Writer, b->Diagnostics())
-                << "unsupported vector element type: " << packed_el_sem_ty->TypeInfo().name;
+            TINT_UNREACHABLE() << "unsupported vector element type: "
+                               << packed_el_sem_ty->TypeInfo().name;
             return ast::Type{};
         });
 
diff --git a/src/tint/lang/wgsl/inspector/inspector.cc b/src/tint/lang/wgsl/inspector/inspector.cc
index 6a77a16..f4b0317 100644
--- a/src/tint/lang/wgsl/inspector/inspector.cc
+++ b/src/tint/lang/wgsl/inspector/inspector.cc
@@ -65,7 +65,7 @@
 
 void AppendResourceBindings(std::vector<ResourceBinding>* dest,
                             const std::vector<ResourceBinding>& orig) {
-    TINT_ASSERT(Inspector, dest);
+    TINT_ASSERT(dest);
     if (!dest) {
         return;
     }
@@ -77,7 +77,7 @@
 std::tuple<ComponentType, CompositionType> CalculateComponentAndComposition(
     const type::Type* type) {
     // entry point in/out variables must of numeric scalar or vector types.
-    TINT_ASSERT(Inspector, type->is_numeric_scalar_or_vector());
+    TINT_ASSERT(type->is_numeric_scalar_or_vector());
 
     ComponentType componentType = Switch(
         type->DeepestElement(),  //
@@ -86,8 +86,7 @@
         [&](const type::I32*) { return ComponentType::kI32; },
         [&](const type::U32*) { return ComponentType::kU32; },
         [&](Default) {
-            tint::diag::List diagnostics;
-            TINT_UNREACHABLE(Inspector, diagnostics) << "unhandled component type";
+            TINT_UNREACHABLE() << "unhandled component type";
             return ComponentType::kUnknown;
         });
 
@@ -107,8 +106,7 @@
                 break;
             }
             default: {
-                tint::diag::List diagnostics;
-                TINT_UNREACHABLE(Inspector, diagnostics) << "unhandled composition type";
+                TINT_UNREACHABLE() << "unhandled composition type";
                 compositionType = CompositionType::kUnknown;
                 break;
             }
@@ -128,8 +126,8 @@
 
 EntryPoint Inspector::GetEntryPoint(const tint::ast::Function* func) {
     EntryPoint entry_point;
-    TINT_ASSERT(Inspector, func != nullptr);
-    TINT_ASSERT(Inspector, func->IsEntryPoint());
+    TINT_ASSERT(func != nullptr);
+    TINT_ASSERT(func->IsEntryPoint());
 
     auto* sem = program_->Sem().Get(func);
 
@@ -156,8 +154,8 @@
             break;
         }
         default: {
-            TINT_UNREACHABLE(Inspector, diagnostics_)
-                << "invalid pipeline stage for entry point '" << entry_point.name << "'";
+            TINT_UNREACHABLE() << "invalid pipeline stage for entry point '" << entry_point.name
+                               << "'";
             break;
         }
     }
@@ -200,7 +198,7 @@
             override.name = name;
             override.id = global->OverrideId();
             auto* type = var->Type();
-            TINT_ASSERT(Inspector, type->Is<type::Scalar>());
+            TINT_ASSERT(type->Is<type::Scalar>());
             if (type->is_bool_scalar_or_vector()) {
                 override.type = Override::Type::kBool;
             } else if (type->is_float_scalar()) {
@@ -214,7 +212,7 @@
             } else if (type->is_unsigned_integer_scalar()) {
                 override.type = Override::Type::kUint32;
             } else {
-                TINT_UNREACHABLE(Inspector, diagnostics_);
+                TINT_UNREACHABLE();
             }
 
             override.is_initialized = global->Declaration()->initializer;
@@ -632,7 +630,7 @@
     std::tie(stage_variable.component_type, stage_variable.composition_type) =
         CalculateComponentAndComposition(type);
 
-    TINT_ASSERT(Inspector, location.has_value());
+    TINT_ASSERT(location.has_value());
     stage_variable.has_location_attribute = true;
     stage_variable.location_attribute = location.value();
 
@@ -913,8 +911,7 @@
 template <size_t N, typename F>
 void Inspector::GetOriginatingResources(std::array<const ast::Expression*, N> exprs, F&& callback) {
     if (TINT_UNLIKELY(!program_->IsValid())) {
-        TINT_ICE(Inspector, diagnostics_)
-            << "attempting to get originating resources in invalid program";
+        TINT_ICE() << "attempting to get originating resources in invalid program";
         return;
     }
 
@@ -940,9 +937,8 @@
             }
             parameters[i] = param;
         } else {
-            TINT_ICE(Inspector, diagnostics_)
-                << "cannot resolve originating resource with expression type "
-                << exprs[i]->TypeInfo().name;
+            TINT_ICE() << "cannot resolve originating resource with expression type "
+                       << exprs[i]->TypeInfo().name;
             return;
         }
     }
diff --git a/src/tint/lang/wgsl/program/program.cc b/src/tint/lang/wgsl/program/program.cc
index 0e8e619..45900e5 100644
--- a/src/tint/lang/wgsl/program/program.cc
+++ b/src/tint/lang/wgsl/program/program.cc
@@ -132,7 +132,7 @@
 }
 
 void Program::AssertNotMoved() const {
-    TINT_ASSERT(Program, !moved_);
+    TINT_ASSERT(!moved_);
 }
 
 }  // namespace tint
diff --git a/src/tint/lang/wgsl/program/program_builder.cc b/src/tint/lang/wgsl/program/program_builder.cc
index 9059f34..06cc052 100644
--- a/src/tint/lang/wgsl/program/program_builder.cc
+++ b/src/tint/lang/wgsl/program/program_builder.cc
@@ -20,7 +20,7 @@
 #include "src/tint/lang/wgsl/sem/type_expression.h"
 #include "src/tint/lang/wgsl/sem/value_expression.h"
 #include "src/tint/lang/wgsl/sem/variable.h"
-#include "src/tint/utils/debug/debug.h"
+#include "src/tint/utils/ice/ice.h"
 #include "src/tint/utils/macros/compiler.h"
 #include "src/tint/utils/rtti/switch.h"
 
@@ -92,8 +92,7 @@
 
 void ProgramBuilder::AssertNotMoved() const {
     if (TINT_UNLIKELY(moved_)) {
-        TINT_ICE(ProgramBuilder, const_cast<ProgramBuilder*>(this)->diagnostics_)
-            << "Attempting to use ProgramBuilder after it has been moved";
+        TINT_ICE() << "Attempting to use ProgramBuilder after it has been moved";
     }
 }
 
diff --git a/src/tint/lang/wgsl/program/program_builder.h b/src/tint/lang/wgsl/program/program_builder.h
index fde203e..f2f87d4 100644
--- a/src/tint/lang/wgsl/program/program_builder.h
+++ b/src/tint/lang/wgsl/program/program_builder.h
@@ -615,7 +615,7 @@
                 case 4:
                     return vec4(source, type);
             }
-            TINT_ICE(ProgramBuilder, builder->Diagnostics()) << "invalid vector width " << n;
+            TINT_ICE() << "invalid vector width " << n;
             return ast::Type{};
         }
 
@@ -716,7 +716,7 @@
                 case 4:
                     return vec4<T>(source);
             }
-            TINT_ICE(ProgramBuilder, builder->Diagnostics()) << "invalid vector width " << n;
+            TINT_ICE() << "invalid vector width " << n;
             return ast::Type{};
         }
 
@@ -756,8 +756,7 @@
                 auto i = (columns - 2) * 3 + (rows - 2);
                 return (*this)(source, names[i], type);
             }
-            TINT_ICE(ProgramBuilder, builder->Diagnostics())
-                << "invalid matrix dimensions " << columns << "x" << rows;
+            TINT_ICE() << "invalid matrix dimensions " << columns << "x" << rows;
             return ast::Type{};
         }
 
@@ -976,8 +975,7 @@
                 case 8:
                     return mat4x4<T>(source);
                 default:
-                    TINT_ICE(ProgramBuilder, builder->Diagnostics())
-                        << "invalid matrix dimensions " << columns << "x" << rows;
+                    TINT_ICE() << "invalid matrix dimensions " << columns << "x" << rows;
                     return ast::Type{};
             }
         }
@@ -1235,7 +1233,7 @@
                 case type::SamplerKind::kComparisonSampler:
                     return (*this)(source, "sampler_comparison");
             }
-            TINT_ICE(ProgramBuilder, builder->Diagnostics()) << "invalid sampler kind " << kind;
+            TINT_ICE() << "invalid sampler kind " << kind;
             return ast::Type{};
         }
 
@@ -1261,8 +1259,7 @@
                 default:
                     break;
             }
-            TINT_ICE(ProgramBuilder, builder->Diagnostics())
-                << "invalid depth_texture dimensions: " << dims;
+            TINT_ICE() << "invalid depth_texture dimensions: " << dims;
             return ast::Type{};
         }
 
@@ -1280,8 +1277,7 @@
             if (dims == type::TextureDimension::k2d) {
                 return (*this)(source, "texture_depth_multisampled_2d");
             }
-            TINT_ICE(ProgramBuilder, builder->Diagnostics())
-                << "invalid depth_multisampled_texture dimensions: " << dims;
+            TINT_ICE() << "invalid depth_multisampled_texture dimensions: " << dims;
             return ast::Type{};
         }
 
@@ -1315,8 +1311,7 @@
                 default:
                     break;
             }
-            TINT_ICE(ProgramBuilder, builder->Diagnostics())
-                << "invalid sampled_texture dimensions: " << dims;
+            TINT_ICE() << "invalid sampled_texture dimensions: " << dims;
             return ast::Type{};
         }
 
@@ -1337,8 +1332,7 @@
             if (dims == type::TextureDimension::k2d) {
                 return (*this)(source, "texture_multisampled_2d", subtype);
             }
-            TINT_ICE(ProgramBuilder, builder->Diagnostics())
-                << "invalid multisampled_texture dimensions: " << dims;
+            TINT_ICE() << "invalid multisampled_texture dimensions: " << dims;
             return ast::Type{};
         }
 
@@ -1373,8 +1367,7 @@
                 default:
                     break;
             }
-            TINT_ICE(ProgramBuilder, builder->Diagnostics())
-                << "invalid storage_texture  dimensions: " << dims;
+            TINT_ICE() << "invalid storage_texture  dimensions: " << dims;
             return ast::Type{};
         }
 
diff --git a/src/tint/lang/wgsl/reader/parser/classify_template_args.cc b/src/tint/lang/wgsl/reader/parser/classify_template_args.cc
index 2cf8b9f..62af8e9 100644
--- a/src/tint/lang/wgsl/reader/parser/classify_template_args.cc
+++ b/src/tint/lang/wgsl/reader/parser/classify_template_args.cc
@@ -17,7 +17,7 @@
 #include <vector>
 
 #include "src/tint/utils/containers/vector.h"
-#include "src/tint/utils/debug/debug.h"
+#include "src/tint/utils/ice/ice.h"
 
 namespace tint::wgsl::reader {
 
@@ -31,17 +31,17 @@
     Token* token = &tokens[idx];
     switch (token->type()) {
         case Token::Type::kShiftRight:  //  '>>'
-            TINT_ASSERT(Reader, token[1].type() == Token::Type::kPlaceholder);
+            TINT_ASSERT(token[1].type() == Token::Type::kPlaceholder);
             token[0].SetType(Token::Type::kGreaterThan);
             token[1].SetType(Token::Type::kGreaterThan);
             break;
         case Token::Type::kGreaterThanEqual:  //  '>='
-            TINT_ASSERT(Reader, token[1].type() == Token::Type::kPlaceholder);
+            TINT_ASSERT(token[1].type() == Token::Type::kPlaceholder);
             token[0].SetType(Token::Type::kGreaterThan);
             token[1].SetType(Token::Type::kEqual);
             break;
         case Token::Type::kShiftRightEqual:  // '>>='
-            TINT_ASSERT(Reader, token[1].type() == Token::Type::kPlaceholder);
+            TINT_ASSERT(token[1].type() == Token::Type::kPlaceholder);
             token[0].SetType(Token::Type::kGreaterThan);
             token[1].SetType(Token::Type::kGreaterThanEqual);
             break;
diff --git a/src/tint/lang/wgsl/reader/parser/lexer.cc b/src/tint/lang/wgsl/reader/parser/lexer.cc
index 132925b..673d83d 100644
--- a/src/tint/lang/wgsl/reader/parser/lexer.cc
+++ b/src/tint/lang/wgsl/reader/parser/lexer.cc
@@ -26,7 +26,7 @@
 #include <utility>
 
 #include "src/tint/lang/core/builtin/number.h"
-#include "src/tint/utils/debug/debug.h"
+#include "src/tint/utils/ice/ice.h"
 #include "src/tint/utils/text/parse_num.h"
 #include "src/tint/utils/text/unicode.h"
 
@@ -637,7 +637,7 @@
     // Note: it's not enough to check mantissa == 0 as we drop the initial bit,
     // whether it's in the integer part or the fractional part.
     const bool is_zero = !seen_prior_one_bits;
-    TINT_ASSERT(Reader, !is_zero || mantissa == 0);
+    TINT_ASSERT(!is_zero || mantissa == 0);
 
     // Parse the optional exponent.
     // ((p|P)(\+|-)?[0-9]+)?
@@ -800,10 +800,10 @@
             // 2^-148 > v >= 2^-149, binary32 s_00000000_00000000000000000000001, 0 arbitrary bit.
 
             // signed_exponent must be in range -149 + 1023 = 874 to -127 + 1023 = 896, inclusive
-            TINT_ASSERT(Reader, (874 <= signed_exponent) && (signed_exponent <= 896));
+            TINT_ASSERT((874 <= signed_exponent) && (signed_exponent <= 896));
             int unbiased_exponent =
                 static_cast<int>(signed_exponent) - static_cast<int>(kExponentBias);
-            TINT_ASSERT(Reader, (-149 <= unbiased_exponent) && (unbiased_exponent <= -127));
+            TINT_ASSERT((-149 <= unbiased_exponent) && (unbiased_exponent <= -127));
             valid_mantissa_bits = unbiased_exponent + 149;  // 0 for -149, and 22 for -127
         } else if (abs_result_f64 != 0.0) {
             // The result is smaller than the smallest subnormal f32 value, but not equal to zero.
@@ -812,7 +812,7 @@
                          "value cannot be exactly represented as 'f32'"};
         }
         // Check the low 52-valid_mantissa_bits mantissa bits must be 0.
-        TINT_ASSERT(Reader, (0 <= valid_mantissa_bits) && (valid_mantissa_bits <= 23));
+        TINT_ASSERT((0 <= valid_mantissa_bits) && (valid_mantissa_bits <= 23));
         if (result_u64 & ((uint64_t(1) << (52 - valid_mantissa_bits)) - 1)) {
             return Token{Token::Type::kError, source,
                          "value cannot be exactly represented as 'f32'"};
@@ -853,10 +853,10 @@
             // 2^-23 > v >= 2^-24, binary16 s_00000_0000000001, 0 arbitrary bits.
 
             // signed_exponent must be in range -24 + 1023 = 999 to -15 + 1023 = 1008, inclusive
-            TINT_ASSERT(Reader, (999 <= signed_exponent) && (signed_exponent <= 1008));
+            TINT_ASSERT((999 <= signed_exponent) && (signed_exponent <= 1008));
             int unbiased_exponent =
                 static_cast<int>(signed_exponent) - static_cast<int>(kExponentBias);
-            TINT_ASSERT(Reader, (-24 <= unbiased_exponent) && (unbiased_exponent <= -15));
+            TINT_ASSERT((-24 <= unbiased_exponent) && (unbiased_exponent <= -15));
             valid_mantissa_bits = unbiased_exponent + 24;  // 0 for -24, and 9 for -15
         } else if (abs_result_f64 != 0.0) {
             // The result is smaller than the smallest subnormal f16 value, but not equal to zero.
@@ -865,7 +865,7 @@
                          "value cannot be exactly represented as 'f16'"};
         }
         // Check the low 52-valid_mantissa_bits mantissa bits must be 0.
-        TINT_ASSERT(Reader, (0 <= valid_mantissa_bits) && (valid_mantissa_bits <= 10));
+        TINT_ASSERT((0 <= valid_mantissa_bits) && (valid_mantissa_bits <= 10));
         if (result_u64 & ((uint64_t(1) << (52 - valid_mantissa_bits)) - 1)) {
             return Token{Token::Type::kError, source,
                          "value cannot be exactly represented as 'f16'"};
diff --git a/src/tint/lang/wgsl/reader/parser/parser.cc b/src/tint/lang/wgsl/reader/parser/parser.cc
index ea686d2..67d027d 100644
--- a/src/tint/lang/wgsl/reader/parser/parser.cc
+++ b/src/tint/lang/wgsl/reader/parser/parser.cc
@@ -290,15 +290,13 @@
 
 void Parser::split_token(Token::Type lhs, Token::Type rhs) {
     if (TINT_UNLIKELY(next_token_idx_ == 0)) {
-        TINT_ICE(Reader, builder_.Diagnostics())
-            << "attempt to update placeholder at beginning of tokens";
+        TINT_ICE() << "attempt to update placeholder at beginning of tokens";
     }
     if (TINT_UNLIKELY(next_token_idx_ >= tokens_.size())) {
-        TINT_ICE(Reader, builder_.Diagnostics())
-            << "attempt to update placeholder past end of tokens";
+        TINT_ICE() << "attempt to update placeholder past end of tokens";
     }
     if (TINT_UNLIKELY(!tokens_[next_token_idx_].IsPlaceholder())) {
-        TINT_ICE(Reader, builder_.Diagnostics()) << "attempt to update non-placeholder token";
+        TINT_ICE() << "attempt to update non-placeholder token";
     }
     tokens_[next_token_idx_ - 1].SetType(lhs);
     tokens_[next_token_idx_].SetType(rhs);
@@ -3389,7 +3387,7 @@
     --parse_depth_;
 
     if (TINT_UNLIKELY(sync_tokens_.back() != tok)) {
-        TINT_ICE(Reader, builder_.Diagnostics()) << "sync_tokens is out of sync";
+        TINT_ICE() << "sync_tokens is out of sync";
     }
     sync_tokens_.pop_back();
 
diff --git a/src/tint/lang/wgsl/reader/parser/parser.h b/src/tint/lang/wgsl/reader/parser/parser.h
index 9adc95c..67d676d 100644
--- a/src/tint/lang/wgsl/reader/parser/parser.h
+++ b/src/tint/lang/wgsl/reader/parser/parser.h
@@ -26,6 +26,7 @@
 #include "src/tint/lang/wgsl/program/program_builder.h"
 #include "src/tint/lang/wgsl/reader/parser/detail.h"
 #include "src/tint/lang/wgsl/reader/parser/token.h"
+#include "src/tint/utils/diagnostic/formatter.h"
 
 namespace tint::ast {
 class BreakStatement;
@@ -122,7 +123,7 @@
         /// return type will always be a pointer to a non-pointer type. #errored
         /// must be false to call.
         inline typename detail::OperatorArrow<T>::type operator->() {
-            TINT_ASSERT(Reader, !errored);
+            TINT_ASSERT(!errored);
             return detail::OperatorArrow<T>::ptr(value);
         }
 
@@ -184,7 +185,7 @@
         /// return type will always be a pointer to a non-pointer type. #errored
         /// must be false to call.
         inline typename detail::OperatorArrow<T>::type operator->() {
-            TINT_ASSERT(Reader, !errored);
+            TINT_ASSERT(!errored);
             return detail::OperatorArrow<T>::ptr(value);
         }
 
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 e0c3c0f..1d64f4b 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
@@ -192,8 +192,8 @@
     bool NeedTerminator() { return current_block_ && !current_block_->HasTerminator(); }
 
     void SetTerminator(ir::Terminator* terminator) {
-        TINT_ASSERT(IR, current_block_);
-        TINT_ASSERT(IR, !current_block_->HasTerminator());
+        TINT_ASSERT(current_block_);
+        TINT_ASSERT(!current_block_->HasTerminator());
 
         current_block_->Append(terminator);
         current_block_ = nullptr;
@@ -276,7 +276,7 @@
 
     void EmitFunction(const ast::Function* ast_func) {
         // The flow stack should have been emptied when the previous function finished building.
-        TINT_ASSERT(IR, control_stack_.IsEmpty());
+        TINT_ASSERT(control_stack_.IsEmpty());
 
         const auto* sem = program_->Sem().Get(ast_func);
 
@@ -303,7 +303,7 @@
                     break;
                 }
                 default: {
-                    TINT_ICE(IR, diagnostics_) << "Invalid pipeline stage";
+                    TINT_ICE() << "Invalid pipeline stage";
                     return;
                 }
             }
@@ -337,13 +337,12 @@
                                         ir::Function::ReturnBuiltin::kSampleMask);
                                     break;
                                 default:
-                                    TINT_ICE(IR, diagnostics_)
-                                        << "Unknown builtin value in return attributes "
-                                        << ident_sem->Value();
+                                    TINT_ICE() << "Unknown builtin value in return attributes "
+                                               << ident_sem->Value();
                                     return;
                             }
                         } else {
-                            TINT_ICE(IR, diagnostics_) << "Builtin attribute sem invalid";
+                            TINT_ICE() << "Builtin attribute sem invalid";
                             return;
                         }
                     });
@@ -415,13 +414,12 @@
                                     param->SetBuiltin(ir::FunctionParam::Builtin::kSampleMask);
                                     break;
                                 default:
-                                    TINT_ICE(IR, diagnostics_)
-                                        << "Unknown builtin value in parameter attributes "
-                                        << ident_sem->Value();
+                                    TINT_ICE() << "Unknown builtin value in parameter attributes "
+                                               << ident_sem->Value();
                                     return;
                             }
                         } else {
-                            TINT_ICE(IR, diagnostics_) << "Builtin attribute sem invalid";
+                            TINT_ICE() << "Builtin attribute sem invalid";
                             return;
                         }
                     });
@@ -452,7 +450,7 @@
             }
         }
 
-        TINT_ASSERT(IR, control_stack_.IsEmpty());
+        TINT_ASSERT(control_stack_.IsEmpty());
         current_block_ = nullptr;
         current_function_ = nullptr;
     }
@@ -781,25 +779,25 @@
 
     void EmitBreak(const ast::BreakStatement*) {
         auto* current_control = FindEnclosingControl(ControlFlags::kNone);
-        TINT_ASSERT(IR, current_control);
+        TINT_ASSERT(current_control);
 
         if (auto* c = current_control->As<ir::Loop>()) {
             SetTerminator(builder_.ExitLoop(c));
         } else if (auto* s = current_control->As<ir::Switch>()) {
             SetTerminator(builder_.ExitSwitch(s));
         } else {
-            TINT_UNREACHABLE(IR, diagnostics_);
+            TINT_UNREACHABLE();
         }
     }
 
     void EmitContinue(const ast::ContinueStatement*) {
         auto* current_control = FindEnclosingControl(ControlFlags::kExcludeSwitch);
-        TINT_ASSERT(IR, current_control);
+        TINT_ASSERT(current_control);
 
         if (auto* c = current_control->As<ir::Loop>()) {
             SetTerminator(builder_.Continue(c));
         } else {
-            TINT_UNREACHABLE(IR, diagnostics_);
+            TINT_UNREACHABLE();
         }
     }
 
@@ -881,7 +879,7 @@
                 if (auto** val = std::get_if<ir::Value*>(&res)) {
                     return *val;
                 }
-                TINT_ICE(IR, impl.diagnostics_) << "expression did not resolve to a value";
+                TINT_ICE() << "expression did not resolve to a value";
                 return nullptr;
             }
 
@@ -913,7 +911,7 @@
 
                 auto* obj = GetValue(expr->object);
                 if (!obj) {
-                    TINT_ASSERT(IR, false && "no object result");
+                    TINT_UNREACHABLE() << "no object result";
                     return;
                 }
 
@@ -933,7 +931,7 @@
                             if (auto* cv = v->Clone(impl.clone_ctx_)) {
                                 return impl.builder_.Constant(cv);
                             }
-                            TINT_ASSERT(IR, false && "constant clone failed");
+                            TINT_UNREACHABLE() << "constant clone failed";
                             return nullptr;
                         }
                         return GetValue(idx->Index()->Declaration());
@@ -954,8 +952,7 @@
                         return nullptr;
                     },
                     [&](Default) {
-                        TINT_ICE(Writer, impl.diagnostics_)
-                            << "invalid accessor: " + std::string(sem->TypeInfo().name);
+                        TINT_ICE() << "invalid accessor: " + std::string(sem->TypeInfo().name);
                         return nullptr;
                     });
 
@@ -1089,7 +1086,7 @@
                 } else if (sem->Target()->Is<sem::ValueConversion>()) {
                     inst = impl.builder_.Convert(ty, args[0]);
                 } else if (expr->target->identifier->Is<ast::TemplatedIdentifier>()) {
-                    TINT_UNIMPLEMENTED(IR, impl.diagnostics_) << "missing templated ident support";
+                    TINT_UNIMPLEMENTED() << "missing templated ident support";
                     return;
                 } else {
                     // Not a builtin and not a templated call, so this is a user function.
@@ -1200,7 +1197,7 @@
                 auto res = GetValue(b);
                 auto* src = res->As<ir::InstructionResult>()->Source();
                 auto* if_ = src->As<ir::If>();
-                TINT_ASSERT_OR_RETURN(IR, if_);
+                TINT_ASSERT_OR_RETURN(if_);
                 auto rhs = GetValue(b->rhs);
                 if (!rhs) {
                     return;
@@ -1271,7 +1268,7 @@
         if (auto** val = std::get_if<ir::Value*>(&res)) {
             return *val;
         }
-        TINT_ICE(IR, diagnostics_) << "expression did not resolve to a value";
+        TINT_ICE() << "expression did not resolve to a value";
         return nullptr;
     }
 
@@ -1388,13 +1385,13 @@
                 return builder_.Modulo(ty, lhs, rhs);
             case ast::BinaryOp::kLogicalAnd:
             case ast::BinaryOp::kLogicalOr:
-                TINT_ICE(IR, diagnostics_) << "short circuit op should have already been handled";
+                TINT_ICE() << "short circuit op should have already been handled";
                 return nullptr;
             case ast::BinaryOp::kNone:
-                TINT_ICE(IR, diagnostics_) << "missing binary operand type";
+                TINT_ICE() << "missing binary operand type";
                 return nullptr;
         }
-        TINT_UNREACHABLE(IR, diagnostics_);
+        TINT_UNREACHABLE();
         return nullptr;
     }
 };
diff --git a/src/tint/lang/wgsl/resolver/const_eval.cc b/src/tint/lang/wgsl/resolver/const_eval.cc
index aa5c67c..e33c37b 100644
--- a/src/tint/lang/wgsl/resolver/const_eval.cc
+++ b/src/tint/lang/wgsl/resolver/const_eval.cc
@@ -320,7 +320,7 @@
             return ctx.builder.constants.Get<constant::Scalar<TO>>(target_ty,
                                                                    static_cast<TO>(scalar->value));
         }
-        TINT_UNREACHABLE(Resolver, ctx.builder.Diagnostics()) << "Expression is not constant";
+        TINT_UNREACHABLE() << "Expression is not constant";
         return nullptr;
     });
     TINT_END_DISABLE_WARNING(UNREACHABLE_CODE);
@@ -355,14 +355,14 @@
         auto next = pending.Pop();
 
         if (auto* build = std::get_if<ActionBuildSplat>(&next)) {
-            TINT_ASSERT(Resolver, value_stack.Length() >= 1);
+            TINT_ASSERT(value_stack.Length() >= 1);
             auto* el = value_stack.Pop();
             value_stack.Push(ctx.builder.constants.Splat(build->type, el, build->count));
             continue;
         }
 
         if (auto* build = std::get_if<ActionBuildComposite>(&next)) {
-            TINT_ASSERT(Resolver, value_stack.Length() >= build->count);
+            TINT_ASSERT(value_stack.Length() >= build->count);
             // Take build->count elements off the top of value_stack
             // Note: The values are ordered with the first composite value at the top of the stack.
             Vector<const constant::Value*, 32> elements;
@@ -421,7 +421,7 @@
                     // default materialization type.
                     for (size_t i = 1; i < members.Length(); i++) {
                         if (members[i]->Type() != target_el_ty) {
-                            TINT_ICE(Resolver, ctx.builder.Diagnostics())
+                            TINT_ICE()
                                 << "inconsistent target struct member types for SplatConvert";
                             return false;
                         }
@@ -443,7 +443,7 @@
 
                 if (auto* str = convert->target_ty->As<type::Struct>()) {
                     if (TINT_UNLIKELY(str->Members().Length() != el_count)) {
-                        TINT_ICE(Resolver, ctx.builder.Diagnostics())
+                        TINT_ICE()
                             << "const-eval conversion of structure has mismatched element counts";
                         return false;
                     }
@@ -468,7 +468,7 @@
         }
     }
 
-    TINT_ASSERT(Resolver, value_stack.Length() == 1);
+    TINT_ASSERT(value_stack.Length() == 1);
     return value_stack.Pop();
 }
 
@@ -567,7 +567,7 @@
 template <typename T>
 ConstEval::Result ConstEval::CreateScalar(const Source& source, const type::Type* t, T v) {
     static_assert(IsNumber<T> || std::is_same_v<T, bool>, "T must be a Number or bool");
-    TINT_ASSERT(Resolver, t->Is<type::Scalar>());
+    TINT_ASSERT(t->Is<type::Scalar>());
 
     if constexpr (IsFloatingPoint<T>) {
         if (!std::isfinite(v.value)) {
@@ -622,7 +622,7 @@
         [&](Default) -> const constant::Value* {
             return ZeroTypeDispatch(type, [&](auto zero) -> const constant::Value* {
                 auto el = CreateScalar(Source{}, type, zero);
-                TINT_ASSERT(Resolver, el);
+                TINT_ASSERT(el);
                 return el.Get();
             });
         });
@@ -1171,7 +1171,7 @@
                                  const constant::Value* v1,
                                  const constant::Value* v2) {
     auto* vec_ty = v1->Type()->As<type::Vector>();
-    TINT_ASSERT(Resolver, vec_ty);
+    TINT_ASSERT(vec_ty);
     auto* elem_ty = vec_ty->type();
     switch (vec_ty->Width()) {
         case 2:
@@ -1190,8 +1190,8 @@
                 v1->Index(0), v1->Index(1), v1->Index(2), v1->Index(3),  //
                 v2->Index(0), v2->Index(1), v2->Index(2), v2->Index(3));
     }
-    TINT_ICE(Resolver, builder.Diagnostics()) << "Expected vector";
-    return tint::Failure;
+    TINT_ICE() << "Expected vector";
+    return Failure;
 }
 
 ConstEval::Result ConstEval::Length(const Source& source,
@@ -1468,14 +1468,14 @@
     auto src_el_ty = src_elements.type;
     auto src_count = src_elements.count;
 
-    TINT_ASSERT(Resolver, dst_count * dst_el_ty->Size() == src_count * src_el_ty->Size());
+    TINT_ASSERT(dst_count * dst_el_ty->Size() == src_count * src_el_ty->Size());
     uint32_t total_bitwidth = dst_count * dst_el_ty->Size();
     // Buffer holding the bits from source value, result value reinterpreted from it.
     Vector<std::byte, 16> buffer;
     buffer.Reserve(total_bitwidth);
 
     // Ensure elements are of 32-bit or 16-bit numerical scalar type.
-    TINT_ASSERT(Resolver, (src_el_ty->IsAnyOf<type::F32, type::I32, type::U32, type::F16>()));
+    TINT_ASSERT((src_el_ty->IsAnyOf<type::F32, type::I32, type::U32, type::F16>()));
     // Pushes bits from source value into the buffer.
     auto push_src_element_bits = [&](const constant::Value* element) {
         auto push_32_bits = [&](uint32_t v) {
@@ -1564,7 +1564,7 @@
             });
     };
 
-    TINT_ASSERT(Resolver, (buffer.Length() == total_bitwidth));
+    TINT_ASSERT((buffer.Length() == total_bitwidth));
     for (size_t i = 0; i < dst_count; i++) {
         if (!push_dst_element(i * dst_el_ty->Size())) {
             return tint::Failure;
@@ -1914,7 +1914,7 @@
                                           const Source& source) {
     // Due to short-circuiting, this function is only called if lhs is true, so we only return the
     // value of the rhs.
-    TINT_ASSERT(Resolver, args[0]->ValueAs<bool>());
+    TINT_ASSERT(args[0]->ValueAs<bool>());
     return CreateScalar(source, ty, args[1]->ValueAs<bool>());
 }
 
@@ -1923,7 +1923,7 @@
                                          const Source& source) {
     // Due to short-circuiting, this function is only called if lhs is false, so we only only return
     // the value of the rhs.
-    TINT_ASSERT(Resolver, !args[0]->ValueAs<bool>());
+    TINT_ASSERT(!args[0]->ValueAs<bool>());
     return CreateScalar(source, ty, args[1]->ValueAs<bool>());
 }
 
@@ -2070,9 +2070,8 @@
     };
 
     if (TINT_UNLIKELY(!args[1]->Type()->DeepestElement()->Is<type::U32>())) {
-        TINT_ICE(Resolver, builder.Diagnostics())
-            << "Element type of rhs of ShiftLeft must be a u32";
-        return tint::Failure;
+        TINT_ICE() << "Element type of rhs of ShiftLeft must be a u32";
+        return Failure;
     }
 
     return TransformElements(builder, ty, transform, args[0], args[1]);
@@ -2138,9 +2137,8 @@
     };
 
     if (TINT_UNLIKELY(!args[1]->Type()->DeepestElement()->Is<type::U32>())) {
-        TINT_ICE(Resolver, builder.Diagnostics())
-            << "Element type of rhs of ShiftLeft must be a u32";
-        return tint::Failure;
+        TINT_ICE() << "Element type of rhs of ShiftLeft must be a u32";
+        return Failure;
     }
 
     return TransformElements(builder, ty, transform, args[0], args[1]);
@@ -2506,8 +2504,8 @@
                                            me(0, 2), me(1, 2), me(2, 2), me(3, 2),  //
                                            me(0, 3), me(1, 3), me(2, 3), me(3, 3));
         }
-        TINT_ICE(Resolver, builder.Diagnostics()) << "Unexpected number of matrix rows";
-        return tint::Failure;
+        TINT_ICE() << "Unexpected number of matrix rows";
+        return Failure;
     };
     auto r = calculate();
     if (!r) {
@@ -2826,10 +2824,9 @@
                 };
             },
             [&](Default) {
-                TINT_ICE(Resolver, builder.Diagnostics())
-                    << "unhandled element type for frexp() const-eval: "
-                    << s->Type()->FriendlyName();
-                return FractExp{tint::Failure, tint::Failure};
+                TINT_ICE() << "unhandled element type for frexp() const-eval: "
+                           << s->Type()->FriendlyName();
+                return FractExp{Failure, Failure};
             });
     };
 
diff --git a/src/tint/lang/wgsl/resolver/const_eval_binary_op_test.cc b/src/tint/lang/wgsl/resolver/const_eval_binary_op_test.cc
index 2bd91fb..881246c 100644
--- a/src/tint/lang/wgsl/resolver/const_eval_binary_op_test.cc
+++ b/src/tint/lang/wgsl/resolver/const_eval_binary_op_test.cc
@@ -2425,8 +2425,6 @@
     auto program = wgsl::reader::Parse(file.get());
 
     if (should_pass) {
-        diag::Formatter::Style style;
-        style.print_newline_at_end = false;
         auto error = program.Diagnostics().str();
 
         EXPECT_TRUE(program.IsValid()) << error;
diff --git a/src/tint/lang/wgsl/resolver/dependency_graph.cc b/src/tint/lang/wgsl/resolver/dependency_graph.cc
index d5ceb40..f6399fd 100644
--- a/src/tint/lang/wgsl/resolver/dependency_graph.cc
+++ b/src/tint/lang/wgsl/resolver/dependency_graph.cc
@@ -124,8 +124,8 @@
 using GlobalMap = Hashmap<Symbol, Global*, 16>;
 
 /// Raises an ICE that a global ast::Node type was not handled by this system.
-void UnhandledNode(diag::List& diagnostics, const ast::Node* node) {
-    TINT_ICE(Resolver, diagnostics) << "unhandled node type: " << node->TypeInfo().name;
+void UnhandledNode(const ast::Node* node) {
+    TINT_ICE() << "unhandled node type: " << node->TypeInfo().name;
 }
 
 /// Raises an error diagnostic with the given message and source.
@@ -194,7 +194,7 @@
                 // Enable directives do not affect the dependency graph.
             },
             [&](const ast::ConstAssert* assertion) { TraverseExpression(assertion->condition); },
-            [&](Default) { UnhandledNode(diagnostics_, global->node); });
+            [&](Default) { UnhandledNode(global->node); });
     }
 
   private:
@@ -318,7 +318,7 @@
             [&](Default) {
                 if (TINT_UNLIKELY((!stmt->IsAnyOf<ast::BreakStatement, ast::ContinueStatement,
                                                   ast::DiscardStatement>()))) {
-                    UnhandledNode(diagnostics_, stmt);
+                    UnhandledNode(stmt);
                 }
             });
     }
@@ -343,7 +343,8 @@
 
         Vector<const ast::Expression*, 8> pending{root_expr};
         while (!pending.IsEmpty()) {
-            ast::TraverseExpressions(pending.Pop(), diagnostics_, [&](const ast::Expression* expr) {
+            auto* next = pending.Pop();
+            bool ok = ast::TraverseExpressions(next, [&](const ast::Expression* expr) {
                 Switch(
                     expr,
                     [&](const ast::IdentifierExpression* e) {
@@ -358,6 +359,10 @@
                     [&](const ast::BitcastExpression* cast) { TraverseExpression(cast->type); });
                 return ast::TraverseAction::Descend;
             });
+            if (!ok) {
+                AddError(diagnostics_, "TraverseExpressions failed", next->source);
+                return;
+            }
         }
     }
 
@@ -434,7 +439,7 @@
             return;
         }
 
-        UnhandledNode(diagnostics_, attr);
+        UnhandledNode(attr);
     }
 
     /// The type of builtin that a symbol could represent.
@@ -636,7 +641,7 @@
             [&](const ast::Enable*) { return Symbol(); },
             [&](const ast::ConstAssert*) { return Symbol(); },
             [&](Default) {
-                UnhandledNode(diagnostics_, node);
+                UnhandledNode(node);
                 return Symbol{};
             });
     }
@@ -660,7 +665,7 @@
             [&](const ast::Variable* v) { return v->Kind(); },        //
             [&](const ast::ConstAssert*) { return "const_assert"; },  //
             [&](Default) {
-                UnhandledNode(diagnostics_, node);
+                UnhandledNode(node);
                 return "<error>";
             });
     }
@@ -779,8 +784,7 @@
 
             if (TINT_UNLIKELY(!stack.IsEmpty())) {
                 // Each stack.push() must have a corresponding stack.pop_back().
-                TINT_ICE(Resolver, diagnostics_)
-                    << "stack not empty after returning from TraverseDependencies()";
+                TINT_ICE() << "stack not empty after returning from TraverseDependencies()";
             }
         }
     }
@@ -793,9 +797,8 @@
         if (TINT_LIKELY(info)) {
             return *info;
         }
-        TINT_ICE(Resolver, diagnostics_)
-            << "failed to find dependency info for edge: '" << NameOf(from->node) << "' -> '"
-            << NameOf(to->node) << "'";
+        TINT_ICE() << "failed to find dependency info for edge: '" << NameOf(from->node) << "' -> '"
+                   << NameOf(to->node) << "'";
         return {};
     }
 
@@ -888,7 +891,7 @@
     return da.Run(module);
 }
 
-std::string ResolvedIdentifier::String(diag::List& diagnostics) const {
+std::string ResolvedIdentifier::String() const {
     if (auto* node = Node()) {
         return Switch(
             node,
@@ -914,8 +917,7 @@
                 return "parameter '" + n->name->symbol.Name() + "'";
             },
             [&](Default) {
-                TINT_UNREACHABLE(Resolver, diagnostics)
-                    << "unhandled ast::Node: " << node->TypeInfo().name;
+                TINT_UNREACHABLE() << "unhandled ast::Node: " << node->TypeInfo().name;
                 return "<unknown>";
             });
     }
@@ -947,7 +949,7 @@
         return "unresolved identifier '" + unresolved->name + "'";
     }
 
-    TINT_UNREACHABLE(Resolver, diagnostics) << "unhandled ResolvedIdentifier";
+    TINT_UNREACHABLE() << "unhandled ResolvedIdentifier";
     return "<unknown>";
 }
 
diff --git a/src/tint/lang/wgsl/resolver/dependency_graph.h b/src/tint/lang/wgsl/resolver/dependency_graph.h
index e555c09..4a14588 100644
--- a/src/tint/lang/wgsl/resolver/dependency_graph.h
+++ b/src/tint/lang/wgsl/resolver/dependency_graph.h
@@ -163,9 +163,8 @@
         return !(*this == other);
     }
 
-    /// @param diagnostics diagnostics used to report ICEs
     /// @return a description of the resolved symbol
-    std::string String(diag::List& diagnostics) const;
+    std::string String() const;
 
   private:
     std::variant<UnresolvedIdentifier,
diff --git a/src/tint/lang/wgsl/resolver/dependency_graph_test.cc b/src/tint/lang/wgsl/resolver/dependency_graph_test.cc
index 2459649..2c49fc6 100644
--- a/src/tint/lang/wgsl/resolver/dependency_graph_test.cc
+++ b/src/tint/lang/wgsl/resolver/dependency_graph_test.cc
@@ -1190,7 +1190,7 @@
 
     auto resolved = Build().resolved_identifiers.Get(ident);
     ASSERT_TRUE(resolved);
-    EXPECT_EQ(resolved->BuiltinFunction(), builtin) << resolved->String(Diagnostics());
+    EXPECT_EQ(resolved->BuiltinFunction(), builtin) << resolved->String();
 }
 
 INSTANTIATE_TEST_SUITE_P(Types,
@@ -1229,8 +1229,7 @@
 
     auto resolved = Build().resolved_identifiers.Get(ident);
     ASSERT_TRUE(resolved);
-    EXPECT_EQ(resolved->BuiltinType(), builtin::ParseBuiltin(name))
-        << resolved->String(Diagnostics());
+    EXPECT_EQ(resolved->BuiltinType(), builtin::ParseBuiltin(name)) << resolved->String();
 }
 
 INSTANTIATE_TEST_SUITE_P(Types,
@@ -1269,7 +1268,7 @@
 
     auto resolved = Build().resolved_identifiers.Get(ident);
     ASSERT_TRUE(resolved);
-    EXPECT_EQ(resolved->Access(), builtin::ParseAccess(name)) << resolved->String(Diagnostics());
+    EXPECT_EQ(resolved->Access(), builtin::ParseAccess(name)) << resolved->String();
 }
 
 INSTANTIATE_TEST_SUITE_P(Types,
@@ -1308,8 +1307,7 @@
 
     auto resolved = Build().resolved_identifiers.Get(ident);
     ASSERT_TRUE(resolved);
-    EXPECT_EQ(resolved->AddressSpace(), builtin::ParseAddressSpace(name))
-        << resolved->String(Diagnostics());
+    EXPECT_EQ(resolved->AddressSpace(), builtin::ParseAddressSpace(name)) << resolved->String();
 }
 
 INSTANTIATE_TEST_SUITE_P(Types,
@@ -1348,8 +1346,7 @@
 
     auto resolved = Build().resolved_identifiers.Get(ident);
     ASSERT_TRUE(resolved);
-    EXPECT_EQ(resolved->BuiltinValue(), builtin::ParseBuiltinValue(name))
-        << resolved->String(Diagnostics());
+    EXPECT_EQ(resolved->BuiltinValue(), builtin::ParseBuiltinValue(name)) << resolved->String();
 }
 
 INSTANTIATE_TEST_SUITE_P(Types,
@@ -1389,7 +1386,7 @@
     auto resolved = Build().resolved_identifiers.Get(ident);
     ASSERT_TRUE(resolved);
     EXPECT_EQ(resolved->InterpolationSampling(), builtin::ParseInterpolationSampling(name))
-        << resolved->String(Diagnostics());
+        << resolved->String();
 }
 
 INSTANTIATE_TEST_SUITE_P(Types,
@@ -1429,7 +1426,7 @@
     auto resolved = Build().resolved_identifiers.Get(ident);
     ASSERT_TRUE(resolved);
     EXPECT_EQ(resolved->InterpolationType(), builtin::ParseInterpolationType(name))
-        << resolved->String(Diagnostics());
+        << resolved->String();
 }
 
 INSTANTIATE_TEST_SUITE_P(
@@ -1471,8 +1468,7 @@
 
     auto resolved = Build().resolved_identifiers.Get(ident);
     ASSERT_TRUE(resolved);
-    EXPECT_EQ(resolved->TexelFormat(), builtin::ParseTexelFormat(name))
-        << resolved->String(Diagnostics());
+    EXPECT_EQ(resolved->TexelFormat(), builtin::ParseTexelFormat(name)) << resolved->String();
 }
 
 INSTANTIATE_TEST_SUITE_P(Types,
@@ -1553,7 +1549,7 @@
 
     auto resolved = Build().resolved_identifiers.Get(ident);
     ASSERT_TRUE(resolved);
-    EXPECT_EQ(resolved->Node(), decl) << resolved->String(Diagnostics());
+    EXPECT_EQ(resolved->Node(), decl) << resolved->String();
 }
 
 TEST_P(ResolverDependencyGraphShadowKindTest, ShadowedByStruct) {
@@ -1570,7 +1566,7 @@
 
     auto resolved = Build().resolved_identifiers.Get(ident);
     ASSERT_TRUE(resolved);
-    EXPECT_EQ(resolved->Node(), decl) << resolved->String(Diagnostics());
+    EXPECT_EQ(resolved->Node(), decl) << resolved->String();
 }
 
 TEST_P(ResolverDependencyGraphShadowKindTest, ShadowedByFunc) {
@@ -1585,7 +1581,7 @@
 
     auto resolved = Build().resolved_identifiers.Get(ident);
     ASSERT_TRUE(resolved);
-    EXPECT_EQ(resolved->Node(), decl) << resolved->String(Diagnostics());
+    EXPECT_EQ(resolved->Node(), decl) << resolved->String();
 }
 
 INSTANTIATE_TEST_SUITE_P(Access,
diff --git a/src/tint/lang/wgsl/resolver/intrinsic_table.cc b/src/tint/lang/wgsl/resolver/intrinsic_table.cc
index c28013a..718b8c5 100644
--- a/src/tint/lang/wgsl/resolver/intrinsic_table.cc
+++ b/src/tint/lang/wgsl/resolver/intrinsic_table.cc
@@ -1429,7 +1429,7 @@
         return_type =
             Match(match.templates, match.overload, indices, earliest_eval_stage).Type(&any);
         if (TINT_UNLIKELY(!return_type)) {
-            TINT_ICE(Resolver, builder.Diagnostics()) << "MatchState.Match() returned null";
+            TINT_ICE() << "MatchState.Match() returned null";
             return {};
         }
     } else {
@@ -1763,7 +1763,7 @@
             ss << std::endl;
         }
     }
-    TINT_ICE(Resolver, builder.Diagnostics()) << ss.str();
+    TINT_ICE() << ss.str();
 }
 
 }  // namespace
diff --git a/src/tint/lang/wgsl/resolver/resolver.cc b/src/tint/lang/wgsl/resolver/resolver.cc
index 4fb716d..6e2ffcc 100644
--- a/src/tint/lang/wgsl/resolver/resolver.cc
+++ b/src/tint/lang/wgsl/resolver/resolver.cc
@@ -136,7 +136,7 @@
     bool result = ResolveInternal();
 
     if (TINT_UNLIKELY(!result && !diagnostics_.contains_errors())) {
-        TINT_ICE(Resolver, diagnostics_) << "resolving failed, but no error was raised";
+        AddICE("resolving failed, but no error was raised", {});
         return false;
     }
 
@@ -179,8 +179,7 @@
                 [&](const ast::Variable* var) { return GlobalVariable(var); },
                 [&](const ast::ConstAssert* ca) { return ConstAssert(ca); },
                 [&](Default) {
-                    TINT_UNREACHABLE(Resolver, diagnostics_)
-                        << "unhandled global declaration: " << decl->TypeInfo().name;
+                    TINT_UNREACHABLE() << "unhandled global declaration: " << decl->TypeInfo().name;
                     return false;
                 })) {
             return false;
@@ -208,10 +207,10 @@
     bool result = true;
     for (auto* node : builder_->ASTNodes().Objects()) {
         if (TINT_UNLIKELY(!marked_[node->node_id.value])) {
-            TINT_ICE(Resolver, diagnostics_)
-                << "AST node '" << node->TypeInfo().name << "' was not reached by the resolver\n"
-                << "At: " << node->source << "\n"
+            StringStream err;
+            err << "AST node '" << node->TypeInfo().name << "' was not reached by the resolver\n"
                 << "Pointer: " << node;
+            AddICE(err.str(), node->source);
             result = false;
         }
     }
@@ -229,9 +228,10 @@
         [&](const ast::Override* override) { return Override(override); },
         [&](const ast::Const* const_) { return Const(const_, is_global); },
         [&](Default) {
-            TINT_ICE(Resolver, diagnostics_)
-                << "Resolver::GlobalVariable() called with a unknown variable type: "
+            StringStream err;
+            err << "Resolver::GlobalVariable() called with a unknown variable type: "
                 << v->TypeInfo().name;
+            AddICE(err.str(), v->source);
             return nullptr;
         });
 }
@@ -876,10 +876,10 @@
     for (auto it : dependencies_.shadows) {
         CastableBase* b = sem_.Get(it.value);
         if (TINT_UNLIKELY(!b)) {
-            TINT_ICE(Resolver, diagnostics_)
-                << "AST node '" << it.value->TypeInfo().name << "' had no semantic info\n"
-                << "At: " << it.value->source << "\n"
+            StringStream err;
+            err << "AST node '" << it.value->TypeInfo().name << "' had no semantic info\n"
                 << "Pointer: " << it.value;
+            AddICE(err.str(), it.value->source);
         }
 
         Switch(
@@ -1145,8 +1145,9 @@
     if (decl->body) {
         Mark(decl->body);
         if (TINT_UNLIKELY(current_compound_statement_)) {
-            TINT_ICE(Resolver, diagnostics_)
-                << "Resolver::Function() called with a current compound statement";
+            StringStream err;
+            err << "Resolver::Function() called with a current compound statement";
+            AddICE(err.str(), decl->body->source);
             return nullptr;
         }
         auto* body = StatementScope(decl->body, builder_->create<sem::FunctionBlockStatement>(func),
@@ -1467,7 +1468,7 @@
     constexpr size_t kMaxExpressionDepth = 512U;
     bool failed = false;
     if (!ast::TraverseExpressions<ast::TraverseOrder::RightToLeft>(
-            root, diagnostics_, [&](const ast::Expression* expr, size_t depth) {
+            root, [&](const ast::Expression* expr, size_t depth) {
                 if (depth > kMaxExpressionDepth) {
                     AddError(
                         "reached max expression depth of " + std::to_string(kMaxExpressionDepth),
@@ -1487,6 +1488,7 @@
                 sorted.Push(expr);
                 return ast::TraverseAction::Descend;
             })) {
+        AddError("TraverseExpressions failed", root->source);
         return nullptr;
     }
 
@@ -1513,8 +1515,9 @@
                                                               /* has_side_effects */ false);
             },
             [&](Default) {
-                TINT_ICE(Resolver, diagnostics_)
-                    << "unhandled expression type: " << expr->TypeInfo().name;
+                StringStream err;
+                err << "unhandled expression type: " << expr->TypeInfo().name;
+                AddICE(err.str(), expr->source);
                 return nullptr;
             });
         if (!sem_expr) {
@@ -1546,11 +1549,12 @@
                     ((*binary)->IsLogicalOr() && lhs_is_true)) {
                     // Mark entire expression tree to not const-evaluate
                     auto r = ast::TraverseExpressions(  //
-                        (*binary)->rhs, diagnostics_, [&](const ast::Expression* e) {
+                        (*binary)->rhs, [&](const ast::Expression* e) {
                             skip_const_eval_.Add(e);
                             return ast::TraverseAction::Descend;
                         });
                     if (!r) {
+                        AddError("TraverseExpressions failed", root->source);
                         return nullptr;
                     }
                 }
@@ -1558,7 +1562,7 @@
         }
     }
 
-    TINT_ICE(Resolver, diagnostics_) << "Expression() did not find root node";
+    AddICE("Expression() did not find root node", root->source);
     return nullptr;
 }
 
@@ -1837,9 +1841,10 @@
     if (!skip_const_eval_.Contains(decl)) {
         auto expr_val = expr->ConstantValue();
         if (TINT_UNLIKELY(!expr_val)) {
-            TINT_ICE(Resolver, diagnostics_)
-                << decl->source << "Materialize(" << decl->TypeInfo().name
+            StringStream err;
+            err << decl->source << "Materialize(" << decl->TypeInfo().name
                 << ") called on expression with no constant value";
+            AddICE(err.str(), expr->Declaration()->source);
             return nullptr;
         }
 
@@ -1850,9 +1855,10 @@
         }
         materialized_val = val.Get();
         if (TINT_UNLIKELY(!materialized_val)) {
-            TINT_ICE(Resolver, diagnostics_)
-                << decl->source << "ConvertValue(" << expr_val->Type()->FriendlyName() << " -> "
+            StringStream err;
+            err << decl->source << "ConvertValue(" << expr_val->Type()->FriendlyName() << " -> "
                 << concrete_ty->FriendlyName() << ") returned invalid value";
+            AddICE(err.str(), expr->Declaration()->source);
             return nullptr;
         }
     }
@@ -2126,7 +2132,7 @@
             [&](const type::Bool*) { return ctor_or_conv(CtorConvIntrinsic::kBool, nullptr); },
             [&](const type::Vector* v) {
                 if (v->Packed()) {
-                    TINT_ASSERT(Resolver, v->Width() == 3u);
+                    TINT_ASSERT(v->Width() == 3u);
                     return ctor_or_conv(CtorConvIntrinsic::kPackedVec3, v->type());
                 }
                 return ctor_or_conv(VectorCtorConvIntrinsic(v->Width()), v->type());
@@ -2225,8 +2231,9 @@
     auto call = [&]() -> sem::Call* {
         auto resolved = dependencies_.resolved_identifiers.Get(ident);
         if (!resolved) {
-            TINT_ICE(Resolver, diagnostics_)
-                << "identifier '" << ident->symbol.Name() << "' was not resolved";
+            StringStream err;
+            err << "identifier '" << ident->symbol.Name() << "' was not resolved";
+            AddICE(err.str(), ident->source);
             return nullptr;
         }
 
@@ -2882,7 +2889,9 @@
     }
 
     auto name = ident->symbol.Name();
-    TINT_ICE(Resolver, diagnostics_) << ident->source << " unhandled builtin type '" << name << "'";
+    StringStream err;
+    err << " unhandled builtin type '" << name << "'";
+    AddICE(err.str(), ident->source);
     return nullptr;
 }
 
@@ -2905,7 +2914,10 @@
     const auto& signature = builtin->Signature();
     int texture_index = signature.IndexOf(sem::ParameterUsage::kTexture);
     if (TINT_UNLIKELY(texture_index == -1)) {
-        TINT_ICE(Resolver, diagnostics_) << "texture builtin without texture parameter";
+        StringStream err;
+        err << "texture builtin without texture parameter";
+        AddICE(err.str(), {});
+        return;
     }
     if (auto* user =
             args[static_cast<size_t>(texture_index)]->UnwrapLoad()->As<sem::VariableUser>()) {
@@ -3013,8 +3025,7 @@
                 case ast::IntLiteralExpression::Suffix::kU:
                     return builder_->create<type::U32>();
             }
-            TINT_UNREACHABLE(Resolver, diagnostics_)
-                << "Unhandled integer literal suffix: " << i->suffix;
+            TINT_UNREACHABLE() << "Unhandled integer literal suffix: " << i->suffix;
             return nullptr;
         },
         [&](const ast::FloatLiteralExpression* f) -> type::Type* {
@@ -3028,14 +3039,12 @@
                                ? builder_->create<type::F16>()
                                : nullptr;
             }
-            TINT_UNREACHABLE(Resolver, diagnostics_)
-                << "Unhandled float literal suffix: " << f->suffix;
+            TINT_UNREACHABLE() << "Unhandled float literal suffix: " << f->suffix;
             return nullptr;
         },
         [&](const ast::BoolLiteralExpression*) { return builder_->create<type::Bool>(); },
         [&](Default) {
-            TINT_UNREACHABLE(Resolver, diagnostics_)
-                << "Unhandled literal type: " << literal->TypeInfo().name;
+            TINT_UNREACHABLE() << "Unhandled literal type: " << literal->TypeInfo().name;
             return nullptr;
         });
 
@@ -3066,8 +3075,9 @@
 
     auto resolved = dependencies_.resolved_identifiers.Get(ident);
     if (!resolved) {
-        TINT_ICE(Resolver, diagnostics_)
-            << "identifier '" << ident->symbol.Name() << "' was not resolved";
+        StringStream err;
+        err << "identifier '" << ident->symbol.Name() << "' was not resolved";
+        AddICE(err.str(), expr->source);
         return nullptr;
     }
 
@@ -3253,8 +3263,7 @@
         return nullptr;
     }
 
-    TINT_UNREACHABLE(Resolver, diagnostics_)
-        << "unhandled resolved identifier: " << resolved->String(diagnostics_);
+    TINT_UNREACHABLE() << "unhandled resolved identifier: " << resolved->String();
     return nullptr;
 }
 
@@ -3853,7 +3862,7 @@
     } else if (auto* str = named_type->As<ast::Struct>()) {
         result = Structure(str);
     } else {
-        TINT_UNREACHABLE(Resolver, diagnostics_) << "Unhandled TypeDecl";
+        TINT_UNREACHABLE() << "Unhandled TypeDecl";
     }
 
     if (!result) {
@@ -4271,7 +4280,7 @@
         return nullptr;
     }
     if (TINT_UNLIKELY(struct_align > std::numeric_limits<uint32_t>::max())) {
-        TINT_ICE(Resolver, diagnostics_) << "calculated struct stride exceeds uint32";
+        AddICE("calculated struct stride exceeds uint32", str->source);
         return nullptr;
     }
 
@@ -4749,7 +4758,7 @@
 
 bool Resolver::Mark(const ast::Node* node) {
     if (TINT_UNLIKELY(node == nullptr)) {
-        TINT_ICE(Resolver, diagnostics_) << "Resolver::Mark() called with nullptr";
+        AddICE("Resolver::Mark() called with nullptr", {});
         return false;
     }
     auto marked_bit_ref = marked_[node->node_id.value];
@@ -4757,10 +4766,11 @@
         marked_bit_ref = true;
         return true;
     }
-    TINT_ICE(Resolver, diagnostics_) << "AST node '" << node->TypeInfo().name
-                                     << "' was encountered twice in the same AST of a Program\n"
-                                     << "At: " << node->source << "\n"
-                                     << "Pointer: " << node;
+    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;
 }
 
@@ -4789,7 +4799,7 @@
 void Resolver::ErrorMismatchedResolvedIdentifier(const Source& source,
                                                  const ResolvedIdentifier& resolved,
                                                  std::string_view wanted) {
-    AddError("cannot use " + resolved.String(diagnostics_) + " as " + std::string(wanted), source);
+    AddError("cannot use " + resolved.String() + " as " + std::string(wanted), source);
     sem_.NoteDeclarationSource(resolved.Node());
 }
 
@@ -4797,6 +4807,20 @@
     AddError("@" + attr->Name() + " is not valid for " + std::string(use), attr->source);
 }
 
+void Resolver::AddICE(const std::string& msg, const Source& source) const {
+    if (source.file) {
+        TINT_ICE() << source << ": " << msg;
+    } else {
+        TINT_ICE() << msg;
+    }
+    diag::Diagnostic err{};
+    err.severity = diag::Severity::InternalCompilerError;
+    err.system = diag::System::Resolver;
+    err.source = source;
+    err.message = msg;
+    diagnostics_.add(std::move(err));
+}
+
 void Resolver::AddError(const std::string& msg, const Source& source) const {
     diagnostics_.add_error(diag::System::Resolver, msg, source);
 }
diff --git a/src/tint/lang/wgsl/resolver/resolver.h b/src/tint/lang/wgsl/resolver/resolver.h
index 64008a6..322965a 100644
--- a/src/tint/lang/wgsl/resolver/resolver.h
+++ b/src/tint/lang/wgsl/resolver/resolver.h
@@ -538,6 +538,9 @@
     /// @param use the thing that the attribute was applied to
     void ErrorInvalidAttribute(const ast::Attribute* attr, std::string_view use);
 
+    /// Adds the given internal compiler error message to the diagnostics
+    void AddICE(const std::string& msg, const Source& source) const;
+
     /// Adds the given error message to the diagnostics
     void AddError(const std::string& msg, const Source& source) const;
 
diff --git a/src/tint/lang/wgsl/resolver/sem_helper.cc b/src/tint/lang/wgsl/resolver/sem_helper.cc
index 92531ef..eb161a8 100644
--- a/src/tint/lang/wgsl/resolver/sem_helper.cc
+++ b/src/tint/lang/wgsl/resolver/sem_helper.cc
@@ -88,8 +88,8 @@
             return "texel format '" + tint::ToString(fmt->Value()) + "'";
         },
         [&](Default) -> std::string {
-            TINT_ICE(Resolver, builder_->Diagnostics())
-                << "unhandled sem::Expression type: " << (expr ? expr->TypeInfo().name : "<null>");
+            TINT_ICE() << "unhandled sem::Expression type: "
+                       << (expr ? expr->TypeInfo().name : "<null>");
             return "<unknown>";
         });
 }
diff --git a/src/tint/lang/wgsl/resolver/sem_helper.h b/src/tint/lang/wgsl/resolver/sem_helper.h
index 4f567e8..dd46bac 100644
--- a/src/tint/lang/wgsl/resolver/sem_helper.h
+++ b/src/tint/lang/wgsl/resolver/sem_helper.h
@@ -48,10 +48,9 @@
         using T = sem::Info::GetResultType<SEM, AST>;
         auto* sem = builder_->Sem().Get(ast);
         if (TINT_UNLIKELY(!sem)) {
-            TINT_ICE(Resolver, builder_->Diagnostics())
-                << "AST node '" << ast->TypeInfo().name << "' had no semantic info\n"
-                << "At: " << ast->source << "\n"
-                << "Pointer: " << ast;
+            TINT_ICE() << "AST node '" << ast->TypeInfo().name << "' had no semantic info\n"
+                       << "At: " << ast->source << "\n"
+                       << "Pointer: " << ast;
         }
         return const_cast<T*>(As<T>(sem));
     }
diff --git a/src/tint/lang/wgsl/resolver/uniformity.cc b/src/tint/lang/wgsl/resolver/uniformity.cc
index 392449f..7d19804bd6 100644
--- a/src/tint/lang/wgsl/resolver/uniformity.cc
+++ b/src/tint/lang/wgsl/resolver/uniformity.cc
@@ -140,7 +140,7 @@
     /// Add an edge to the `to` node.
     /// @param to the destination node
     void AddEdge(Node* to) {
-        TINT_ASSERT(Resolver, to != nullptr);
+        TINT_ASSERT(to != nullptr);
         edges.Add(to);
     }
 };
@@ -273,7 +273,7 @@
             case builtin::DiagnosticSeverity::kInfo:
                 return required_to_be_uniform_info;
             default:
-                TINT_ASSERT(Resolver, false && "unhandled severity");
+                TINT_UNREACHABLE() << "unhandled severity";
                 return nullptr;
         }
     }
@@ -1053,7 +1053,7 @@
                     current_function_->value_return->AddEdge(v);
                     cf_ret = cf1;
                 } else {
-                    TINT_ASSERT(Resolver, cf != nullptr);
+                    TINT_ASSERT(cf != nullptr);
                     cf_ret = cf;
                 }
 
@@ -1161,8 +1161,7 @@
             },
 
             [&](Default) {
-                TINT_ICE(Resolver, diagnostics_)
-                    << "unknown statement type: " << std::string(stmt->TypeInfo().name);
+                TINT_ICE() << "unknown statement type: " << std::string(stmt->TypeInfo().name);
                 return nullptr;
             });
     }
@@ -1190,7 +1189,7 @@
 
         auto* node = CreateNode({NameFor(ident), "_ident_expr"}, ident);
         auto* sem_ident = sem_.GetVal(ident);
-        TINT_ASSERT(Resolver, sem_ident);
+        TINT_ASSERT(sem_ident);
         auto* var_user = sem_ident->Unwrap()->As<sem::VariableUser>();
         auto* sem = var_user->Variable();
         return Switch(
@@ -1294,8 +1293,8 @@
             },
 
             [&](Default) {
-                TINT_ICE(Resolver, diagnostics_)
-                    << "unknown identifier expression type: " << std::string(sem->TypeInfo().name);
+                TINT_ICE() << "unknown identifier expression type: "
+                           << std::string(sem->TypeInfo().name);
                 return std::pair<Node*, Node*>(nullptr, nullptr);
             });
     }
@@ -1367,8 +1366,7 @@
             },
 
             [&](Default) {
-                TINT_ICE(Resolver, diagnostics_)
-                    << "unknown expression type: " << std::string(expr->TypeInfo().name);
+                TINT_ICE() << "unknown expression type: " << std::string(expr->TypeInfo().name);
                 return std::pair<Node*, Node*>(nullptr, nullptr);
             });
     }
@@ -1377,7 +1375,7 @@
     /// @returns true if `u` is an indirection unary expression that ultimately dereferences a
     /// partial pointer, false otherwise.
     bool IsDerefOfPartialPointer(const ast::UnaryOpExpression* u) {
-        TINT_ASSERT(Resolver, u->op == ast::UnaryOp::kIndirection);
+        TINT_ASSERT(u->op == ast::UnaryOp::kIndirection);
 
         // To determine if we're dereferencing a partial pointer, unwrap *&
         // chains; if the final expression is an identifier, see if it's a
@@ -1389,7 +1387,7 @@
                 return true;
             }
         } else {
-            TINT_ASSERT(Resolver, e->Is<ast::AccessorExpression>());
+            TINT_ASSERT(e->Is<ast::AccessorExpression>());
             return true;
         }
         return false;
@@ -1436,9 +1434,8 @@
 
                     return LValue{cf, value, local};
                 } else {
-                    TINT_ICE(Resolver, diagnostics_)
-                        << "unknown lvalue identifier expression type: "
-                        << std::string(sem->Variable()->TypeInfo().name);
+                    TINT_ICE() << "unknown lvalue identifier expression type: "
+                               << std::string(sem->Variable()->TypeInfo().name);
                     return LValue{};
                 }
             },
@@ -1476,8 +1473,8 @@
             },
 
             [&](Default) {
-                TINT_ICE(Resolver, diagnostics_)
-                    << "unknown lvalue expression type: " << std::string(expr->TypeInfo().name);
+                TINT_ICE() << "unknown lvalue expression type: "
+                           << std::string(expr->TypeInfo().name);
                 return LValue{};
             });
     }
@@ -1577,7 +1574,7 @@
                 // We must have already analyzed the user-defined function since we process
                 // functions in dependency order.
                 auto info = functions_.Find(func->Declaration());
-                TINT_ASSERT(Resolver, info != nullptr);
+                TINT_ASSERT(info != nullptr);
                 callsite_tag = info->callsite_tag;
                 function_tag = info->function_tag;
                 func_info = info;
@@ -1590,9 +1587,7 @@
                 callsite_tag = {CallSiteTag::CallSiteNoRestriction};
                 function_tag = NoRestriction;
             },
-            [&](Default) {
-                TINT_ICE(Resolver, diagnostics_) << "unhandled function call target: " << name;
-            });
+            [&](Default) { TINT_ICE() << "unhandled function call target: " << name; });
 
         cf_after->AddEdge(call_node);
 
@@ -1662,7 +1657,7 @@
 
                     // Update the current stored value for this pointer argument.
                     auto* root_ident = sem_arg->RootIdentifier();
-                    TINT_ASSERT(Resolver, root_ident);
+                    TINT_ASSERT(root_ident);
                     current_function_->variables.Set(root_ident, ptr_result);
                 }
             } else {
@@ -1746,9 +1741,9 @@
                     return FindBuiltinThatRequiresUniformity(child_call, severity);
                 }
             }
-            TINT_ASSERT(Resolver, false && "unable to find child call with uniformity requirement");
+            TINT_UNREACHABLE() << "unable to find child call with uniformity requirement";
         } else {
-            TINT_ASSERT(Resolver, false && "unexpected call expression type");
+            TINT_UNREACHABLE() << "unexpected call expression type";
         }
         return nullptr;
     }
@@ -1766,7 +1761,7 @@
 
         // Get the source of the non-uniform value.
         auto* non_uniform_source = may_be_non_uniform->visited_from;
-        TINT_ASSERT(Resolver, non_uniform_source);
+        TINT_ASSERT(non_uniform_source);
 
         // Show where the non-uniform value results in non-uniform control flow.
         auto* control_flow = TraceBackAlongPathUntil(
@@ -1789,7 +1784,7 @@
     /// Add a diagnostic note to show the origin of a non-uniform value.
     /// @param non_uniform_source the node that represents a non-uniform value
     void ShowSourceOfNonUniformity(Node* non_uniform_source) {
-        TINT_ASSERT(Resolver, non_uniform_source);
+        TINT_ASSERT(non_uniform_source);
 
         auto var_type = [&](const sem::Variable* var) {
             switch (var->AddressSpace()) {
@@ -1874,7 +1869,7 @@
                         break;
                     }
                     default: {
-                        TINT_ICE(Resolver, diagnostics_) << "unhandled source of non-uniformity";
+                        TINT_ICE() << "unhandled source of non-uniformity";
                         break;
                     }
                 }
@@ -1883,9 +1878,7 @@
                 diagnostics_.add_note(diag::System::Resolver,
                                       "result of expression may be non-uniform", e->source);
             },
-            [&](Default) {
-                TINT_ICE(Resolver, diagnostics_) << "unhandled source of non-uniformity";
-            });
+            [&](Default) { TINT_ICE() << "unhandled source of non-uniformity"; });
     }
 
     /// Generate a diagnostic message for a uniformity issue.
@@ -1908,7 +1901,7 @@
         // Traverse the graph to generate a path from RequiredToBeUniform to the source node.
         function.ResetVisited();
         Traverse(function.RequiredToBeUniform(severity));
-        TINT_ASSERT(Resolver, source_node->visited_from);
+        TINT_ASSERT(source_node->visited_from);
 
         // Find a node that is required to be uniform that has a path to the source node.
         auto* cause = TraceBackAlongPathUntil(source_node, [&](Node* node) {
@@ -1917,7 +1910,7 @@
 
         // The node will always have a corresponding call expression.
         auto* call = cause->ast->As<ast::CallExpression>();
-        TINT_ASSERT(Resolver, call);
+        TINT_ASSERT(call);
         auto* target = SemCall(call)->Target();
         auto func_name = NameFor(call->target);
 
diff --git a/src/tint/lang/wgsl/resolver/validation_test.cc b/src/tint/lang/wgsl/resolver/validation_test.cc
index c6c399e..8a23f2d 100644
--- a/src/tint/lang/wgsl/resolver/validation_test.cc
+++ b/src/tint/lang/wgsl/resolver/validation_test.cc
@@ -155,8 +155,7 @@
             b.WrapInFunction(b.create<FakeExpr>());
             Resolver(&b).Resolve();
         },
-        "internal compiler error: unhandled expression type: "
-        "tint::resolver::FakeExpr");
+        "internal compiler error: unhandled expression 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 1716e50..b7e4780 100644
--- a/src/tint/lang/wgsl/resolver/validator.cc
+++ b/src/tint/lang/wgsl/resolver/validator.cc
@@ -127,22 +127,19 @@
 }
 
 template <typename CALLBACK>
-void TraverseCallChain(diag::List& diagnostics,
-                       const sem::Function* from,
-                       const sem::Function* to,
-                       CALLBACK&& callback) {
+void TraverseCallChain(const sem::Function* from, const sem::Function* to, CALLBACK&& callback) {
     for (auto* f : from->TransitivelyCalledFunctions()) {
         if (f == to) {
             callback(f);
             return;
         }
         if (f->TransitivelyCalledFunctions().Contains(to)) {
-            TraverseCallChain(diagnostics, f, to, callback);
+            TraverseCallChain(f, to, callback);
             callback(f);
             return;
         }
     }
-    TINT_ICE(Resolver, diagnostics) << "TraverseCallChain() 'from' does not transitively call 'to'";
+    TINT_ICE() << "TraverseCallChain() 'from' does not transitively call 'to'";
 }
 
 }  // namespace
@@ -571,9 +568,8 @@
         [&](const ast::Let*) { return Let(local); },  //
         [&](const ast::Const*) { return true; },      //
         [&](Default) {
-            TINT_ICE(Resolver, diagnostics_)
-                << "Validator::Variable() called with a unknown variable type: "
-                << decl->TypeInfo().name;
+            TINT_ICE() << "Validator::Variable() called with a unknown variable type: "
+                       << decl->TypeInfo().name;
             return false;
         });
 }
@@ -611,9 +607,8 @@
         [&](const ast::Override*) { return Override(global, override_ids); },
         [&](const ast::Const*) { return Const(global); },
         [&](Default) {
-            TINT_ICE(Resolver, diagnostics_)
-                << "Validator::GlobalVariable() called with a unknown variable type: "
-                << decl->TypeInfo().name;
+            TINT_ICE() << "Validator::GlobalVariable() called with a unknown variable type: "
+                       << decl->TypeInfo().name;
             return false;
         });
 
@@ -1018,8 +1013,7 @@
             }
         } else if (TINT_UNLIKELY(IsValidationEnabled(
                        decl->attributes, ast::DisabledValidation::kFunctionHasNoBody))) {
-            TINT_ICE(Resolver, diagnostics_)
-                << "Function " << decl->name->symbol.Name() << " has no body";
+            TINT_ICE() << "Function " << decl->name->symbol.Name() << " has no body";
         }
     }
 
@@ -1034,8 +1028,7 @@
     if (TINT_UNLIKELY(func->Behaviors() != sem::Behaviors{} &&
                       func->Behaviors() != sem::Behavior::kNext)) {
         auto name = decl->name->symbol.Name();
-        TINT_ICE(Resolver, diagnostics_)
-            << "function '" << name << "' behaviors are: " << func->Behaviors();
+        TINT_ICE() << "function '" << name << "' behaviors are: " << func->Behaviors();
     }
 
     return true;
@@ -1110,7 +1103,7 @@
                 bool is_input = param_or_ret == ParamOrRetType::kParameter;
 
                 if (TINT_UNLIKELY(!location.has_value())) {
-                    TINT_ICE(Resolver, diagnostics_) << "Location has no value";
+                    TINT_ICE() << "Location has no value";
                     return false;
                 }
 
@@ -1663,10 +1656,10 @@
         return false;
     }
 
-    TINT_ASSERT(Resolver, call->Arguments().Length() > 0);
+    TINT_ASSERT(call->Arguments().Length() > 0);
     auto* arg = call->Arguments()[0];
     auto* ptr = arg->Type()->As<type::Pointer>();
-    TINT_ASSERT(Resolver, ptr != nullptr);
+    TINT_ASSERT(ptr != nullptr);
     auto* ty = ptr->StoreType();
 
     if (ty->Is<type::Atomic>() || atomic_composite_info_.Contains(ty)) {
@@ -1763,7 +1756,7 @@
             auto* root = call->Arguments()[i]->RootIdentifier();
             auto* root_ptr_ty = root->Type()->As<type::Pointer>();
             auto* root_ref_ty = root->Type()->As<type::Reference>();
-            TINT_ASSERT(Resolver, root_ptr_ty || root_ref_ty);
+            TINT_ASSERT(root_ptr_ty || root_ref_ty);
             const type::Type* root_store_type;
             if (root_ptr_ty) {
                 root_store_type = root_ptr_ty->StoreType();
@@ -1865,7 +1858,7 @@
     }
 
     if (TINT_UNLIKELY(!c->Is<type::ConstantArrayCount>())) {
-        TINT_ICE(Resolver, diagnostics_) << "Invalid ArrayCount found";
+        TINT_ICE() << "Invalid ArrayCount found";
         return false;
     }
 
@@ -1899,7 +1892,7 @@
 bool Validator::PipelineStages(VectorRef<sem::Function*> entry_points) const {
     auto backtrace = [&](const sem::Function* func, const sem::Function* entry_point) {
         if (func != entry_point) {
-            TraverseCallChain(diagnostics_, entry_point, func, [&](const sem::Function* f) {
+            TraverseCallChain(entry_point, func, [&](const sem::Function* f) {
                 AddNote("called by function '" + f->Declaration()->name->symbol.Name() + "'",
                         f->Declaration()->source);
             });
@@ -2017,7 +2010,7 @@
                 AddNote("first 'push_constant' variable declaration is here",
                         var->Declaration()->source);
                 if (func != ep) {
-                    TraverseCallChain(diagnostics_, ep, func, [&](const sem::Function* f) {
+                    TraverseCallChain(ep, func, [&](const sem::Function* f) {
                         AddNote(
                             "called by function '" + f->Declaration()->name->symbol.Name() + "'",
                             f->Declaration()->source);
@@ -2029,12 +2022,11 @@
                 AddNote("second 'push_constant' variable declaration is here",
                         push_constant_var->Declaration()->source);
                 if (push_constant_func != ep) {
-                    TraverseCallChain(diagnostics_, ep, push_constant_func,
-                                      [&](const sem::Function* f) {
-                                          AddNote("called by function '" +
-                                                      f->Declaration()->name->symbol.Name() + "'",
-                                                  f->Declaration()->source);
-                                      });
+                    TraverseCallChain(ep, push_constant_func, [&](const sem::Function* f) {
+                        AddNote(
+                            "called by function '" + f->Declaration()->name->symbol.Name() + "'",
+                            f->Declaration()->source);
+                    });
                     AddNote(
                         "called by entry point '" + ep->Declaration()->name->symbol.Name() + "'",
                         ep->Declaration()->source);
@@ -2145,7 +2137,7 @@
                 },
                 [&](const ast::LocationAttribute* location) {
                     location_attribute = location;
-                    TINT_ASSERT(Resolver, member->Attributes().location.has_value());
+                    TINT_ASSERT(member->Attributes().location.has_value());
                     if (!LocationAttribute(location, member->Type(), stage,
                                            member->Declaration()->source)) {
                         return false;
@@ -2394,7 +2386,7 @@
         lhs = compound->lhs;
         rhs = compound->rhs;
     } else {
-        TINT_ICE(Resolver, diagnostics_) << "invalid assignment statement";
+        TINT_ICE() << "invalid assignment statement";
         return false;
     }
 
diff --git a/src/tint/lang/wgsl/sem/array_count.cc b/src/tint/lang/wgsl/sem/array_count.cc
index 2e867a4..407d6b2 100644
--- a/src/tint/lang/wgsl/sem/array_count.cc
+++ b/src/tint/lang/wgsl/sem/array_count.cc
@@ -38,7 +38,7 @@
 }
 
 type::ArrayCount* NamedOverrideArrayCount::Clone(type::CloneContext&) const {
-    TINT_ASSERT(Type, false && "Named override array count clone not available");
+    TINT_UNREACHABLE() << "Named override array count clone not available";
     return nullptr;
 }
 
@@ -59,7 +59,7 @@
 }
 
 type::ArrayCount* UnnamedOverrideArrayCount::Clone(type::CloneContext&) const {
-    TINT_ASSERT(Type, false && "Unnamed override array count clone not available");
+    TINT_UNREACHABLE() << "Unnamed override array count clone not available";
     return nullptr;
 }
 
diff --git a/src/tint/lang/wgsl/sem/block_statement.cc b/src/tint/lang/wgsl/sem/block_statement.cc
index 19c9211..8c2bf7a 100644
--- a/src/tint/lang/wgsl/sem/block_statement.cc
+++ b/src/tint/lang/wgsl/sem/block_statement.cc
@@ -37,7 +37,7 @@
 
 FunctionBlockStatement::FunctionBlockStatement(const sem::Function* function)
     : Base(function->Declaration()->body, nullptr, function) {
-    TINT_ASSERT(Semantic, function);
+    TINT_ASSERT(function);
 }
 
 FunctionBlockStatement::~FunctionBlockStatement() = default;
@@ -46,8 +46,8 @@
                                        const CompoundStatement* parent,
                                        const sem::Function* function)
     : Base(declaration, parent, function) {
-    TINT_ASSERT(Semantic, parent);
-    TINT_ASSERT(Semantic, function);
+    TINT_ASSERT(parent);
+    TINT_ASSERT(function);
 }
 LoopBlockStatement::~LoopBlockStatement() = default;
 
diff --git a/src/tint/lang/wgsl/sem/call.cc b/src/tint/lang/wgsl/sem/call.cc
index dede66b..643849b 100644
--- a/src/tint/lang/wgsl/sem/call.cc
+++ b/src/tint/lang/wgsl/sem/call.cc
@@ -32,8 +32,7 @@
       target_(target),
       arguments_(std::move(arguments)) {
     // Check that the stage is no earlier than the target supports
-    TINT_ASSERT(Semantic,
-                (target->Stage() <= stage) || (stage == sem::EvaluationStage::kNotEvaluated));
+    TINT_ASSERT((target->Stage() <= stage) || (stage == sem::EvaluationStage::kNotEvaluated));
 }
 
 Call::~Call() = default;
diff --git a/src/tint/lang/wgsl/sem/call_target.cc b/src/tint/lang/wgsl/sem/call_target.cc
index b5ce684..cee9cb8 100644
--- a/src/tint/lang/wgsl/sem/call_target.cc
+++ b/src/tint/lang/wgsl/sem/call_target.cc
@@ -34,7 +34,7 @@
     for (auto* param : parameters) {
         AddParameter(param);
     }
-    TINT_ASSERT(Semantic, return_type);
+    TINT_ASSERT(return_type);
 }
 
 CallTarget::CallTarget(const CallTarget&) = default;
diff --git a/src/tint/lang/wgsl/sem/info.cc b/src/tint/lang/wgsl/sem/info.cc
index 750836e..dabdaeb 100644
--- a/src/tint/lang/wgsl/sem/info.cc
+++ b/src/tint/lang/wgsl/sem/info.cc
@@ -73,7 +73,7 @@
 
     // Query the diagnostic severity from the semantic node that corresponds to the AST node.
     auto* sem = Get(ast_node);
-    TINT_ASSERT(Resolver, sem != nullptr);
+    TINT_ASSERT(sem != nullptr);
     auto severity = Switch(
         sem,  //
         [&](const sem::ValueExpression* expr) { return check_stmt(expr->Stmt()); },
@@ -83,7 +83,7 @@
             // Use the global severity set on the module.
             return check(module_);
         });
-    TINT_ASSERT(Resolver, severity != builtin::DiagnosticSeverity::kUndefined);
+    TINT_ASSERT(severity != builtin::DiagnosticSeverity::kUndefined);
     return severity;
 }
 
diff --git a/src/tint/lang/wgsl/sem/info.h b/src/tint/lang/wgsl/sem/info.h
index 91cbcce..649c9f0 100644
--- a/src/tint/lang/wgsl/sem/info.h
+++ b/src/tint/lang/wgsl/sem/info.h
@@ -25,7 +25,7 @@
 #include "src/tint/lang/wgsl/sem/node.h"
 #include "src/tint/lang/wgsl/sem/type_mappings.h"
 #include "src/tint/utils/containers/unique_vector.h"
-#include "src/tint/utils/debug/debug.h"
+#include "src/tint/utils/ice/ice.h"
 
 // Forward declarations
 namespace tint::sem {
@@ -104,7 +104,7 @@
     void Add(const AST* ast_node, const SemanticNodeTypeFor<AST>* sem_node) {
         Reserve(ast_node->node_id);
         // Check there's no semantic info already existing for the AST node
-        TINT_ASSERT(Semantic, nodes_[ast_node->node_id.value] == nullptr);
+        TINT_ASSERT(nodes_[ast_node->node_id.value] == nullptr);
         nodes_[ast_node->node_id.value] = sem_node;
     }
 
diff --git a/src/tint/lang/wgsl/sem/load.cc b/src/tint/lang/wgsl/sem/load.cc
index 2d57224..129f926 100644
--- a/src/tint/lang/wgsl/sem/load.cc
+++ b/src/tint/lang/wgsl/sem/load.cc
@@ -15,7 +15,7 @@
 #include "src/tint/lang/wgsl/sem/load.h"
 
 #include "src/tint/lang/core/type/reference.h"
-#include "src/tint/utils/debug/debug.h"
+#include "src/tint/utils/ice/ice.h"
 
 TINT_INSTANTIATE_TYPEINFO(tint::sem::Load);
 
@@ -29,7 +29,7 @@
            /* has_side_effects */ ref->HasSideEffects(),
            /* root_ident */ ref->RootIdentifier()),
       reference_(ref) {
-    TINT_ASSERT(Semantic, ref->Type()->Is<type::Reference>());
+    TINT_ASSERT(ref->Type()->Is<type::Reference>());
 }
 
 Load::~Load() = default;
diff --git a/src/tint/lang/wgsl/sem/loop_statement.cc b/src/tint/lang/wgsl/sem/loop_statement.cc
index b125176..f6605f2 100644
--- a/src/tint/lang/wgsl/sem/loop_statement.cc
+++ b/src/tint/lang/wgsl/sem/loop_statement.cc
@@ -26,8 +26,8 @@
                              const CompoundStatement* parent,
                              const sem::Function* function)
     : Base(declaration, parent, function) {
-    TINT_ASSERT(Semantic, parent);
-    TINT_ASSERT(Semantic, function);
+    TINT_ASSERT(parent);
+    TINT_ASSERT(function);
 }
 
 LoopStatement::~LoopStatement() = default;
@@ -36,8 +36,8 @@
                                                            const CompoundStatement* parent,
                                                            const sem::Function* function)
     : Base(declaration, parent, function) {
-    TINT_ASSERT(Semantic, parent);
-    TINT_ASSERT(Semantic, function);
+    TINT_ASSERT(parent);
+    TINT_ASSERT(function);
 }
 LoopContinuingBlockStatement::~LoopContinuingBlockStatement() = default;
 
diff --git a/src/tint/lang/wgsl/sem/struct.cc b/src/tint/lang/wgsl/sem/struct.cc
index e779ac0..07d79f8 100644
--- a/src/tint/lang/wgsl/sem/struct.cc
+++ b/src/tint/lang/wgsl/sem/struct.cc
@@ -28,7 +28,7 @@
                uint32_t size,
                uint32_t size_no_padding)
     : Base(name, members, align, size, size_no_padding), declaration_(declaration) {
-    TINT_ASSERT(Semantic, declaration != nullptr);
+    TINT_ASSERT(declaration != nullptr);
 }
 
 Struct::~Struct() = default;
@@ -42,7 +42,7 @@
                            uint32_t size,
                            const type::StructMemberAttributes& attributes)
     : Base(name, type, index, offset, align, size, attributes), declaration_(declaration) {
-    TINT_ASSERT(Semantic, declaration != nullptr);
+    TINT_ASSERT(declaration != nullptr);
 }
 
 StructMember::~StructMember() = default;
diff --git a/src/tint/lang/wgsl/sem/switch_statement.cc b/src/tint/lang/wgsl/sem/switch_statement.cc
index 53213d6..e3d0c67 100644
--- a/src/tint/lang/wgsl/sem/switch_statement.cc
+++ b/src/tint/lang/wgsl/sem/switch_statement.cc
@@ -27,8 +27,8 @@
                                  const CompoundStatement* parent,
                                  const sem::Function* function)
     : Base(declaration, parent, function) {
-    TINT_ASSERT(Semantic, parent);
-    TINT_ASSERT(Semantic, function);
+    TINT_ASSERT(parent);
+    TINT_ASSERT(function);
 }
 
 SwitchStatement::~SwitchStatement() = default;
@@ -41,8 +41,8 @@
                              const CompoundStatement* parent,
                              const sem::Function* function)
     : Base(declaration, parent, function) {
-    TINT_ASSERT(Semantic, parent);
-    TINT_ASSERT(Semantic, function);
+    TINT_ASSERT(parent);
+    TINT_ASSERT(function);
 }
 CaseStatement::~CaseStatement() = default;
 
diff --git a/src/tint/lang/wgsl/sem/value_expression.cc b/src/tint/lang/wgsl/sem/value_expression.cc
index 5d69e97..28d5104 100644
--- a/src/tint/lang/wgsl/sem/value_expression.cc
+++ b/src/tint/lang/wgsl/sem/value_expression.cc
@@ -37,10 +37,10 @@
       stage_(stage),
       constant_(std::move(constant)),
       has_side_effects_(has_side_effects) {
-    TINT_ASSERT(Semantic, type_);
-    TINT_ASSERT(Semantic, (constant != nullptr) == (stage == EvaluationStage::kConstant));
+    TINT_ASSERT(type_);
+    TINT_ASSERT((constant != nullptr) == (stage == EvaluationStage::kConstant));
     if (constant != nullptr) {
-        TINT_ASSERT(Semantic, type_ == constant->Type());
+        TINT_ASSERT(type_ == constant->Type());
     }
 }
 
diff --git a/src/tint/lang/wgsl/writer/ast_printer/ast_printer.cc b/src/tint/lang/wgsl/writer/ast_printer/ast_printer.cc
index 07a2edf..c21bb65 100644
--- a/src/tint/lang/wgsl/writer/ast_printer/ast_printer.cc
+++ b/src/tint/lang/wgsl/writer/ast_printer/ast_printer.cc
@@ -109,7 +109,7 @@
             [&](const ast::Function* func) { return EmitFunction(func); },
             [&](const ast::Variable* var) { return EmitVariable(Line(), var); },
             [&](const ast::ConstAssert* ca) { return EmitConstAssert(ca); },
-            [&](Default) { TINT_UNREACHABLE(Writer, diagnostics_); });
+            [&](Default) { TINT_UNREACHABLE(); });
         if (decl != program_->AST().GlobalDeclarations().Back()) {
             Line();
         }
@@ -420,9 +420,7 @@
         },
         [&](const ast::Let*) { out << "let"; }, [&](const ast::Override*) { out << "override"; },
         [&](const ast::Const*) { out << "const"; },
-        [&](Default) {
-            TINT_ICE(Writer, diagnostics_) << "unhandled variable type " << v->TypeInfo().name;
-        });
+        [&](Default) { TINT_ICE() << "unhandled variable type " << v->TypeInfo().name; });
 
     out << " " << v->name->symbol.Name();
 
@@ -526,8 +524,7 @@
                 out << "internal(" << internal->InternalName() << ")";
             },
             [&](Default) {
-                TINT_ICE(Writer, diagnostics_)
-                    << "Unsupported attribute '" << attr->TypeInfo().name << "'";
+                TINT_ICE() << "Unsupported attribute '" << attr->TypeInfo().name << "'";
             });
     }
 }
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 ffe0443..4ee82b2 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
@@ -74,9 +74,9 @@
 #include "src/tint/utils/rtti/switch.h"
 
 // Helper for calling TINT_UNIMPLEMENTED() from a Switch(object_ptr) default case.
-#define UNHANDLED_CASE(object_ptr)          \
-    TINT_UNIMPLEMENTED(IR, b.Diagnostics()) \
-        << "unhandled case in Switch(): " << (object_ptr ? object_ptr->TypeInfo().name : "<null>")
+#define UNHANDLED_CASE(object_ptr)                         \
+    TINT_UNIMPLEMENTED() << "unhandled case in Switch(): " \
+                         << (object_ptr ? object_ptr->TypeInfo().name : "<null>")
 
 // Helper for incrementing nesting_depth_ and then decrementing nesting_depth_ at the end
 // of the scope that holds the call.
@@ -495,8 +495,7 @@
 
         // Return has arguments - this is the return value.
         if (ret->Args().Length() != 1) {
-            TINT_ICE(IR, b.Diagnostics())
-                << "expected 1 value for return, got " << ret->Args().Length();
+            TINT_ICE() << "expected 1 value for return, got " << ret->Args().Length();
             return;
         }
 
@@ -641,13 +640,12 @@
                 [&](const type::Struct* s) {
                     if (auto* c = index->As<ir::Constant>()) {
                         auto i = c->Value()->ValueAs<uint32_t>();
-                        TINT_ASSERT_OR_RETURN(IR, i < s->Members().Length());
+                        TINT_ASSERT_OR_RETURN(i < s->Members().Length());
                         auto* member = s->Members()[i];
                         obj_ty = member->Type();
                         expr = b.MemberAccessor(expr, member->Name().NameView());
                     } else {
-                        TINT_ICE(IR, b.Diagnostics())
-                            << "invalid index for struct type: " << index->TypeInfo().name;
+                        TINT_ICE() << "invalid index for struct type: " << index->TypeInfo().name;
                     }
                 },
                 [&](Default) { UNHANDLED_CASE(obj_ty); });
@@ -660,7 +658,7 @@
         Vector<char, 4> components;
         for (uint32_t i : s->Indices()) {
             if (TINT_UNLIKELY(i >= 4)) {
-                TINT_ICE(IR, b.Diagnostics()) << "invalid swizzle index: " << i;
+                TINT_ICE() << "invalid swizzle index: " << i;
                 return;
             }
             components.Push("xyzw"[i]);
@@ -748,9 +746,8 @@
             [&](Default) -> ExprAndPtrKind {
                 auto lookup = bindings_.Find(value);
                 if (TINT_UNLIKELY(!lookup)) {
-                    TINT_ICE(IR, b.Diagnostics())
-                        << "Expr(" << (value ? value->TypeInfo().name : "null")
-                        << ") value has no expression";
+                    TINT_ICE() << "Expr(" << (value ? value->TypeInfo().name : "null")
+                               << ") value has no expression";
                     return {};
                 }
                 return std::visit(
@@ -769,10 +766,10 @@
                         }
 
                         if constexpr (std::is_same_v<T, ConsumedValue>) {
-                            TINT_ICE(IR, b.Diagnostics()) << "Expr(" << value->TypeInfo().name
-                                                          << ") called twice on the same value";
+                            TINT_ICE() << "Expr(" << value->TypeInfo().name
+                                       << ") called twice on the same value";
                         } else {
-                            TINT_ICE(IR, b.Diagnostics())
+                            TINT_ICE()
                                 << "Expr(" << value->TypeInfo().name << ") has unhandled value";
                         }
                         return {};
@@ -868,7 +865,7 @@
             [&](const type::Vector* v) {
                 auto el = Type(v->type());
                 if (v->Packed()) {
-                    TINT_ASSERT(IR, v->Width() == 3u);
+                    TINT_ASSERT(v->Width() == 3u);
                     return b.ty(builtin::Builtin::kPackedVec3, el);
                 } else {
                     return b.ty.vec(el, v->Width());
@@ -885,7 +882,7 @@
                 }
                 auto count = a->ConstantCount();
                 if (TINT_UNLIKELY(!count)) {
-                    TINT_ICE(IR, b.Diagnostics()) << type::Array::kErrExpectedConstantCount;
+                    TINT_ICE() << type::Array::kErrExpectedConstantCount;
                     return b.ty.array(el, u32(1), std::move(attrs));
                 }
                 return b.ty.array(el, u32(count.value()), std::move(attrs));
@@ -920,7 +917,7 @@
                 return b.ty.ptr(address_space, el, access);
             },
             [&](const type::Reference*) {
-                TINT_ICE(IR, b.Diagnostics()) << "reference types should never appear in the IR";
+                TINT_ICE() << "reference types should never appear in the IR";
                 return b.ty.i32();
             },
             [&](Default) {
@@ -1002,7 +999,7 @@
     /// Associates the IR value @p value with the AST expression @p expr.
     /// @p ptr_kind defines how pointer values are represented by @p expr.
     void Bind(ir::Value* value, const ast::Expression* expr, PtrKind ptr_kind = PtrKind::kRef) {
-        TINT_ASSERT(IR, value);
+        TINT_ASSERT(value);
         if (can_inline_.Remove(value)) {
             // Value will be inlined at its place of usage.
             if (TINT_LIKELY(bindings_.Add(value, InlinedValue{expr, ptr_kind}))) {
@@ -1026,20 +1023,18 @@
             return;
         }
 
-        TINT_ICE(IR, b.Diagnostics())
-            << "Bind(" << value->TypeInfo().name << ") called twice for same value";
+        TINT_ICE() << "Bind(" << value->TypeInfo().name << ") called twice for same value";
     }
 
     /// Associates the IR value @p value with the AST 'var', 'let' or parameter with the name @p
     /// name.
     /// @p ptr_kind defines how pointer values are represented by @p expr.
     void Bind(ir::Value* value, Symbol name, PtrKind ptr_kind) {
-        TINT_ASSERT(IR, value);
+        TINT_ASSERT(value);
 
         bool added = bindings_.Add(value, VariableValue{name, ptr_kind});
         if (TINT_UNLIKELY(!added)) {
-            TINT_ICE(IR, b.Diagnostics())
-                << "Bind(" << value->TypeInfo().name << ") called twice for same value";
+            TINT_ICE() << "Bind(" << value->TypeInfo().name << ") called twice for same value";
         }
     }
 
diff --git a/src/tint/lang/wgsl/writer/ir_to_program/rename_conflicts.cc b/src/tint/lang/wgsl/writer/ir_to_program/rename_conflicts.cc
index f7f62f7..8795491 100644
--- a/src/tint/lang/wgsl/writer/ir_to_program/rename_conflicts.cc
+++ b/src/tint/lang/wgsl/writer/ir_to_program/rename_conflicts.cc
@@ -261,9 +261,7 @@
             [&](ir::Value* value) { ir->SetName(value, new_name); },
             [&](type::Struct* str) { str->SetName(new_name); },
             [&](Default) {
-                diag::List diags;
-                TINT_ICE(Transform, diags)
-                    << "unhandled type for renaming: " << thing->TypeInfo().name;
+                TINT_ICE() << "unhandled type for renaming: " << thing->TypeInfo().name;
             });
     }
 
diff --git a/src/tint/lang/wgsl/writer/syntax_tree_printer/syntax_tree_printer.cc b/src/tint/lang/wgsl/writer/syntax_tree_printer/syntax_tree_printer.cc
index 5de0f1e..7d0e627 100644
--- a/src/tint/lang/wgsl/writer/syntax_tree_printer/syntax_tree_printer.cc
+++ b/src/tint/lang/wgsl/writer/syntax_tree_printer/syntax_tree_printer.cc
@@ -91,7 +91,7 @@
             [&](const ast::Function* func) { EmitFunction(func); },
             [&](const ast::Variable* var) { EmitVariable(var); },
             [&](const ast::ConstAssert* ca) { EmitConstAssert(ca); },
-            [&](Default) { TINT_UNREACHABLE(Writer, diagnostics_); });
+            [&](Default) { TINT_UNREACHABLE(); });
 
         if (decl != program_->AST().GlobalDeclarations().Back()) {
             Line();
@@ -485,9 +485,7 @@
             [&](const ast::Let*) { Line() << "Let []"; },
             [&](const ast::Override*) { Line() << "Override []"; },
             [&](const ast::Const*) { Line() << "Const []"; },
-            [&](Default) {
-                TINT_ICE(Writer, diagnostics_) << "unhandled variable type " << v->TypeInfo().name;
-            });
+            [&](Default) { TINT_ICE() << "unhandled variable type " << v->TypeInfo().name; });
 
         Line() << "name: " << v->name->symbol.Name();
 
@@ -637,8 +635,7 @@
                 Line() << "InternalAttribute [" << internal->InternalName() << "]";
             },
             [&](Default) {
-                TINT_ICE(Writer, diagnostics_)
-                    << "Unsupported attribute '" << attr->TypeInfo().name << "'";
+                TINT_ICE() << "Unsupported attribute '" << attr->TypeInfo().name << "'";
             });
     }
 }
diff --git a/src/tint/test_main.cc b/src/tint/test_main.cc
index 1c75902..4f7ae8d 100644
--- a/src/tint/test_main.cc
+++ b/src/tint/test_main.cc
@@ -13,17 +13,12 @@
 // limitations under the License.
 
 #include "gmock/gmock.h"
-#include "src/tint/lang/wgsl/program/program.h"
 #include "tint/tint.h"
 
-#if TINT_BUILD_SPV_READER
-#include "src/tint/lang/spirv/reader/ast_parser/test_helper.h"
-#endif
-
 namespace {
 
-void TintInternalCompilerErrorReporter(const tint::diag::List& diagnostics) {
-    FAIL() << diagnostics.str();
+void TintInternalCompilerErrorReporter(const tint::InternalCompilerError& err) {
+    FAIL() << err.Error();
 }
 
 struct Flags {
@@ -58,12 +53,6 @@
         return -1;
     }
 
-#if TINT_BUILD_SPV_READER
-    if (flags.spirv_reader_dump_converted) {
-        tint::spirv::reader::test::DumpSuccessfullyConvertedSpirv();
-    }
-#endif  // TINT_BUILD_SPV_READER
-
     tint::SetInternalCompilerErrorReporter(&TintInternalCompilerErrorReporter);
 
     auto res = RUN_ALL_TESTS();
diff --git a/src/tint/utils/containers/hashmap.h b/src/tint/utils/containers/hashmap.h
index bfbe7fc..d3c7b96 100644
--- a/src/tint/utils/containers/hashmap.h
+++ b/src/tint/utils/containers/hashmap.h
@@ -21,7 +21,7 @@
 
 #include "src/tint/utils/containers/hashmap_base.h"
 #include "src/tint/utils/containers/vector.h"
-#include "src/tint/utils/debug/debug.h"
+#include "src/tint/utils/ice/ice.h"
 #include "src/tint/utils/math/hash.h"
 
 namespace tint {
@@ -74,7 +74,7 @@
         /// trigger a TINT_ASSERT, or invalid pointer dereference.
         T* operator->() const {
             auto* hashmap_reference_lookup = Get();
-            TINT_ASSERT(Utils, hashmap_reference_lookup != nullptr);
+            TINT_ASSERT(hashmap_reference_lookup != nullptr);
             return hashmap_reference_lookup;
         }
 
diff --git a/src/tint/utils/containers/hashmap_base.h b/src/tint/utils/containers/hashmap_base.h
index a77299b..753564d 100644
--- a/src/tint/utils/containers/hashmap_base.h
+++ b/src/tint/utils/containers/hashmap_base.h
@@ -22,7 +22,7 @@
 #include <utility>
 
 #include "src/tint/utils/containers/vector.h"
-#include "src/tint/utils/debug/debug.h"
+#include "src/tint/utils/ice/ice.h"
 #include "src/tint/utils/math/hash.h"
 
 #define TINT_ASSERT_ITERATORS_NOT_INVALIDATED
@@ -194,8 +194,8 @@
         /// @returns the value pointed to by this iterator
         EntryRef<IS_CONST> operator->() const {
 #ifdef TINT_ASSERT_ITERATORS_NOT_INVALIDATED
-            TINT_ASSERT(Utils, map.Generation() == initial_generation &&
-                                   "iterator invalidated by container modification");
+            TINT_ASSERT(map.Generation() == initial_generation &&
+                        "iterator invalidated by container modification");
 #endif
             return *this;
         }
@@ -203,8 +203,8 @@
         /// @returns a reference to the value at the iterator
         EntryRef<IS_CONST> operator*() const {
 #ifdef TINT_ASSERT_ITERATORS_NOT_INVALIDATED
-            TINT_ASSERT(Utils, map.Generation() == initial_generation &&
-                                   "iterator invalidated by container modification");
+            TINT_ASSERT(map.Generation() == initial_generation &&
+                        "iterator invalidated by container modification");
 #endif
             auto& ref = current->entry.value();
             if constexpr (ValueIsVoid) {
@@ -218,8 +218,8 @@
         /// @returns this iterator
         IteratorT& operator++() {
 #ifdef TINT_ASSERT_ITERATORS_NOT_INVALIDATED
-            TINT_ASSERT(Utils, map.Generation() == initial_generation &&
-                                   "iterator invalidated by container modification");
+            TINT_ASSERT(map.Generation() == initial_generation &&
+                        "iterator invalidated by container modification");
 #endif
             if (current == end) {
                 return *this;
@@ -234,8 +234,8 @@
         /// @returns true if this iterator is equal to other
         bool operator==(const IteratorT& other) const {
 #ifdef TINT_ASSERT_ITERATORS_NOT_INVALIDATED
-            TINT_ASSERT(Utils, map.Generation() == initial_generation &&
-                                   "iterator invalidated by container modification");
+            TINT_ASSERT(map.Generation() == initial_generation &&
+                        "iterator invalidated by container modification");
 #endif
             return current == other.current;
         }
@@ -245,8 +245,8 @@
         /// @returns true if this iterator is not equal to other
         bool operator!=(const IteratorT& other) const {
 #ifdef TINT_ASSERT_ITERATORS_NOT_INVALIDATED
-            TINT_ASSERT(Utils, map.Generation() == initial_generation &&
-                                   "iterator invalidated by container modification");
+            TINT_ASSERT(map.Generation() == initial_generation &&
+                        "iterator invalidated by container modification");
 #endif
             return current != other.current;
         }
@@ -436,11 +436,11 @@
             if (slot.entry.has_value()) {
                 num_alive++;
                 auto const [index, hash] = Hash(KeyOf(*slot.entry));
-                TINT_ASSERT(Utils, hash == slot.hash);
-                TINT_ASSERT(Utils, slot_idx == Wrap(index + slot.distance));
+                TINT_ASSERT(hash == slot.hash);
+                TINT_ASSERT(slot_idx == Wrap(index + slot.distance));
             }
         }
-        TINT_ASSERT(Utils, num_alive == count_);
+        TINT_ASSERT(num_alive == count_);
     }
 
   protected:
@@ -530,8 +530,7 @@
             index = (index == count - 1) ? 0 : index + 1;
         }
 
-        tint::diag::List diags;
-        TINT_ICE(Utils, diags) << "HashmapBase::Put() looped entire map without finding a slot";
+        TINT_ICE() << "HashmapBase::Put() looped entire map without finding a slot";
         return PutResult{};
     }
 
@@ -581,8 +580,7 @@
             index = (index == count - 1) ? 0 : index + 1;
         }
 
-        tint::diag::List diags;
-        TINT_ICE(Utils, diags) << "HashmapBase::IndexOf() looped entire map without finding a slot";
+        TINT_ICE() << "HashmapBase::IndexOf() looped entire map without finding a slot";
         return {/* found */ false, /* index */ 0};
     }
 
diff --git a/src/tint/utils/containers/hashset.h b/src/tint/utils/containers/hashset.h
index e3bc40b..1203047 100644
--- a/src/tint/utils/containers/hashset.h
+++ b/src/tint/utils/containers/hashset.h
@@ -24,7 +24,6 @@
 
 #include "src/tint/utils/containers/hashmap.h"
 #include "src/tint/utils/containers/vector.h"
-#include "src/tint/utils/debug/debug.h"
 
 namespace tint {
 
diff --git a/src/tint/utils/containers/slice.h b/src/tint/utils/containers/slice.h
index 7097409..d25c1de 100644
--- a/src/tint/utils/containers/slice.h
+++ b/src/tint/utils/containers/slice.h
@@ -18,7 +18,7 @@
 #include <cstdint>
 #include <iterator>
 
-#include "src/tint/utils/debug/debug.h"
+#include "src/tint/utils/ice/ice.h"
 #include "src/tint/utils/memory/bitcast.h"
 #include "src/tint/utils/rtti/castable.h"
 #include "src/tint/utils/traits/traits.h"
@@ -188,7 +188,7 @@
     /// @param i the element index. Must be less than `len`.
     /// @returns a reference to the i'th element.
     T& operator[](size_t i) {
-        TINT_ASSERT(Utils, i < Length());
+        TINT_ASSERT(i < Length());
         return data[i];
     }
 
@@ -196,31 +196,31 @@
     /// @param i the element index. Must be less than `len`.
     /// @returns a reference to the i'th element.
     const T& operator[](size_t i) const {
-        TINT_ASSERT(Utils, i < Length());
+        TINT_ASSERT(i < Length());
         return data[i];
     }
 
     /// @returns a reference to the first element in the vector
     T& Front() {
-        TINT_ASSERT(Utils, !IsEmpty());
+        TINT_ASSERT(!IsEmpty());
         return data[0];
     }
 
     /// @returns a reference to the first element in the vector
     const T& Front() const {
-        TINT_ASSERT(Utils, !IsEmpty());
+        TINT_ASSERT(!IsEmpty());
         return data[0];
     }
 
     /// @returns a reference to the last element in the vector
     T& Back() {
-        TINT_ASSERT(Utils, !IsEmpty());
+        TINT_ASSERT(!IsEmpty());
         return data[len - 1];
     }
 
     /// @returns a reference to the last element in the vector
     const T& Back() const {
-        TINT_ASSERT(Utils, !IsEmpty());
+        TINT_ASSERT(!IsEmpty());
         return data[len - 1];
     }
 
diff --git a/src/tint/utils/containers/vector.h b/src/tint/utils/containers/vector.h
index 32d42e3..c437731 100644
--- a/src/tint/utils/containers/vector.h
+++ b/src/tint/utils/containers/vector.h
@@ -24,7 +24,7 @@
 #include <vector>
 
 #include "src/tint/utils/containers/slice.h"
-#include "src/tint/utils/debug/debug.h"
+#include "src/tint/utils/ice/ice.h"
 #include "src/tint/utils/macros/compiler.h"
 #include "src/tint/utils/memory/bitcast.h"
 #include "src/tint/utils/text/string_stream.h"
@@ -216,7 +216,7 @@
     /// @param i the element index. Must be less than `len`.
     /// @returns a reference to the i'th element.
     T& operator[](size_t i) {
-        TINT_ASSERT(Utils, i < Length());
+        TINT_ASSERT(i < Length());
         return impl_.slice[i];
     }
 
@@ -224,7 +224,7 @@
     /// @param i the element index. Must be less than `len`.
     /// @returns a reference to the i'th element.
     const T& operator[](size_t i) const {
-        TINT_ASSERT(Utils, i < Length());
+        TINT_ASSERT(i < Length());
         return impl_.slice[i];
     }
 
@@ -325,7 +325,7 @@
     /// Removes and returns the last element from the vector.
     /// @returns the popped element
     T Pop() {
-        TINT_ASSERT(Utils, !IsEmpty());
+        TINT_ASSERT(!IsEmpty());
         auto& el = impl_.slice.data[--impl_.slice.len];
         auto val = std::move(el);
         el.~T();
@@ -337,7 +337,7 @@
     /// @param element the element to insert
     template <typename EL>
     void Insert(size_t before, EL&& element) {
-        TINT_ASSERT(Utils, before <= Length());
+        TINT_ASSERT(before <= Length());
         size_t n = Length();
         Resize(Length() + 1);
         // Shuffle
@@ -354,8 +354,8 @@
     /// @param start the index of the first element to remove
     /// @param count the number of elements to remove
     void Erase(size_t start, size_t count = 1) {
-        TINT_ASSERT(Utils, start < Length());
-        TINT_ASSERT(Utils, (start + count) <= Length());
+        TINT_ASSERT(start < Length());
+        TINT_ASSERT((start + count) <= Length());
         // Shuffle
         for (size_t i = start + count; i < impl_.slice.len; i++) {
             auto& src = impl_.slice.data[i];
diff --git a/src/tint/utils/debug/debug.h b/src/tint/utils/debug/debug.h
deleted file mode 100644
index c039861..0000000
--- a/src/tint/utils/debug/debug.h
+++ /dev/null
@@ -1,156 +0,0 @@
-// Copyright 2021 The Tint Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef SRC_TINT_UTILS_DEBUG_DEBUG_H_
-#define SRC_TINT_UTILS_DEBUG_DEBUG_H_
-
-#include <utility>
-
-#include "src/tint/utils/diagnostic/diagnostic.h"
-#include "src/tint/utils/diagnostic/formatter.h"
-#include "src/tint/utils/diagnostic/printer.h"
-#include "src/tint/utils/macros/compiler.h"
-#include "src/tint/utils/text/string_stream.h"
-
-namespace tint {
-
-/// Function type used for registering an internal compiler error reporter
-using InternalCompilerErrorReporter = void(const diag::List&);
-
-/// Sets the global error reporter to be called in case of internal compiler
-/// errors.
-/// @param reporter the error reporter
-void SetInternalCompilerErrorReporter(InternalCompilerErrorReporter* reporter);
-
-/// InternalCompilerError is a helper for reporting internal compiler errors.
-/// Construct the InternalCompilerError with the source location of the ICE
-/// fault and append any error details with the `<<` operator.
-/// When the InternalCompilerError is destructed, the concatenated error message
-/// is appended to the diagnostics list with the severity of
-/// tint::diag::Severity::InternalCompilerError, and if a
-/// InternalCompilerErrorReporter is set, then it is called with the diagnostic
-/// list.
-class InternalCompilerError {
-  public:
-    /// Constructor
-    /// @param file the file containing the ICE
-    /// @param line the line containing the ICE
-    /// @param system the Tint system that has raised the ICE
-    /// @param diagnostics the list of diagnostics to append the ICE message to
-    InternalCompilerError(const char* file,
-                          size_t line,
-                          diag::System system,
-                          diag::List& diagnostics);
-
-    /// Destructor.
-    /// Adds the internal compiler error message to the diagnostics list, and then
-    /// calls the InternalCompilerErrorReporter if one is set.
-    ~InternalCompilerError();
-
-    /// Appends `arg` to the ICE message.
-    /// @param arg the argument to append to the ICE message
-    /// @returns this object so calls can be chained
-    template <typename T>
-    InternalCompilerError& operator<<(T&& arg) {
-        msg_ << std::forward<T>(arg);
-        return *this;
-    }
-
-  private:
-    char const* const file_;
-    const size_t line_;
-    diag::System system_;
-    diag::List& diagnostics_;
-    StringStream msg_;
-};
-
-}  // namespace tint
-
-/// TINT_ICE() is a macro for appending an internal compiler error message
-/// to the diagnostics list `diagnostics`, and calling the
-/// InternalCompilerErrorReporter with the full diagnostic list if a reporter is
-/// set.
-/// The ICE message contains the callsite's file and line.
-/// Use the `<<` operator to append an error message to the ICE.
-#define TINT_ICE(system, diagnostics) \
-    tint::InternalCompilerError(__FILE__, __LINE__, ::tint::diag::System::system, diagnostics)
-
-/// TINT_UNREACHABLE() is a macro for appending a "TINT_UNREACHABLE"
-/// internal compiler error message to the diagnostics list `diagnostics`, and
-/// calling the InternalCompilerErrorReporter with the full diagnostic list if a
-/// reporter is set.
-/// The ICE message contains the callsite's file and line.
-/// Use the `<<` operator to append an error message to the ICE.
-#define TINT_UNREACHABLE(system, diagnostics) TINT_ICE(system, diagnostics) << "TINT_UNREACHABLE "
-
-/// TINT_UNIMPLEMENTED() is a macro for appending a "TINT_UNIMPLEMENTED"
-/// internal compiler error message to the diagnostics list `diagnostics`, and
-/// calling the InternalCompilerErrorReporter with the full diagnostic list if a
-/// reporter is set.
-/// The ICE message contains the callsite's file and line.
-/// Use the `<<` operator to append an error message to the ICE.
-#define TINT_UNIMPLEMENTED(system, diagnostics) \
-    TINT_ICE(system, diagnostics) << "TINT_UNIMPLEMENTED "
-
-/// TINT_ASSERT() is a macro for checking the expression is true, triggering a
-/// TINT_ICE if it is not.
-/// The ICE message contains the callsite's file and line.
-/// @warning: Unlike TINT_ICE() and TINT_UNREACHABLE(), TINT_ASSERT() does not
-/// append a message to an existing tint::diag::List. As such, TINT_ASSERT()
-/// may silently fail in builds where SetInternalCompilerErrorReporter() is not
-/// called. Only use in places where there's no sensible place to put proper
-/// error handling.
-#define TINT_ASSERT(system, condition)                                                   \
-    do {                                                                                 \
-        if (TINT_UNLIKELY(!(condition))) {                                               \
-            tint::diag::List diagnostics;                                                \
-            TINT_ICE(system, diagnostics) << "TINT_ASSERT(" #system ", " #condition ")"; \
-        }                                                                                \
-    } 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.
-/// @warning: Unlike TINT_ICE() and TINT_UNREACHABLE(), TINT_ASSERT_OR_RETURN() does not
-/// append a message to an existing tint::diag::List. As such, TINT_ASSERT_OR_RETURN()
-/// may silently fail in builds where SetInternalCompilerErrorReporter() is not
-/// called. Only use in places where there's no sensible place to put proper
-/// error handling.
-#define TINT_ASSERT_OR_RETURN(system, condition)                                         \
-    do {                                                                                 \
-        if (TINT_UNLIKELY(!(condition))) {                                               \
-            tint::diag::List diagnostics;                                                \
-            TINT_ICE(system, diagnostics) << "TINT_ASSERT(" #system ", " #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.
-/// @warning: Unlike TINT_ICE() and TINT_UNREACHABLE(), TINT_ASSERT_OR_RETURN_VALUE() does not
-/// append a message to an existing tint::diag::List. As such, TINT_ASSERT_OR_RETURN_VALUE()
-/// may silently fail in builds where SetInternalCompilerErrorReporter() is not
-/// called. Only use in places where there's no sensible place to put proper
-/// error handling.
-#define TINT_ASSERT_OR_RETURN_VALUE(system, condition, value)                            \
-    do {                                                                                 \
-        if (TINT_UNLIKELY(!(condition))) {                                               \
-            tint::diag::List diagnostics;                                                \
-            TINT_ICE(system, diagnostics) << "TINT_ASSERT(" #system ", " #condition ")"; \
-            return value;                                                                \
-        }                                                                                \
-    } while (false)
-
-#endif  // SRC_TINT_UTILS_DEBUG_DEBUG_H_
diff --git a/src/tint/utils/file/tmpfile_posix.cc b/src/tint/utils/file/tmpfile_posix.cc
index 9d6505b..47b92c1 100644
--- a/src/tint/utils/file/tmpfile_posix.cc
+++ b/src/tint/utils/file/tmpfile_posix.cc
@@ -17,7 +17,7 @@
 #include <unistd.h>
 #include <limits>
 
-#include "src/tint/utils/debug/debug.h"
+#include "src/tint/utils/ice/ice.h"
 
 namespace tint {
 
@@ -34,7 +34,7 @@
     // (when the source value exceeds the representable range) is implementation
     // defined. While such a large file extension is unlikely in practice, we
     // enforce this here at runtime.
-    TINT_ASSERT(Utils, ext.length() <= static_cast<size_t>(std::numeric_limits<int>::max()));
+    TINT_ASSERT(ext.length() <= static_cast<size_t>(std::numeric_limits<int>::max()));
     std::string name = std::string(dir) + "/tint_XXXXXX" + ext;
     int file = mkstemps(&name[0], static_cast<int>(ext.length()));
     if (file != -1) {
diff --git a/src/tint/utils/generation_id.cc b/src/tint/utils/generation_id.cc
index bbcc984..b0b9a60 100644
--- a/src/tint/utils/generation_id.cc
+++ b/src/tint/utils/generation_id.cc
@@ -40,7 +40,6 @@
 void AssertGenerationIDsEqual(GenerationID a,
                               GenerationID b,
                               bool if_valid,
-                              diag::System system,
                               const char* msg,
                               const char* file,
                               size_t line) {
@@ -50,8 +49,7 @@
     if (if_valid && (!a || !b)) {
         return;  //  a or b were not valid
     }
-    diag::List diagnostics;
-    tint::InternalCompilerError(file, line, system, diagnostics) << msg;
+    tint::InternalCompilerError(file, line) << msg;
 }
 
 }  // namespace detail
diff --git a/src/tint/utils/generation_id.h b/src/tint/utils/generation_id.h
index fd8455a..6a9249b 100644
--- a/src/tint/utils/generation_id.h
+++ b/src/tint/utils/generation_id.h
@@ -18,7 +18,7 @@
 #include <stdint.h>
 #include <utility>
 
-#include "src/tint/utils/debug/debug.h"
+#include "src/tint/utils/ice/ice.h"
 #include "src/tint/utils/text/string_stream.h"
 
 namespace tint {
@@ -88,7 +88,6 @@
 void AssertGenerationIDsEqual(GenerationID a,
                               GenerationID b,
                               bool if_valid,
-                              diag::System system,
                               const char* msg,
                               const char* file,
                               size_t line);
@@ -102,15 +101,14 @@
 /// that the generation identifiers for A and B are equal, if both A and B have
 /// valid generation identifiers.
 #if TINT_CHECK_FOR_CROSS_GENERATION_LEAKS
-#define TINT_ASSERT_GENERATION_IDS_EQUAL(system, a, b)                           \
-    tint::detail::AssertGenerationIDsEqual(                                      \
-        GenerationIDOf(a), GenerationIDOf(b), false, tint::diag::System::system, \
-        "TINT_ASSERT_GENERATION_IDS_EQUAL(" #system "," #a ", " #b ")", __FILE__, __LINE__)
-#define TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(system, a, b)                             \
-    tint::detail::AssertGenerationIDsEqual(                                                 \
-        GenerationIDOf(a), GenerationIDOf(b), true, tint::diag::System::system,             \
-        "TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(" #system ", " #a ", " #b ")", __FILE__, \
-        __LINE__)
+#define TINT_ASSERT_GENERATION_IDS_EQUAL(a, b)                                                 \
+    tint::detail::AssertGenerationIDsEqual(GenerationIDOf(a), GenerationIDOf(b), false,        \
+                                           "TINT_ASSERT_GENERATION_IDS_EQUAL(" #a ", " #b ")", \
+                                           __FILE__, __LINE__)
+#define TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(a, b) \
+    tint::detail::AssertGenerationIDsEqual(             \
+        GenerationIDOf(a), GenerationIDOf(b), true,     \
+        "TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(" #a ", " #b ")", __FILE__, __LINE__)
 #else
 #define TINT_ASSERT_GENERATION_IDS_EQUAL(a, b) \
     do {                                       \
diff --git a/src/tint/utils/debug/debug.cc b/src/tint/utils/ice/ice.cc
similarity index 62%
rename from src/tint/utils/debug/debug.cc
rename to src/tint/utils/ice/ice.cc
index c5c07f1..df5c567 100644
--- a/src/tint/utils/debug/debug.cc
+++ b/src/tint/utils/ice/ice.cc
@@ -12,9 +12,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/utils/debug/debug.h"
+#include "src/tint/utils/ice/ice.h"
 
 #include <memory>
+#include <string>
 
 #include "src/tint/utils/debug/debugger.h"
 
@@ -29,22 +30,19 @@
     ice_reporter = reporter;
 }
 
-InternalCompilerError::InternalCompilerError(const char* file,
-                                             size_t line,
-                                             diag::System system,
-                                             diag::List& diagnostics)
-    : file_(file), line_(line), system_(system), diagnostics_(diagnostics) {}
+InternalCompilerError::InternalCompilerError(const char* file, size_t line)
+    : file_(file), line_(line) {}
 
 InternalCompilerError::~InternalCompilerError() {
-    auto file = std::make_shared<Source::File>(file_, "");
-    Source source{Source::Range{{line_}}, file.get()};
-    diagnostics_.add_ice(system_, msg_.str(), source, std::move(file));
-
     if (ice_reporter) {
-        ice_reporter(diagnostics_);
+        ice_reporter(*this);
     }
-
     debugger::Break();
 }
 
+std::string InternalCompilerError::Error() const {
+    return std::string(File()) + +":" + std::to_string(Line()) +
+           " internal compiler error: " + Message();
+}
+
 }  // namespace tint
diff --git a/src/tint/utils/ice/ice.h b/src/tint/utils/ice/ice.h
new file mode 100644
index 0000000..63966f7
--- /dev/null
+++ b/src/tint/utils/ice/ice.h
@@ -0,0 +1,127 @@
+// Copyright 2021 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SRC_TINT_UTILS_ICE_ICE_H_
+#define SRC_TINT_UTILS_ICE_ICE_H_
+
+#include <sstream>
+#include <string>
+#include <utility>
+
+#include "src/tint/utils/macros/compiler.h"
+#include "src/tint/utils/text/string_stream.h"
+
+namespace tint {
+
+/// InternalCompilerError is a helper for reporting internal compiler errors.
+/// Construct the InternalCompilerError with the source location of the ICE fault and append any
+/// error details with the `<<` operator. When the InternalCompilerError is destructed, the
+/// concatenated error message is passed to the InternalCompilerErrorReporter.
+class InternalCompilerError {
+  public:
+    /// Constructor
+    /// @param file the file containing the ICE
+    /// @param line the line containing the ICE
+    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();
+
+    /// Appends `arg` to the ICE message.
+    /// @param arg the argument to append to the ICE message
+    /// @returns this object so calls can be chained
+    template <typename T>
+    InternalCompilerError& operator<<(T&& arg) {
+        msg_ << std::forward<T>(arg);
+        return *this;
+    }
+
+    /// @returns the file that triggered the ICE
+    const char* File() const { return file_; }
+
+    /// @returns the line that triggered the ICE
+    size_t Line() const { return line_; }
+
+    /// @returns the ICE message
+    std::string Message() const { return msg_.str(); }
+
+    /// @returns the ICE file, line and message
+    std::string Error() const;
+
+  private:
+    char const* const file_;
+    const size_t line_;
+    StringStream msg_;
+};
+
+/// Function type used for registering an internal compiler error reporter
+using InternalCompilerErrorReporter = void(const InternalCompilerError&);
+
+/// Sets the global error reporter to be called in case of internal compiler
+/// errors.
+/// @param reporter the error reporter
+void SetInternalCompilerErrorReporter(InternalCompilerErrorReporter* reporter);
+
+}  // namespace tint
+
+/// TINT_ICE() is a macro to invoke the InternalCompilerErrorReporter for an Internal Compiler
+/// Error. The ICE message contains the callsite's file and line. Use the `<<` operator to append an
+/// error message to the ICE.
+#define TINT_ICE() tint::InternalCompilerError(__FILE__, __LINE__)
+
+/// TINT_UNREACHABLE() is a macro invoke the InternalCompilerErrorReporter when an expectedly
+/// unreachable statement is reached. The ICE message contains the callsite's file and line. Use the
+/// `<<` operator to append an error message to the ICE.
+#define TINT_UNREACHABLE() TINT_ICE() << "TINT_UNREACHABLE "
+
+/// TINT_UNIMPLEMENTED() is a macro to invoke the InternalCompilerErrorReporter when unimplemented
+/// code is executed. The ICE message contains the callsite's file and line. Use the `<<` operator
+/// to append an error message to the ICE.
+#define TINT_UNIMPLEMENTED() TINT_ICE() << "TINT_UNIMPLEMENTED "
+
+/// TINT_ASSERT() is a macro for checking the expression is true, triggering a
+/// TINT_ICE if it is not.
+/// The ICE message contains the callsite's file and line.
+#define TINT_ASSERT(condition)                           \
+    do {                                                 \
+        if (TINT_UNLIKELY(!(condition))) {               \
+            TINT_ICE() << "TINT_ASSERT(" #condition ")"; \
+        }                                                \
+    } 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/debug/debug_test.cc b/src/tint/utils/ice/ice_test.cc
similarity index 62%
rename from src/tint/utils/debug/debug_test.cc
rename to src/tint/utils/ice/ice_test.cc
index 3566427..36c4e17 100644
--- a/src/tint/utils/debug/debug_test.cc
+++ b/src/tint/utils/ice/ice_test.cc
@@ -12,28 +12,23 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/utils/debug/debug.h"
+#include "src/tint/utils/ice/ice.h"
 
 #include "gtest/gtest-spi.h"
 
 namespace tint {
 namespace {
 
-TEST(DebugTest, Unreachable) {
-    EXPECT_FATAL_FAILURE(
-        {
-            diag::List diagnostics;
-            TINT_UNREACHABLE(Test, diagnostics);
-        },
-        "internal compiler error");
+TEST(ICETest_AssertTrue_Test, Unreachable) {
+    EXPECT_FATAL_FAILURE({ TINT_UNREACHABLE(); }, "internal compiler error");
 }
 
-TEST(DebugTest, AssertTrue) {
-    TINT_ASSERT(Test, true);
+TEST(ICETest_AssertTrue_Test, AssertTrue) {
+    TINT_ASSERT(true);
 }
 
-TEST(DebugTest, AssertFalse) {
-    EXPECT_FATAL_FAILURE({ TINT_ASSERT(Test, false); }, "internal compiler error");
+TEST(ICETest_AssertTrue_Test, AssertFalse) {
+    EXPECT_FATAL_FAILURE({ TINT_ASSERT(false); }, "internal compiler error");
 }
 
 }  // namespace
diff --git a/src/tint/utils/result/result.h b/src/tint/utils/result/result.h
index ee87ecd..ad7e864 100644
--- a/src/tint/utils/result/result.h
+++ b/src/tint/utils/result/result.h
@@ -18,7 +18,7 @@
 #include <utility>
 #include <variant>
 
-#include "src/tint/utils/debug/debug.h"
+#include "src/tint/utils/ice/ice.h"
 #include "src/tint/utils/text/string_stream.h"
 
 namespace tint {
@@ -152,7 +152,7 @@
     }
 
   private:
-    void Validate() const { TINT_ASSERT(Utils, !std::holds_alternative<std::monostate>(value)); }
+    void Validate() const { TINT_ASSERT(!std::holds_alternative<std::monostate>(value)); }
 
     /// The result. Either a success of failure value.
     std::variant<std::monostate, SUCCESS_TYPE, FAILURE_TYPE> value;
diff --git a/src/tint/utils/text/float_to_string.cc b/src/tint/utils/text/float_to_string.cc
index cfbfc00..462af68 100644
--- a/src/tint/utils/text/float_to_string.cc
+++ b/src/tint/utils/text/float_to_string.cc
@@ -20,7 +20,7 @@
 #include <iomanip>
 #include <limits>
 
-#include "src/tint/utils/debug/debug.h"
+#include "src/tint/utils/ice/ice.h"
 #include "src/tint/utils/text/string_stream.h"
 
 namespace tint::writer {
@@ -122,7 +122,7 @@
                 }
             } else {
                 // Subnormal, and not zero.
-                TINT_ASSERT(Writer, mantissa != 0);
+                TINT_ASSERT(mantissa != 0);
                 const auto kTopBit = static_cast<uint_t>(1u) << T::kMantissaBits;
 
                 // Shift left until we get 1.x
diff --git a/src/tint/utils/text/symbol.cc b/src/tint/utils/text/symbol.cc
index 7b51f7f..336083f 100644
--- a/src/tint/utils/text/symbol.cc
+++ b/src/tint/utils/text/symbol.cc
@@ -34,17 +34,17 @@
 Symbol& Symbol::operator=(Symbol&& o) = default;
 
 bool Symbol::operator==(const Symbol& other) const {
-    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(Symbol, generation_id_, other.generation_id_);
+    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(generation_id_, other.generation_id_);
     return val_ == other.val_;
 }
 
 bool Symbol::operator!=(const Symbol& other) const {
-    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(Symbol, generation_id_, other.generation_id_);
+    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(generation_id_, other.generation_id_);
     return val_ != other.val_;
 }
 
 bool Symbol::operator<(const Symbol& other) const {
-    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(Symbol, generation_id_, other.generation_id_);
+    TINT_ASSERT_GENERATION_IDS_EQUAL_IF_VALID(generation_id_, other.generation_id_);
     return val_ < other.val_;
 }
 
diff --git a/src/tint/utils/text/symbol_table.cc b/src/tint/utils/text/symbol_table.cc
index 5bfca8c0..9276232 100644
--- a/src/tint/utils/text/symbol_table.cc
+++ b/src/tint/utils/text/symbol_table.cc
@@ -14,7 +14,7 @@
 
 #include "src/tint/utils/text/symbol_table.h"
 
-#include "src/tint/utils/debug/debug.h"
+#include "src/tint/utils/ice/ice.h"
 
 namespace tint {
 
@@ -27,7 +27,7 @@
 SymbolTable& SymbolTable::operator=(SymbolTable&&) = default;
 
 Symbol SymbolTable::Register(std::string_view name) {
-    TINT_ASSERT(Symbol, !name.empty());
+    TINT_ASSERT(!name.empty());
 
     auto it = name_to_symbol_.Find(name);
     if (it) {
diff --git a/src/tint/utils/text/text_generator.cc b/src/tint/utils/text/text_generator.cc
index dec64b0..e3d1a0a 100644
--- a/src/tint/utils/text/text_generator.cc
+++ b/src/tint/utils/text/text_generator.cc
@@ -18,7 +18,7 @@
 #include <limits>
 
 #include "src/tint/utils/containers/map.h"
-#include "src/tint/utils/debug/debug.h"
+#include "src/tint/utils/ice/ice.h"
 
 namespace tint {
 
@@ -27,7 +27,7 @@
 TextGenerator::~TextGenerator() = default;
 
 std::string TextGenerator::UniqueIdentifier(const std::string& /* = "" */) {
-    TINT_UNIMPLEMENTED(Utils, diagnostics_) << "UniqueIdentifier() not overridden";
+    TINT_UNIMPLEMENTED() << "UniqueIdentifier() not overridden";
     return "<error>";
 }
 
@@ -70,10 +70,9 @@
 
 void TextGenerator::TextBuffer::Insert(const std::string& line, size_t before, uint32_t indent) {
     if (TINT_UNLIKELY(before >= lines.size())) {
-        diag::List d;
-        TINT_ICE(Writer, d) << "TextBuffer::Insert() called with before >= lines.size()\n"
-                            << "  before:" << before << "\n"
-                            << "  lines.size(): " << lines.size();
+        TINT_ICE() << "TextBuffer::Insert() called with before >= lines.size()\n"
+                   << "  before:" << before << "\n"
+                   << "  lines.size(): " << lines.size();
         return;
     }
     using DT = decltype(lines)::difference_type;
@@ -89,10 +88,9 @@
 
 void TextGenerator::TextBuffer::Insert(const TextBuffer& tb, size_t before, uint32_t indent) {
     if (TINT_UNLIKELY(before >= lines.size())) {
-        diag::List d;
-        TINT_ICE(Writer, d) << "TextBuffer::Insert() called with before >= lines.size()\n"
-                            << "  before:" << before << "\n"
-                            << "  lines.size(): " << lines.size();
+        TINT_ICE() << "TextBuffer::Insert() called with before >= lines.size()\n"
+                   << "  before:" << before << "\n"
+                   << "  lines.size(): " << lines.size();
         return;
     }
     size_t idx = 0;