Просмотр исходного кода

Switch `CARBON_CHECK` to a format string API (#4285)

This switches `DCHECK` and `FATAL` as well.

The goal is to reduce the code size impact of these assertions so that
we can keep more of them enabled. Currently, the largest cost I see from
`CHECK` is not the actual check or the cold code itself, but actually
the failure to inline trivial functions due to the presence of the cold
code. This means that our goal isn't to reduce apparent code size in the
final binary but the LLVM IR cost assessed for these routines in the
inliner, which closely correlates with code size but is a bit different.

As discussed in #4283, experimentation shows that a single function call
with a minimal number of arguments is the lowest cost model for these.
This is easily achieved with a format-string API that internally uses
`llvm::formatv`. This PR is essentially the `CHECK` version of #4283.

However, the check macros are substantially harder to make work with
both format strings and streaming because they also take a condition.
Also, unexpectedly, I was very successful at devising a regular
expression based automated rewrite from the streaming to the format
string form with only low 10s of manual fixes. This includes compacting
strings broken up across lines, etc. Given how well that went, I've
prepared this PR which just directly switches to the format string API
and migrate everything to use it.

One nice side-effect is that the format string approach ends up greatly
simplifying the implementation here as well.

This is ... *shockingly* effective. Parsing speeds up by more than 3%
with just this change. And checking speeds up by **8%** with this change
alone:
```
BM_CompileAPIFileDenseDecls<Phase::Parse>/256      86.3µs ± 1%  82.9µs ± 1%  -3.94%  (p=0.000 n=17+19)
BM_CompileAPIFileDenseDecls<Phase::Parse>/1024      431µs ± 1%   415µs ± 1%  -3.76%  (p=0.000 n=18+19)
BM_CompileAPIFileDenseDecls<Phase::Parse>/4096     1.77ms ± 1%  1.71ms ± 1%  -3.18%  (p=0.000 n=18+19)
BM_CompileAPIFileDenseDecls<Phase::Parse>/16384    7.44ms ± 1%  7.17ms ± 2%  -3.56%  (p=0.000 n=18+20)
BM_CompileAPIFileDenseDecls<Phase::Parse>/65536    30.7ms ± 1%  29.7ms ± 1%  -3.15%  (p=0.000 n=18+20)
BM_CompileAPIFileDenseDecls<Phase::Parse>/262144    131ms ± 1%   127ms ± 1%  -2.81%  (p=0.000 n=18+18)
BM_CompileAPIFileDenseDecls<Phase::Check>/256       878µs ± 2%   800µs ± 1%  -8.91%  (p=0.000 n=19+20)
BM_CompileAPIFileDenseDecls<Phase::Check>/1024     1.88ms ± 2%  1.72ms ± 1%  -8.56%  (p=0.000 n=19+20)
BM_CompileAPIFileDenseDecls<Phase::Check>/4096     5.78ms ± 2%  5.28ms ± 1%  -8.70%  (p=0.000 n=20+18)
BM_CompileAPIFileDenseDecls<Phase::Check>/16384    21.9ms ± 1%  20.1ms ± 1%  -8.02%  (p=0.000 n=18+20)
BM_CompileAPIFileDenseDecls<Phase::Check>/65536    90.4ms ± 2%  83.1ms ± 1%  -8.04%  (p=0.000 n=19+20)
BM_CompileAPIFileDenseDecls<Phase::Check>/262144    381ms ± 2%   352ms ± 1%  -7.79%  (p=0.000 n=19+19)
```

---------

Co-authored-by: Richard Smith <richard@metafoo.co.uk>
Co-authored-by: josh11b <15258583+josh11b@users.noreply.github.com>
Chandler Carruth 1 год назад
Родитель
Сommit
4845f40dff
100 измененных файлов с 982 добавлено и 913 удалено
  1. 2 0
      common/BUILD
  2. 4 4
      common/array_stack.h
  3. 26 16
      common/check.h
  4. 14 16
      common/check_internal.cpp
  5. 94 61
      common/check_internal.h
  6. 15 6
      common/check_test.cpp
  7. 77 71
      common/command_line.cpp
  8. 4 4
      common/command_line.h
  9. 1 1
      common/error.h
  10. 1 1
      common/hashing_test.cpp
  11. 2 2
      common/map.h
  12. 3 3
      common/map_benchmark.cpp
  13. 24 22
      common/raw_hashtable.h
  14. 4 3
      common/raw_hashtable_benchmark_helpers.cpp
  15. 53 48
      common/raw_hashtable_metadata_group.h
  16. 1 1
      common/set.h
  17. 3 3
      common/set_benchmark.cpp
  18. 3 3
      explorer/ast/bindings.cpp
  19. 5 5
      explorer/ast/clone_context.cpp
  20. 1 1
      explorer/ast/clone_context.h
  21. 1 1
      explorer/ast/declaration.cpp
  22. 3 3
      explorer/ast/declaration.h
  23. 2 2
      explorer/ast/element_path.h
  24. 1 2
      explorer/ast/expression.cpp
  25. 4 3
      explorer/ast/expression.h
  26. 3 3
      explorer/ast/impl_binding.h
  27. 2 2
      explorer/ast/pattern.h
  28. 3 3
      explorer/ast/statement.h
  29. 2 2
      explorer/ast/static_scope.cpp
  30. 22 24
      explorer/ast/value.cpp
  31. 10 10
      explorer/ast/value.h
  32. 2 2
      explorer/file_test.cpp
  33. 9 9
      explorer/fuzzing/ast_to_proto.cpp
  34. 2 2
      explorer/fuzzing/fuzzer_util.cpp
  35. 8 8
      explorer/interpreter/action.cpp
  36. 1 1
      explorer/interpreter/action.h
  37. 7 7
      explorer/interpreter/action_stack.cpp
  38. 2 2
      explorer/interpreter/heap.cpp
  39. 7 7
      explorer/interpreter/impl_scope.cpp
  40. 70 68
      explorer/interpreter/interpreter.cpp
  41. 1 1
      explorer/interpreter/matching_impl_set.cpp
  42. 12 13
      explorer/interpreter/pattern_match.cpp
  43. 7 7
      explorer/interpreter/resolve_names.cpp
  44. 2 2
      explorer/interpreter/resolve_unformed.cpp
  45. 5 5
      explorer/interpreter/stack.h
  46. 67 65
      explorer/interpreter/type_checker.cpp
  47. 2 2
      explorer/interpreter/type_utils.cpp
  48. 2 2
      explorer/syntax/parse.cpp
  49. 1 2
      explorer/syntax/prelude.cpp
  50. 2 2
      migrate_cpp/rewriter_test.cpp
  51. 4 3
      testing/base/global_exe_path.cpp
  52. 21 21
      testing/base/source_gen.cpp
  53. 13 13
      testing/file_test/autoupdate.cpp
  54. 6 5
      testing/file_test/autoupdate.h
  55. 3 3
      testing/file_test/file_test_base.cpp
  56. 3 3
      toolchain/base/value_store.h
  57. 1 1
      toolchain/base/yaml.h
  58. 19 20
      toolchain/check/check.cpp
  59. 1 1
      toolchain/check/check_fuzzer.cpp
  60. 31 30
      toolchain/check/context.cpp
  61. 1 2
      toolchain/check/context.h
  62. 13 16
      toolchain/check/convert.cpp
  63. 2 3
      toolchain/check/decl_introducer_state.h
  64. 24 24
      toolchain/check/decl_name_stack.cpp
  65. 4 4
      toolchain/check/deduce.cpp
  66. 22 21
      toolchain/check/eval.cpp
  67. 26 24
      toolchain/check/generic.cpp
  68. 4 4
      toolchain/check/handle_binding_pattern.cpp
  69. 4 4
      toolchain/check/handle_class.cpp
  70. 1 1
      toolchain/check/handle_if_statement.cpp
  71. 2 2
      toolchain/check/handle_interface.cpp
  72. 2 2
      toolchain/check/handle_let_and_var.cpp
  73. 1 1
      toolchain/check/handle_name.cpp
  74. 2 2
      toolchain/check/handle_noop.cpp
  75. 2 2
      toolchain/check/handle_struct.cpp
  76. 10 10
      toolchain/check/impl.cpp
  77. 6 6
      toolchain/check/import.cpp
  78. 18 18
      toolchain/check/import_ref.cpp
  79. 5 5
      toolchain/check/inst_block_stack.cpp
  80. 3 3
      toolchain/check/inst_block_stack.h
  81. 12 11
      toolchain/check/lexical_lookup.h
  82. 5 6
      toolchain/check/member_access.cpp
  83. 6 6
      toolchain/check/merge.cpp
  84. 1 1
      toolchain/check/node_stack.cpp
  85. 19 20
      toolchain/check/node_stack.h
  86. 4 4
      toolchain/check/return.cpp
  87. 32 30
      toolchain/check/scope_stack.cpp
  88. 6 6
      toolchain/check/sem_ir_diagnostic_converter.cpp
  89. 6 6
      toolchain/check/subst.cpp
  90. 9 8
      toolchain/diagnostics/diagnostic_emitter.h
  91. 2 2
      toolchain/diagnostics/sorting_diagnostic_consumer.h
  92. 1 1
      toolchain/docs/idioms.md
  93. 1 1
      toolchain/driver/clang_runner.cpp
  94. 1 1
      toolchain/driver/clang_runner_test.cpp
  95. 2 2
      toolchain/driver/driver.cpp
  96. 1 1
      toolchain/driver/driver_fuzzer.cpp
  97. 10 9
      toolchain/driver/driver_test.cpp
  98. 3 3
      toolchain/install/install_paths.cpp
  99. 5 5
      toolchain/install/install_paths_test.cpp
  100. 3 3
      toolchain/install/install_paths_test_helpers.cpp

+ 2 - 0
common/BUILD

@@ -68,6 +68,7 @@ cc_library(
     hdrs = ["check.h"],
     hdrs = ["check.h"],
     deps = [
     deps = [
         ":ostream",
         ":ostream",
+        ":template_string",
         "@llvm-project//llvm:Support",
         "@llvm-project//llvm:Support",
     ],
     ],
 )
 )
@@ -329,6 +330,7 @@ cc_library(
     hdrs = ["raw_hashtable_metadata_group.h"],
     hdrs = ["raw_hashtable_metadata_group.h"],
     deps = [
     deps = [
         ":check",
         ":check",
+        ":ostream",
         "@llvm-project//llvm:Support",
         "@llvm-project//llvm:Support",
     ],
     ],
 )
 )

+ 4 - 4
common/array_stack.h

@@ -62,15 +62,15 @@ class ArrayStack {
 
 
   // Appends a value to the top array on the stack.
   // Appends a value to the top array on the stack.
   auto AppendToTop(ValueT value) -> void {
   auto AppendToTop(ValueT value) -> void {
-    CARBON_CHECK(!array_offsets_.empty())
-        << "Must call PushArray before PushValue.";
+    CARBON_CHECK(!array_offsets_.empty(),
+                 "Must call PushArray before PushValue.");
     values_.push_back(value);
     values_.push_back(value);
   }
   }
 
 
   // Adds multiple values to the top array on the stack.
   // Adds multiple values to the top array on the stack.
   auto AppendToTop(llvm::ArrayRef<ValueT> values) -> void {
   auto AppendToTop(llvm::ArrayRef<ValueT> values) -> void {
-    CARBON_CHECK(!array_offsets_.empty())
-        << "Must call PushArray before PushValues.";
+    CARBON_CHECK(!array_offsets_.empty(),
+                 "Must call PushArray before PushValues.");
     values_.append(values.begin(), values.end());
     values_.append(values.begin(), values.end());
   }
   }
 
 

+ 26 - 16
common/check.h

@@ -14,30 +14,40 @@ namespace Carbon {
 // a bug in the application.
 // a bug in the application.
 //
 //
 // For example:
 // For example:
-//   CARBON_CHECK(is_valid) << "Data is not valid!";
-#define CARBON_CHECK(...)                                                   \
-  (__VA_ARGS__) ? (void)0                                                   \
-                : CARBON_CHECK_INTERNAL_STREAM()                            \
-                      << "CHECK failure at " << __FILE__ << ":" << __LINE__ \
-                      << ": " #__VA_ARGS__                                  \
-                      << Carbon::Internal::ExitingStream::AddSeparator()
+//   CARBON_CHECK(is_valid, "Data is not valid!");
+//
+// The condition must be parenthesized if it contains top-level commas, for
+// example in a template argument list:
+//   CARBON_CHECK((inst.IsOneOf<Call, TupleLiteral>()),
+//                "Unexpected inst {0}", inst);
+#define CARBON_CHECK(condition, ...) \
+  (condition) ? (void)0              \
+              : CARBON_INTERNAL_CHECK(condition __VA_OPT__(, ) __VA_ARGS__)
 
 
 // DCHECK calls CHECK in debug mode, and does nothing otherwise.
 // DCHECK calls CHECK in debug mode, and does nothing otherwise.
 #ifndef NDEBUG
 #ifndef NDEBUG
-#define CARBON_DCHECK(...) CARBON_CHECK(__VA_ARGS__)
+#define CARBON_DCHECK(condition, ...) \
+  CARBON_CHECK(condition __VA_OPT__(, ) __VA_ARGS__)
 #else
 #else
-#define CARBON_DCHECK(...) CARBON_CHECK(true || (__VA_ARGS__))
+// When in a debug build we want to preserve as much as we can of how the
+// parameters are used, other than making them be trivially in dead code and
+// eliminated by the optimizer. As a consequence we preserve the condition but
+// prefix it with a short-circuit operator, and we still emit the (dead) call to
+// the check implementation. But we use a special implementation that reduces
+// the compile time cost.
+#define CARBON_DCHECK(condition, ...) \
+  (true || (condition))               \
+      ? (void)0                       \
+      : CARBON_INTERNAL_DEAD_DCHECK(condition __VA_OPT__(, ) __VA_ARGS__)
 #endif
 #endif
 
 
-// This is similar to CHECK, but is unconditional. Writing CARBON_FATAL() is
-// clearer than CARBON_CHECK(false) because it avoids confusion about control
-// flow.
+// This is similar to CHECK, but is unconditional. Writing
+// `CARBON_FATAL("message")` is clearer than `CARBON_CHECK(false, "message")
+// because it avoids confusion about control flow.
 //
 //
 // For example:
 // For example:
-//   CARBON_FATAL() << "Unreachable!";
-#define CARBON_FATAL()           \
-  CARBON_CHECK_INTERNAL_STREAM() \
-      << "FATAL failure at " << __FILE__ << ":" << __LINE__ << ": "
+//   CARBON_FATAL("Unreachable!");
+#define CARBON_FATAL(...) CARBON_INTERNAL_FATAL(__VA_ARGS__)
 
 
 }  // namespace Carbon
 }  // namespace Carbon
 
 

+ 14 - 16
common/check_internal.cpp

@@ -4,7 +4,7 @@
 
 
 #include "common/check_internal.h"
 #include "common/check_internal.h"
 
 
-#include "llvm/Support/ErrorHandling.h"
+#include "common/ostream.h"
 #include "llvm/Support/Signals.h"
 #include "llvm/Support/Signals.h"
 
 
 namespace Carbon::Internal {
 namespace Carbon::Internal {
@@ -14,22 +14,20 @@ static auto PrintAfterStackTrace(void* str) -> void {
   llvm::errs() << reinterpret_cast<char*>(str);
   llvm::errs() << reinterpret_cast<char*>(str);
 }
 }
 
 
-ExitingStream::~ExitingStream() {
-  llvm_unreachable(
-      "Exiting streams should only be constructed by check.h macros that "
-      "ensure the special operator| exits the program prior to their "
-      "destruction!");
-}
-
-auto ExitingStream::Done() -> void {
-  buffer_ << "\n";
-  buffer_.flush();
-
-  // Register another signal handler to print the buffered message. This is
-  // because we want it at the bottom of output, after LLVM's builtin stack
-  // output, rather than the top.
+auto CheckFailImpl(const char* kind, const char* file, int line,
+                   const char* condition_str, llvm::StringRef extra_message)
+    -> void {
+  // Render the final check string here.
+  std::string message = llvm::formatv(
+      "{0} failure at {1}:{2}{3}{4}{5}{6}\n", kind, file, line,
+      llvm::StringRef(condition_str).empty() ? "" : ": ", condition_str,
+      extra_message.empty() ? "" : ": ", extra_message);
+
+  // Register another signal handler to print the message. This is because we
+  // want it at the bottom of output, after LLVM's builtin stack output, rather
+  // than the top.
   llvm::sys::AddSignalHandler(PrintAfterStackTrace,
   llvm::sys::AddSignalHandler(PrintAfterStackTrace,
-                              const_cast<char*>(buffer_str_.c_str()));
+                              const_cast<char*>(message.c_str()));
   // It's useful to exit the program with `std::abort()` for integration with
   // It's useful to exit the program with `std::abort()` for integration with
   // debuggers and other tools. We also assume LLVM's exit handling is
   // debuggers and other tools. We also assume LLVM's exit handling is
   // installed, which will stack trace on `std::abort()`.
   // installed, which will stack trace on `std::abort()`.

+ 94 - 61
common/check_internal.h

@@ -5,73 +5,106 @@
 #ifndef CARBON_COMMON_CHECK_INTERNAL_H_
 #ifndef CARBON_COMMON_CHECK_INTERNAL_H_
 #define CARBON_COMMON_CHECK_INTERNAL_H_
 #define CARBON_COMMON_CHECK_INTERNAL_H_
 
 
-#include "common/ostream.h"
+#include "common/template_string.h"
+#include "llvm/Support/FormatVariadic.h"
 
 
 namespace Carbon::Internal {
 namespace Carbon::Internal {
 
 
-// Wraps a stream and exiting for fatal errors. Should only be used by check.h
-// macros.
-class ExitingStream {
- public:
-  // A tag type that renders as ": " in an ExitingStream, but only if it is
-  // followed by additional output. Otherwise, it renders as "". Primarily used
-  // when building macros around these streams.
-  struct AddSeparator {};
-
-  // Internal type used in macros to dispatch to the `operator|` overload.
-  struct Helper {};
-
-  ExitingStream()
-      // Prefix the buffer with the current bug report message.
-      : buffer_(buffer_str_) {}
-
-  // Never called.
-  [[noreturn]] ~ExitingStream();
-
-  // If the bool cast occurs, it's because the condition is false. This supports
-  // && short-circuiting the creation of ExitingStream.
-  explicit operator bool() const { return true; }
-
-  // Forward output to llvm::errs.
-  template <typename T>
-  auto operator<<(const T& message) -> ExitingStream& {
-    if (separator_) {
-      buffer_ << ": ";
-      separator_ = false;
-    }
-    buffer_ << message;
-    return *this;
-  }
-
-  auto operator<<(AddSeparator /*add_separator*/) -> ExitingStream& {
-    separator_ = true;
-    return *this;
-  }
-
-  // Low-precedence binary operator overload used in check.h macros to flush the
-  // output and exit the program. We do this in a binary operator rather than
-  // the destructor to ensure good debug info and backtraces for errors.
-  [[noreturn]] friend auto operator|(Helper /*helper*/, ExitingStream& stream)
-      -> void {
-    stream.Done();
+// Implements the check failure message printing.
+//
+// This is out-of-line and will arrange to stop the program, print any debugging
+// information and this string.
+//
+// This API uses `const char*` C string arguments rather than `llvm::StringRef`
+// because we know that these are available as C strings and passing them that
+// way lets the code size of calling it be smaller: it only needs to materialize
+// a single pointer argument for each. The runtime cost of re-computing the size
+// should be minimal. The extra message however might not be compile-time
+// guaranteed to be a C string so we use a normal `StringRef` there.
+[[noreturn]] auto CheckFailImpl(const char* kind, const char* file, int line,
+                                const char* condition_str,
+                                llvm::StringRef extra_message) -> void;
+
+// Prints a check failure, including rendering any user-provided message using
+// a format string.
+//
+// Most of the parameters are passed as compile-time template strings to avoid
+// runtime cost of parameter setup in optimized builds. Each of these are passed
+// along to the underlying implementation to include in the final printed
+// message.
+//
+// Any user-provided format string and values are directly passed to
+// `llvm::formatv` which handles all of the formatting of output.
+template <TemplateString Kind, TemplateString File, int Line,
+          TemplateString ConditionStr, TemplateString FormatStr, typename... Ts>
+[[noreturn, gnu::cold, clang::noinline, clang::preserve_most]] auto CheckFail(
+    Ts&&... values) -> void {
+  if constexpr (llvm::StringRef(FormatStr).empty()) {
+    // Skip the format string rendering if empty. Note that we don't skip it
+    // even if there are no values as we want to have consistent handling of
+    // `{}`s in the format string. This case is about when there is no message
+    // at all, just the condition.
+    CheckFailImpl(Kind.c_str(), File.c_str(), Line, ConditionStr.c_str(), "");
+  } else {
+    CheckFailImpl(
+        Kind.c_str(), File.c_str(), Line, ConditionStr.c_str(),
+        llvm::formatv(FormatStr.c_str(), std::forward<Ts>(values)...).str());
   }
   }
-
- private:
-  [[noreturn]] auto Done() -> void;
-
-  // Whether a separator should be printed if << is used again.
-  bool separator_ = false;
-
-  std::string buffer_str_;
-  llvm::raw_string_ostream buffer_;
-};
+}
 
 
 }  // namespace Carbon::Internal
 }  // namespace Carbon::Internal
 
 
-// Raw exiting stream. This should be used when building forms of exiting
-// macros. It evaluates to a temporary `ExitingStream` object that can be
-// manipulated, streamed into, and then will exit the program.
-#define CARBON_CHECK_INTERNAL_STREAM() \
-  Carbon::Internal::ExitingStream::Helper() | Carbon::Internal::ExitingStream()
+// Implements check messages without any formatted values.
+//
+// Passes each of the provided components of the message to the template
+// parameters of the check failure printing function above, including an empty
+// string for the format string. Because there are multiple template arguments,
+// the entire call is wrapped in parentheses.
+#define CARBON_INTERNAL_CHECK_IMPL(kind, file, line, condition_str) \
+  (Carbon::Internal::CheckFail<kind, file, line, condition_str, "">())
+
+// Implements check messages with a format string and potentially formatted
+// values.
+//
+// Each of the main components is passed as a template arguments, and then any
+// formatted values are passed as arguments. Because there are multiple template
+// arguments, the entire call is wrapped in parentheses.
+#define CARBON_INTERNAL_CHECK_IMPL_FORMAT(kind, file, line, condition_str,   \
+                                          format_str, ...)                   \
+  (Carbon::Internal::CheckFail<kind, file, line, condition_str, format_str>( \
+      __VA_ARGS__))
+
+// Implements the failure of a check.
+//
+// Collects all the metadata about the failure to be printed, such as source
+// location and stringified condition, and passes those, any format string and
+// formatted arguments to the correct implementation macro above.
+#define CARBON_INTERNAL_CHECK(condition, ...)      \
+  CARBON_INTERNAL_CHECK_IMPL##__VA_OPT__(_FORMAT)( \
+      "CHECK", __FILE__, __LINE__, #condition __VA_OPT__(, ) __VA_ARGS__)
+
+// Implements the fatal macro.
+//
+// Similar to the check failure macro, but tags the message as a fatal one and
+// leaves the stringified condition empty.
+#define CARBON_INTERNAL_FATAL(...)                 \
+  CARBON_INTERNAL_CHECK_IMPL##__VA_OPT__(_FORMAT)( \
+      "FATAL", __FILE__, __LINE__, "" __VA_OPT__(, ) __VA_ARGS__)
+
+#ifdef NDEBUG
+// For `DCHECK` in optimized builds we have a dead check that we want to
+// potentially "use" arguments, but otherwise have the minimal overhead. We
+// avoid forming interesting format strings here so that we don't have to
+// repeatedly instantiate the `Check` function above. This format string would
+// be an error if actually used.
+#define CARBON_INTERNAL_DEAD_DCHECK(condition, ...) \
+  CARBON_INTERNAL_DEAD_DCHECK_IMPL##__VA_OPT__(_FORMAT)(__VA_ARGS__)
+
+#define CARBON_INTERNAL_DEAD_DCHECK_IMPL() \
+  Carbon::Internal::CheckFail<"", "", 0, "", "">()
+
+#define CARBON_INTERNAL_DEAD_DCHECK_IMPL_FORMAT(format_str, ...) \
+  Carbon::Internal::CheckFail<"", "", 0, "", "">(__VA_ARGS__)
+#endif
 
 
 #endif  // CARBON_COMMON_CHECK_INTERNAL_H_
 #endif  // CARBON_COMMON_CHECK_INTERNAL_H_

+ 15 - 6
common/check_test.cpp

@@ -26,32 +26,41 @@ TEST(CheckTest, CheckTrueCallbackNotUsed) {
     called = true;
     called = true;
     return "called";
     return "called";
   };
   };
-  CARBON_CHECK(true) << callback();
+  CARBON_CHECK(true, "{0}", callback());
   EXPECT_FALSE(called);
   EXPECT_FALSE(called);
 }
 }
 
 
 TEST(CheckTest, CheckFalseMessage) {
 TEST(CheckTest, CheckFalseMessage) {
-  ASSERT_DEATH({ CARBON_CHECK(false) << "msg"; },
+  ASSERT_DEATH({ CARBON_CHECK(false, "msg"); },
                "\nCHECK failure at common/check_test.cpp:.+: false: msg\n");
                "\nCHECK failure at common/check_test.cpp:.+: false: msg\n");
 }
 }
 
 
+TEST(CheckTest, CheckFalseFormattedMessage) {
+  const char msg[] = "msg";
+  std::string str = "str";
+  int i = 1;
+  ASSERT_DEATH(
+      { CARBON_CHECK(false, "{0} {1} {2} {3}", msg, str, i, 0); },
+      "\nCHECK failure at common/check_test.cpp:.+: false: msg str 1 0\n");
+}
+
 TEST(CheckTest, CheckOutputForms) {
 TEST(CheckTest, CheckOutputForms) {
   const char msg[] = "msg";
   const char msg[] = "msg";
   std::string str = "str";
   std::string str = "str";
   int i = 1;
   int i = 1;
-  CARBON_CHECK(true) << msg << str << i << 0;
+  CARBON_CHECK(true, "{0} {1} {2} {3}", msg, str, i, 0);
 }
 }
 
 
 TEST(CheckTest, Fatal) {
 TEST(CheckTest, Fatal) {
-  ASSERT_DEATH({ CARBON_FATAL() << "msg"; },
+  ASSERT_DEATH({ CARBON_FATAL("msg"); },
                "\nFATAL failure at common/check_test.cpp:.+: msg\n");
                "\nFATAL failure at common/check_test.cpp:.+: msg\n");
 }
 }
 
 
 TEST(CheckTest, FatalHasStackDump) {
 TEST(CheckTest, FatalHasStackDump) {
-  ASSERT_DEATH({ CARBON_FATAL() << "msg"; }, "\nStack dump:\n");
+  ASSERT_DEATH({ CARBON_FATAL("msg"); }, "\nStack dump:\n");
 }
 }
 
 
-auto FatalNoReturnRequired() -> int { CARBON_FATAL() << "msg"; }
+auto FatalNoReturnRequired() -> int { CARBON_FATAL("msg"); }
 
 
 TEST(ErrorTest, FatalNoReturnRequired) {
 TEST(ErrorTest, FatalNoReturnRequired) {
   ASSERT_DEATH({ FatalNoReturnRequired(); },
   ASSERT_DEATH({ FatalNoReturnRequired(); },

+ 77 - 71
common/command_line.cpp

@@ -22,7 +22,7 @@ auto operator<<(llvm::raw_ostream& output, ParseResult result)
     case ParseResult::Success:
     case ParseResult::Success:
       return output << "Success";
       return output << "Success";
   }
   }
-  CARBON_FATAL() << "Corrupt parse result!";
+  CARBON_FATAL("Corrupt parse result!");
 }
 }
 
 
 auto operator<<(llvm::raw_ostream& output, ArgKind kind) -> llvm::raw_ostream& {
 auto operator<<(llvm::raw_ostream& output, ArgKind kind) -> llvm::raw_ostream& {
@@ -40,7 +40,7 @@ auto operator<<(llvm::raw_ostream& output, ArgKind kind) -> llvm::raw_ostream& {
     case ArgKind::Invalid:
     case ArgKind::Invalid:
       return output << "Invalid";
       return output << "Invalid";
   }
   }
-  CARBON_FATAL() << "Corrupt argument kind!";
+  CARBON_FATAL("Corrupt argument kind!");
 }
 }
 
 
 auto operator<<(llvm::raw_ostream& output, CommandKind kind)
 auto operator<<(llvm::raw_ostream& output, CommandKind kind)
@@ -55,7 +55,7 @@ auto operator<<(llvm::raw_ostream& output, CommandKind kind)
     case CommandKind::MetaAction:
     case CommandKind::MetaAction:
       return output << "MetaAction";
       return output << "MetaAction";
   }
   }
-  CARBON_FATAL() << "Corrupt command kind!";
+  CARBON_FATAL("Corrupt command kind!");
 }
 }
 Arg::Arg(const ArgInfo& info) : info(info) {}
 Arg::Arg(const ArgInfo& info) : info(info) {}
 
 
@@ -315,8 +315,9 @@ void MetaPrinter::PrintHelpForSubcommandName(
 }
 }
 
 
 void MetaPrinter::PrintVersion(const Command& command) const {
 void MetaPrinter::PrintVersion(const Command& command) const {
-  CARBON_CHECK(!command.info.version.empty())
-      << "Printing should not be enabled without a version string configured.";
+  CARBON_CHECK(
+      !command.info.version.empty(),
+      "Printing should not be enabled without a version string configured.");
   PrintRawVersion(command, /*indent=*/"");
   PrintRawVersion(command, /*indent=*/"");
   if (!command.info.build_info.empty()) {
   if (!command.info.build_info.empty()) {
     out_ << "\n";
     out_ << "\n";
@@ -463,13 +464,14 @@ void MetaPrinter::PrintOptionUsage(const Arg& option) const {
 }
 }
 
 
 void MetaPrinter::PrintOptionShortName(const Arg& arg) const {
 void MetaPrinter::PrintOptionShortName(const Arg& arg) const {
-  CARBON_CHECK(!arg.info.short_name.empty()) << "No short name to use.";
+  CARBON_CHECK(!arg.info.short_name.empty(), "No short name to use.");
   out_ << "-" << arg.info.short_name;
   out_ << "-" << arg.info.short_name;
 }
 }
 
 
 void MetaPrinter::PrintArgShortValues(const Arg& arg) const {
 void MetaPrinter::PrintArgShortValues(const Arg& arg) const {
-  CARBON_CHECK(arg.kind == Arg::Kind::OneOf)
-      << "Only one-of arguments have interesting value snippets to print.";
+  CARBON_CHECK(
+      arg.kind == Arg::Kind::OneOf,
+      "Only one-of arguments have interesting value snippets to print.");
   llvm::ListSeparator sep;
   llvm::ListSeparator sep;
   for (llvm::StringRef value_string : arg.value_strings) {
   for (llvm::StringRef value_string : arg.value_strings) {
     out_ << sep << value_string;
     out_ << sep << value_string;
@@ -517,7 +519,7 @@ void MetaPrinter::PrintArgHelp(const Arg& arg, llvm::StringRef indent) const {
       // No value help.
       // No value help.
       break;
       break;
     case Arg::Kind::Invalid:
     case Arg::Kind::Invalid:
-      CARBON_FATAL() << "Argument configured without any action or kind!";
+      CARBON_FATAL("Argument configured without any action or kind!");
   }
   }
 }
 }
 
 
@@ -793,11 +795,11 @@ void Parser::PopulateMaps(const Command& command) {
     if (option->info.short_name.empty()) {
     if (option->info.short_name.empty()) {
       continue;
       continue;
     }
     }
-    CARBON_CHECK(option->info.short_name.size() == 1)
-        << "Short option names must have exactly one character.";
+    CARBON_CHECK(option->info.short_name.size() == 1,
+                 "Short option names must have exactly one character.");
     unsigned char short_char = option->info.short_name[0];
     unsigned char short_char = option->info.short_name[0];
-    CARBON_CHECK(short_char < short_option_table_.size())
-        << "Short option name outside of the expected range.";
+    CARBON_CHECK(short_char < short_option_table_.size(),
+                 "Short option name outside of the expected range.");
     short_option_table_[short_char] = &map_entry.second;
     short_option_table_[short_char] = &map_entry.second;
   }
   }
   subcommand_map_.clear();
   subcommand_map_.clear();
@@ -807,7 +809,7 @@ void Parser::PopulateMaps(const Command& command) {
 }
 }
 
 
 void Parser::SetOptionDefault(const Arg& option) {
 void Parser::SetOptionDefault(const Arg& option) {
-  CARBON_CHECK(option.has_default) << "No default value available!";
+  CARBON_CHECK(option.has_default, "No default value available!");
   switch (option.kind) {
   switch (option.kind) {
     case Arg::Kind::Flag:
     case Arg::Kind::Flag:
       *option.flag_storage = option.default_flag;
       *option.flag_storage = option.default_flag;
@@ -822,9 +824,9 @@ void Parser::SetOptionDefault(const Arg& option) {
       option.default_action(option);
       option.default_action(option);
       break;
       break;
     case Arg::Kind::MetaActionOnly:
     case Arg::Kind::MetaActionOnly:
-      CARBON_FATAL() << "Can't set a default value for a meta action!";
+      CARBON_FATAL("Can't set a default value for a meta action!");
     case Arg::Kind::Invalid:
     case Arg::Kind::Invalid:
-      CARBON_FATAL() << "Option configured without any action or kind!";
+      CARBON_FATAL("Option configured without any action or kind!");
   }
   }
 }
 }
 
 
@@ -846,7 +848,7 @@ auto Parser::ParseNegatedFlag(const Arg& flag,
 
 
 auto Parser::ParseFlag(const Arg& flag, std::optional<llvm::StringRef> value)
 auto Parser::ParseFlag(const Arg& flag, std::optional<llvm::StringRef> value)
     -> bool {
     -> bool {
-  CARBON_CHECK(flag.kind == Arg::Kind::Flag) << "Incorrect kind: " << flag.kind;
+  CARBON_CHECK(flag.kind == Arg::Kind::Flag, "Incorrect kind: {0}", flag.kind);
   if (!value || *value == "true") {
   if (!value || *value == "true") {
     *flag.flag_storage = true;
     *flag.flag_storage = true;
   } else if (*value == "false") {
   } else if (*value == "false") {
@@ -862,8 +864,7 @@ auto Parser::ParseFlag(const Arg& flag, std::optional<llvm::StringRef> value)
 
 
 auto Parser::ParseIntegerArgValue(const Arg& arg, llvm::StringRef value)
 auto Parser::ParseIntegerArgValue(const Arg& arg, llvm::StringRef value)
     -> bool {
     -> bool {
-  CARBON_CHECK(arg.kind == Arg::Kind::Integer)
-      << "Incorrect kind: " << arg.kind;
+  CARBON_CHECK(arg.kind == Arg::Kind::Integer, "Incorrect kind: {0}", arg.kind);
   int integer_value;
   int integer_value;
   // Note that this method returns *true* on error!
   // Note that this method returns *true* on error!
   if (value.getAsInteger(/*Radix=*/0, integer_value)) {
   if (value.getAsInteger(/*Radix=*/0, integer_value)) {
@@ -881,7 +882,7 @@ auto Parser::ParseIntegerArgValue(const Arg& arg, llvm::StringRef value)
 
 
 auto Parser::ParseStringArgValue(const Arg& arg, llvm::StringRef value)
 auto Parser::ParseStringArgValue(const Arg& arg, llvm::StringRef value)
     -> bool {
     -> bool {
-  CARBON_CHECK(arg.kind == Arg::Kind::String) << "Incorrect kind: " << arg.kind;
+  CARBON_CHECK(arg.kind == Arg::Kind::String, "Incorrect kind: {0}", arg.kind);
   if (!arg.is_append) {
   if (!arg.is_append) {
     *arg.string_storage = value;
     *arg.string_storage = value;
   } else {
   } else {
@@ -891,7 +892,7 @@ auto Parser::ParseStringArgValue(const Arg& arg, llvm::StringRef value)
 }
 }
 
 
 auto Parser::ParseOneOfArgValue(const Arg& arg, llvm::StringRef value) -> bool {
 auto Parser::ParseOneOfArgValue(const Arg& arg, llvm::StringRef value) -> bool {
-  CARBON_CHECK(arg.kind == Arg::Kind::OneOf) << "Incorrect kind: " << arg.kind;
+  CARBON_CHECK(arg.kind == Arg::Kind::OneOf, "Incorrect kind: {0}", arg.kind);
   if (!arg.value_action(arg, value)) {
   if (!arg.value_action(arg, value)) {
     errors_ << "ERROR: Option '--" << arg.info.name << "=";
     errors_ << "ERROR: Option '--" << arg.info.name << "=";
     llvm::printEscapedString(value, errors_);
     llvm::printEscapedString(value, errors_);
@@ -967,7 +968,7 @@ auto Parser::ParseArg(const Arg& arg, bool short_spelling,
       return false;
       return false;
     case Arg::Kind::Flag:
     case Arg::Kind::Flag:
     case Arg::Kind::Invalid:
     case Arg::Kind::Invalid:
-      CARBON_FATAL() << "Invalid kind!";
+      CARBON_FATAL("Invalid kind!");
   }
   }
 }
 }
 
 
@@ -984,8 +985,8 @@ auto Parser::SplitValue(llvm::StringRef& unparsed_arg)
 }
 }
 
 
 auto Parser::ParseLongOption(llvm::StringRef unparsed_arg) -> bool {
 auto Parser::ParseLongOption(llvm::StringRef unparsed_arg) -> bool {
-  CARBON_CHECK(unparsed_arg.starts_with("--") && unparsed_arg.size() > 2)
-      << "Must only be called on a potential long option.";
+  CARBON_CHECK(unparsed_arg.starts_with("--") && unparsed_arg.size() > 2,
+               "Must only be called on a potential long option.");
 
 
   // Walk past the double dash.
   // Walk past the double dash.
   unparsed_arg = unparsed_arg.drop_front(2);
   unparsed_arg = unparsed_arg.drop_front(2);
@@ -1009,8 +1010,8 @@ auto Parser::ParseLongOption(llvm::StringRef unparsed_arg) -> bool {
 }
 }
 
 
 auto Parser::ParseShortOptionSeq(llvm::StringRef unparsed_arg) -> bool {
 auto Parser::ParseShortOptionSeq(llvm::StringRef unparsed_arg) -> bool {
-  CARBON_CHECK(unparsed_arg.starts_with("-") && unparsed_arg.size() > 1)
-      << "Must only be called on a potential short option sequence.";
+  CARBON_CHECK(unparsed_arg.starts_with("-") && unparsed_arg.size() > 1,
+               "Must only be called on a potential short option sequence.");
 
 
   unparsed_arg = unparsed_arg.drop_front();
   unparsed_arg = unparsed_arg.drop_front();
   std::optional<llvm::StringRef> value = SplitValue(unparsed_arg);
   std::optional<llvm::StringRef> value = SplitValue(unparsed_arg);
@@ -1143,10 +1144,10 @@ auto Parser::FinalizeParse() -> ParseResult {
   // If we were appending to a positional argument, mark that as complete.
   // If we were appending to a positional argument, mark that as complete.
   llvm::ArrayRef positional_args = command_->positional_args;
   llvm::ArrayRef positional_args = command_->positional_args;
   if (appending_to_positional_arg_) {
   if (appending_to_positional_arg_) {
-    CARBON_CHECK(static_cast<size_t>(positional_arg_index_) <
-                 positional_args.size())
-        << "Appending to a positional argument with an invalid index: "
-        << positional_arg_index_;
+    CARBON_CHECK(
+        static_cast<size_t>(positional_arg_index_) < positional_args.size(),
+        "Appending to a positional argument with an invalid index: {0}",
+        positional_arg_index_);
     ++positional_arg_index_;
     ++positional_arg_index_;
   }
   }
 
 
@@ -1162,15 +1163,15 @@ auto Parser::FinalizeParse() -> ParseResult {
       return ParseResult::Error;
       return ParseResult::Error;
     }
     }
     for (const auto& arg_ptr : unparsed_positional_args) {
     for (const auto& arg_ptr : unparsed_positional_args) {
-      CARBON_CHECK(!arg_ptr->is_required)
-          << "Cannot have required positional parameters after an optional "
-             "one.";
+      CARBON_CHECK(
+          !arg_ptr->is_required,
+          "Cannot have required positional parameters after an optional one.");
     }
     }
   }
   }
 
 
   switch (command_->kind) {
   switch (command_->kind) {
     case Command::Kind::Invalid:
     case Command::Kind::Invalid:
-      CARBON_FATAL() << "Should never have a parser with an invalid command!";
+      CARBON_FATAL("Should never have a parser with an invalid command!");
     case Command::Kind::RequiresSubcommand:
     case Command::Kind::RequiresSubcommand:
       errors_ << "ERROR: No subcommand specified. Available subcommands: ";
       errors_ << "ERROR: No subcommand specified. Available subcommands: ";
       error_meta_printer_.PrintSubcommands(*command_);
       error_meta_printer_.PrintSubcommands(*command_);
@@ -1189,11 +1190,13 @@ auto Parser::FinalizeParse() -> ParseResult {
 
 
 auto Parser::ParsePositionalSuffix(
 auto Parser::ParsePositionalSuffix(
     llvm::ArrayRef<llvm::StringRef> unparsed_args) -> bool {
     llvm::ArrayRef<llvm::StringRef> unparsed_args) -> bool {
-  CARBON_CHECK(!command_->positional_args.empty())
-      << "Cannot do positional suffix parsing without positional arguments!";
-  CARBON_CHECK(!unparsed_args.empty() && unparsed_args.front() == "--")
-      << "Must be called with a suffix of arguments starting with a `--` that "
-         "switches to positional suffix parsing.";
+  CARBON_CHECK(
+      !command_->positional_args.empty(),
+      "Cannot do positional suffix parsing without positional arguments!");
+  CARBON_CHECK(
+      !unparsed_args.empty() && unparsed_args.front() == "--",
+      "Must be called with a suffix of arguments starting with a `--` that "
+      "switches to positional suffix parsing.");
   // Once we're in the positional suffix, we can track empty positional
   // Once we're in the positional suffix, we can track empty positional
   // arguments.
   // arguments.
   bool empty_positional = false;
   bool empty_positional = false;
@@ -1291,9 +1294,9 @@ auto Parser::Parse(llvm::ArrayRef<llvm::StringRef> unparsed_args)
       continue;
       continue;
     }
     }
 
 
-    CARBON_CHECK(command_->positional_args.empty() ||
-                 command_->subcommands.empty())
-        << "Cannot have both positional arguments and subcommands!";
+    CARBON_CHECK(
+        command_->positional_args.empty() || command_->subcommands.empty(),
+        "Cannot have both positional arguments and subcommands!");
     if (command_->positional_args.empty() && command_->subcommands.empty()) {
     if (command_->positional_args.empty() && command_->subcommands.empty()) {
       errors_ << "ERROR: Found unexpected positional argument or subcommand: '"
       errors_ << "ERROR: Found unexpected positional argument or subcommand: '"
               << unparsed_arg << "'\n";
               << unparsed_arg << "'\n";
@@ -1439,12 +1442,13 @@ void CommandBuilder::AddOneOfPositionalArg(
 
 
 void CommandBuilder::AddSubcommand(
 void CommandBuilder::AddSubcommand(
     const CommandInfo& info, llvm::function_ref<void(CommandBuilder&)> build) {
     const CommandInfo& info, llvm::function_ref<void(CommandBuilder&)> build) {
-  CARBON_CHECK(IsValidName(info.name))
-      << "Invalid subcommand name: " << info.name;
-  CARBON_CHECK(subcommand_names_.insert(info.name).second)
-      << "Added a duplicate subcommand: " << info.name;
-  CARBON_CHECK(command_.positional_args.empty())
-      << "Cannot add subcommands to a command with a positional argument.";
+  CARBON_CHECK(IsValidName(info.name), "Invalid subcommand name: {0}",
+               info.name);
+  CARBON_CHECK(subcommand_names_.insert(info.name).second,
+               "Added a duplicate subcommand: {0}", info.name);
+  CARBON_CHECK(
+      command_.positional_args.empty(),
+      "Cannot add subcommands to a command with a positional argument.");
 
 
   command_.subcommands.emplace_back(new Command(info, &command_));
   command_.subcommands.emplace_back(new Command(info, &command_));
   CommandBuilder builder(*command_.subcommands.back(), meta_printer_);
   CommandBuilder builder(*command_.subcommands.back(), meta_printer_);
@@ -1457,25 +1461,28 @@ void CommandBuilder::HelpHidden(bool is_help_hidden) {
 }
 }
 
 
 void CommandBuilder::RequiresSubcommand() {
 void CommandBuilder::RequiresSubcommand() {
-  CARBON_CHECK(!command_.subcommands.empty())
-      << "Cannot require subcommands unless there are subcommands.";
-  CARBON_CHECK(command_.positional_args.empty())
-      << "Cannot require subcommands and have a positional argument.";
-  CARBON_CHECK(command_.kind == Kind::Invalid)
-      << "Already established the kind of this command as: " << command_.kind;
+  CARBON_CHECK(!command_.subcommands.empty(),
+               "Cannot require subcommands unless there are subcommands.");
+  CARBON_CHECK(command_.positional_args.empty(),
+               "Cannot require subcommands and have a positional argument.");
+  CARBON_CHECK(command_.kind == Kind::Invalid,
+               "Already established the kind of this command as: {0}",
+               command_.kind);
   command_.kind = Kind::RequiresSubcommand;
   command_.kind = Kind::RequiresSubcommand;
 }
 }
 
 
 void CommandBuilder::Do(ActionT action) {
 void CommandBuilder::Do(ActionT action) {
-  CARBON_CHECK(command_.kind == Kind::Invalid)
-      << "Already established the kind of this command as: " << command_.kind;
+  CARBON_CHECK(command_.kind == Kind::Invalid,
+               "Already established the kind of this command as: {0}",
+               command_.kind);
   command_.kind = Kind::Action;
   command_.kind = Kind::Action;
   command_.action = std::move(action);
   command_.action = std::move(action);
 }
 }
 
 
 void CommandBuilder::Meta(ActionT action) {
 void CommandBuilder::Meta(ActionT action) {
-  CARBON_CHECK(command_.kind == Kind::Invalid)
-      << "Already established the kind of this command as: " << command_.kind;
+  CARBON_CHECK(command_.kind == Kind::Invalid,
+               "Already established the kind of this command as: {0}",
+               command_.kind);
   command_.kind = Kind::MetaAction;
   command_.kind = Kind::MetaAction;
   command_.action = std::move(action);
   command_.action = std::move(action);
 }
 }
@@ -1484,10 +1491,9 @@ CommandBuilder::CommandBuilder(Command& command, MetaPrinter& meta_printer)
     : command_(command), meta_printer_(meta_printer) {}
     : command_(command), meta_printer_(meta_printer) {}
 
 
 auto CommandBuilder::AddArgImpl(const ArgInfo& info, Arg::Kind kind) -> Arg& {
 auto CommandBuilder::AddArgImpl(const ArgInfo& info, Arg::Kind kind) -> Arg& {
-  CARBON_CHECK(IsValidName(info.name))
-      << "Invalid argument name: " << info.name;
-  CARBON_CHECK(arg_names_.insert(info.name).second)
-      << "Added a duplicate argument name: " << info.name;
+  CARBON_CHECK(IsValidName(info.name), "Invalid argument name: {0}", info.name);
+  CARBON_CHECK(arg_names_.insert(info.name).second,
+               "Added a duplicate argument name: {0}", info.name);
 
 
   command_.options.emplace_back(new Arg(info));
   command_.options.emplace_back(new Arg(info));
   Arg& arg = *command_.options.back();
   Arg& arg = *command_.options.back();
@@ -1497,23 +1503,23 @@ auto CommandBuilder::AddArgImpl(const ArgInfo& info, Arg::Kind kind) -> Arg& {
 
 
 void CommandBuilder::AddPositionalArgImpl(
 void CommandBuilder::AddPositionalArgImpl(
     const ArgInfo& info, Arg::Kind kind, llvm::function_ref<void(Arg&)> build) {
     const ArgInfo& info, Arg::Kind kind, llvm::function_ref<void(Arg&)> build) {
-  CARBON_CHECK(IsValidName(info.name))
-      << "Invalid argument name: " << info.name;
-  CARBON_CHECK(command_.subcommands.empty())
-      << "Cannot add a positional argument to a command with subcommands.";
+  CARBON_CHECK(IsValidName(info.name), "Invalid argument name: {0}", info.name);
+  CARBON_CHECK(
+      command_.subcommands.empty(),
+      "Cannot add a positional argument to a command with subcommands.");
 
 
   command_.positional_args.emplace_back(new Arg(info));
   command_.positional_args.emplace_back(new Arg(info));
   Arg& arg = *command_.positional_args.back();
   Arg& arg = *command_.positional_args.back();
   arg.kind = kind;
   arg.kind = kind;
   build(arg);
   build(arg);
 
 
-  CARBON_CHECK(!arg.is_help_hidden)
-      << "Cannot have a help-hidden positional argument.";
+  CARBON_CHECK(!arg.is_help_hidden,
+               "Cannot have a help-hidden positional argument.");
 
 
   if (arg.is_required && command_.positional_args.size() > 1) {
   if (arg.is_required && command_.positional_args.size() > 1) {
-    CARBON_CHECK((*std::prev(command_.positional_args.end(), 2))->is_required)
-        << "A required positional argument cannot be added after an optional "
-           "one.";
+    CARBON_CHECK((*std::prev(command_.positional_args.end(), 2))->is_required,
+                 "A required positional argument cannot be added after an "
+                 "optional one.");
   }
   }
 }
 }
 
 

+ 4 - 4
common/command_line.h

@@ -735,7 +735,7 @@ struct Command {
 
 
 template <typename T>
 template <typename T>
 void ArgBuilder::MetaAction(T action) {
 void ArgBuilder::MetaAction(T action) {
-  CARBON_CHECK(!arg_.meta_action) << "Cannot set a meta action twice!";
+  CARBON_CHECK(!arg_.meta_action, "Cannot set a meta action twice!");
   arg_.meta_action = std::move(action);
   arg_.meta_action = std::move(action);
 }
 }
 
 
@@ -814,9 +814,9 @@ void OneOfArgBuilder::OneOfImpl(const OneOfValueT<U> (&input_values)[N],
 
 
   // Fold over all the input values to see if there is a default.
   // Fold over all the input values to see if there is a default.
   if ((input_values[Indices].is_default || ...)) {
   if ((input_values[Indices].is_default || ...)) {
-    CARBON_CHECK(!arg_.is_append) << "Can't append default.";
-    CARBON_CHECK((input_values[Indices].is_default + ... + 0) == 1)
-        << "Cannot default more than one value.";
+    CARBON_CHECK(!arg_.is_append, "Can't append default.");
+    CARBON_CHECK((input_values[Indices].is_default + ... + 0) == 1,
+                 "Cannot default more than one value.");
 
 
     arg_.has_default = true;
     arg_.has_default = true;
 
 

+ 1 - 1
common/error.h

@@ -27,7 +27,7 @@ class [[nodiscard]] Error : public Printable<Error> {
   // Represents an error state.
   // Represents an error state.
   explicit Error(llvm::Twine location, llvm::Twine message)
   explicit Error(llvm::Twine location, llvm::Twine message)
       : location_(location.str()), message_(message.str()) {
       : location_(location.str()), message_(message.str()) {
-    CARBON_CHECK(!message_.empty()) << "Errors must have a message.";
+    CARBON_CHECK(!message_.empty(), "Errors must have a message.");
   }
   }
 
 
   // Represents an error with no associated location.
   // Represents an error with no associated location.

+ 1 - 1
common/hashing_test.cpp

@@ -653,7 +653,7 @@ auto FindBitRangeCollisions(llvm::ArrayRef<HashedValue<T>> hashes)
 auto CheckNoDuplicateValues(llvm::ArrayRef<HashedString> hashes) -> void {
 auto CheckNoDuplicateValues(llvm::ArrayRef<HashedString> hashes) -> void {
   for (int i = 0, size = hashes.size(); i < size - 1; ++i) {
   for (int i = 0, size = hashes.size(); i < size - 1; ++i) {
     const auto& [_, value] = hashes[i];
     const auto& [_, value] = hashes[i];
-    CARBON_CHECK(value != hashes[i + 1].v) << "Duplicate value: " << value;
+    CARBON_CHECK(value != hashes[i + 1].v, "Duplicate value: {0}", value);
   }
   }
 }
 }
 
 

+ 2 - 2
common/map.h

@@ -472,7 +472,7 @@ MapBase<InputKeyT, InputValueT, InputKeyContextT>::Insert(
            std::invocable<InsertCallbackT, LookupKeyT, void*, void*>)
            std::invocable<InsertCallbackT, LookupKeyT, void*, void*>)
 {
 {
   auto [entry, inserted] = this->InsertImpl(lookup_key, key_context);
   auto [entry, inserted] = this->InsertImpl(lookup_key, key_context);
-  CARBON_DCHECK(entry) << "Should always result in a valid index.";
+  CARBON_DCHECK(entry, "Should always result in a valid index.");
 
 
   if (LLVM_LIKELY(!inserted)) {
   if (LLVM_LIKELY(!inserted)) {
     return InsertKVResult(false, *entry);
     return InsertKVResult(false, *entry);
@@ -538,7 +538,7 @@ MapBase<InputKeyT, InputValueT, InputKeyContextT>::Update(
            std::invocable<UpdateCallbackT, KeyT&, ValueT&>)
            std::invocable<UpdateCallbackT, KeyT&, ValueT&>)
 {
 {
   auto [entry, inserted] = this->InsertImpl(lookup_key, key_context);
   auto [entry, inserted] = this->InsertImpl(lookup_key, key_context);
-  CARBON_DCHECK(entry) << "Should always result in a valid index.";
+  CARBON_DCHECK(entry, "Should always result in a valid index.");
 
 
   if (LLVM_LIKELY(!inserted)) {
   if (LLVM_LIKELY(!inserted)) {
     update_cb(entry->key(), entry->value());
     update_cb(entry->key(), entry->value());

+ 3 - 3
common/map_benchmark.cpp

@@ -460,12 +460,12 @@ static void BM_MapInsertSeq(benchmark::State& state) {
     MapWrapperT m;
     MapWrapperT m;
     for (auto k : keys) {
     for (auto k : keys) {
       bool inserted = m.BenchInsert(k, MakeValue<VT>());
       bool inserted = m.BenchInsert(k, MakeValue<VT>());
-      CARBON_DCHECK(inserted) << "Must be a successful insert!";
+      CARBON_DCHECK(inserted, "Must be a successful insert!");
     }
     }
 
 
     // Now insert a final random repeated key.
     // Now insert a final random repeated key.
     bool inserted = m.BenchInsert(lookup_keys[i], MakeValue2<VT>());
     bool inserted = m.BenchInsert(lookup_keys[i], MakeValue2<VT>());
-    CARBON_DCHECK(!inserted) << "Must already be in the map!";
+    CARBON_DCHECK(!inserted, "Must already be in the map!");
 
 
     // Rotate through the shuffled keys.
     // Rotate through the shuffled keys.
     i = (i + static_cast<ssize_t>(!inserted)) & (LookupKeysSize - 1);
     i = (i + static_cast<ssize_t>(!inserted)) & (LookupKeysSize - 1);
@@ -484,7 +484,7 @@ static void BM_MapInsertSeq(benchmark::State& state) {
     MapWrapperT m;
     MapWrapperT m;
     for (auto k : keys) {
     for (auto k : keys) {
       bool inserted = m.BenchInsert(k, MakeValue<VT>());
       bool inserted = m.BenchInsert(k, MakeValue<VT>());
-      CARBON_DCHECK(inserted) << "Must be a successful insert!";
+      CARBON_DCHECK(inserted, "Must be a successful insert!");
     }
     }
 
 
     ReportMetrics(m, state);
     ReportMetrics(m, state);

+ 24 - 22
common/raw_hashtable.h

@@ -381,8 +381,8 @@ class ViewImpl {
   // given size. This is trivial, but we use this routine to enforce invariants
   // given size. This is trivial, but we use this routine to enforce invariants
   // on the sizes.
   // on the sizes.
   static constexpr auto EntriesOffset(ssize_t alloc_size) -> ssize_t {
   static constexpr auto EntriesOffset(ssize_t alloc_size) -> ssize_t {
-    CARBON_DCHECK(llvm::isPowerOf2_64(alloc_size))
-        << "Size must be a power of two for a hashed buffer!";
+    CARBON_DCHECK(llvm::isPowerOf2_64(alloc_size),
+                  "Size must be a power of two for a hashed buffer!");
     // The size is always a power of two. We prevent any too-small sizes so it
     // The size is always a power of two. We prevent any too-small sizes so it
     // being a power of two provides the needed alignment. As a result, the
     // being a power of two provides the needed alignment. As a result, the
     // offset is exactly the size. We validate this here to catch alignment bugs
     // offset is exactly the size. We validate this here to catch alignment bugs
@@ -615,8 +615,8 @@ inline auto ComputeSeed() -> uint64_t {
 }
 }
 
 
 inline auto ComputeProbeMaskFromSize(ssize_t size) -> size_t {
 inline auto ComputeProbeMaskFromSize(ssize_t size) -> size_t {
-  CARBON_DCHECK(llvm::isPowerOf2_64(size))
-      << "Size must be a power of two for a hashed buffer!";
+  CARBON_DCHECK(llvm::isPowerOf2_64(size),
+                "Size must be a power of two for a hashed buffer!");
   // Since `size` is a power of two, we can make sure the probes are less
   // Since `size` is a power of two, we can make sure the probes are less
   // than `size` by making the mask `size - 1`. We also mask off the low
   // than `size` by making the mask `size - 1`. We also mask off the low
   // bits so the probes are a multiple of the size of the groups of entries.
   // bits so the probes are a multiple of the size of the groups of entries.
@@ -659,12 +659,14 @@ class ProbeSequence {
     // everything down by `GroupSize`.
     // everything down by `GroupSize`.
     CARBON_DCHECK(
     CARBON_DCHECK(
         (p_ / GroupSize) ==
         (p_ / GroupSize) ==
-        ((start_ / GroupSize +
-          (step_ / GroupSize + (step_ / GroupSize) * (step_ / GroupSize)) / 2) %
-         (size_ / GroupSize)))
-        << "Index in probe sequence does not match the expected formula.";
-    CARBON_DCHECK(step_ < size_) << "We necessarily visit all groups, so we "
-                                    "can't have more probe steps than groups.";
+            ((start_ / GroupSize +
+              (step_ / GroupSize + (step_ / GroupSize) * (step_ / GroupSize)) /
+                  2) %
+             (size_ / GroupSize)),
+        "Index in probe sequence does not match the expected formula.");
+    CARBON_DCHECK(step_ < size_,
+                  "We necessarily visit all groups, so we can't have more "
+                  "probe steps than groups.");
 #endif
 #endif
   }
   }
 
 
@@ -924,13 +926,14 @@ auto BaseImpl<InputKeyT, InputValueT, InputKeyContextT>::InsertImpl(
     }
     }
 
 
     --growth_budget_;
     --growth_budget_;
-    CARBON_DCHECK(growth_budget() >= 0)
-        << "Growth budget shouldn't have gone negative!";
+    CARBON_DCHECK(growth_budget() >= 0,
+                  "Growth budget shouldn't have gone negative!");
     return return_insert_at_index(group_index + empty_match.index());
     return return_insert_at_index(group_index + empty_match.index());
   }
   }
 
 
-  CARBON_FATAL() << "We should never finish probing without finding the entry "
-                    "or an empty slot.";
+  CARBON_FATAL(
+      "We should never finish probing without finding the entry or an empty "
+      "slot.");
 }
 }
 
 
 template <typename InputKeyT, typename InputValueT, typename InputKeyContextT>
 template <typename InputKeyT, typename InputValueT, typename InputKeyContextT>
@@ -1264,11 +1267,11 @@ BaseImpl<InputKeyT, InputValueT, InputKeyContextT>::InsertIntoEmpty(
 template <typename InputKeyT, typename InputValueT, typename InputKeyContextT>
 template <typename InputKeyT, typename InputValueT, typename InputKeyContextT>
 auto BaseImpl<InputKeyT, InputValueT, InputKeyContextT>::ComputeNextAllocSize(
 auto BaseImpl<InputKeyT, InputValueT, InputKeyContextT>::ComputeNextAllocSize(
     ssize_t old_alloc_size) -> ssize_t {
     ssize_t old_alloc_size) -> ssize_t {
-  CARBON_DCHECK(llvm::isPowerOf2_64(old_alloc_size))
-      << "Expected a power of two!";
+  CARBON_DCHECK(llvm::isPowerOf2_64(old_alloc_size),
+                "Expected a power of two!");
   ssize_t new_alloc_size;
   ssize_t new_alloc_size;
   bool overflow = __builtin_mul_overflow(old_alloc_size, 2, &new_alloc_size);
   bool overflow = __builtin_mul_overflow(old_alloc_size, 2, &new_alloc_size);
-  CARBON_CHECK(!overflow) << "Computing the new size overflowed `ssize_t`!";
+  CARBON_CHECK(!overflow, "Computing the new size overflowed `ssize_t`!");
   return new_alloc_size;
   return new_alloc_size;
 }
 }
 
 
@@ -1340,11 +1343,10 @@ auto BaseImpl<InputKeyT, InputValueT, InputKeyContextT>::GrowToNextAllocSize(
       llvm::count(llvm::ArrayRef(old_metadata, old_size), MetadataGroup::Empty);
       llvm::count(llvm::ArrayRef(old_metadata, old_size), MetadataGroup::Empty);
   ssize_t debug_deleted_count = llvm::count(
   ssize_t debug_deleted_count = llvm::count(
       llvm::ArrayRef(old_metadata, old_size), MetadataGroup::Deleted);
       llvm::ArrayRef(old_metadata, old_size), MetadataGroup::Deleted);
-  CARBON_DCHECK(debug_empty_count >=
-                (old_size - GrowthThresholdForAllocSize(old_size)))
-      << "debug_empty_count: " << debug_empty_count
-      << ", debug_deleted_count: " << debug_deleted_count
-      << ", size: " << old_size;
+  CARBON_DCHECK(
+      debug_empty_count >= (old_size - GrowthThresholdForAllocSize(old_size)),
+      "debug_empty_count: {0}, debug_deleted_count: {1}, size: {2}",
+      debug_empty_count, debug_deleted_count, old_size);
 #endif
 #endif
 
 
   // Configure for the new size and allocate the new storage.
   // Configure for the new size and allocate the new storage.

+ 4 - 3
common/raw_hashtable_benchmark_helpers.cpp

@@ -43,8 +43,9 @@ static auto MakeChars() -> llvm::OwningArrayRef<char> {
       ++i;
       ++i;
     }
     }
   }
   }
-  CARBON_CHECK(i == NumChars) << "Expected exactly " << NumChars
-                              << " characters, got " << i << " instead!";
+  CARBON_CHECK(i == NumChars,
+               "Expected exactly {0} characters, got {1} instead!", NumChars,
+               i);
   return characters;
   return characters;
 }
 }
 
 
@@ -344,7 +345,7 @@ auto DumpHashStatistics(llvm::ArrayRef<T> keys) -> void {
                                                     GroupShift);
                                                     GroupShift);
   for (auto [i, k] : llvm::enumerate(keys)) {
   for (auto [i, k] : llvm::enumerate(keys)) {
     ssize_t hash_index = get_hash_index(k);
     ssize_t hash_index = get_hash_index(k);
-    CARBON_CHECK(hash_index < (expected_size >> GroupShift)) << hash_index;
+    CARBON_CHECK(hash_index < (expected_size >> GroupShift), "{0}", hash_index);
     grouped_key_indices[hash_index].push_back(i);
     grouped_key_indices[hash_index].push_back(i);
   }
   }
   ssize_t max_group_index =
   ssize_t max_group_index =

+ 53 - 48
common/raw_hashtable_metadata_group.h

@@ -10,6 +10,7 @@
 #include <iterator>
 #include <iterator>
 
 
 #include "common/check.h"
 #include "common/check.h"
+#include "common/ostream.h"
 #include "llvm/ADT/Sequence.h"
 #include "llvm/ADT/Sequence.h"
 #include "llvm/ADT/bit.h"
 #include "llvm/ADT/bit.h"
 #include "llvm/Support/FormatVariadic.h"
 #include "llvm/Support/FormatVariadic.h"
@@ -80,14 +81,14 @@ class BitIndex
 
 
   // Returns true when there are no matches for the tag.
   // Returns true when there are no matches for the tag.
   auto empty() const -> bool {
   auto empty() const -> bool {
-    CARBON_DCHECK((bits_ & ZeroMask) == 0) << "Unexpected non-zero bits!";
+    CARBON_DCHECK((bits_ & ZeroMask) == 0, "Unexpected non-zero bits!");
     __builtin_assume((bits_ & ZeroMask) == 0);
     __builtin_assume((bits_ & ZeroMask) == 0);
     return bits_ == 0;
     return bits_ == 0;
   }
   }
 
 
   // Returns the index of the first matched tag.
   // Returns the index of the first matched tag.
   auto index() -> ssize_t {
   auto index() -> ssize_t {
-    CARBON_DCHECK(bits_ != 0) << "Cannot get an index from zero bits!";
+    CARBON_DCHECK(bits_ != 0, "Cannot get an index from zero bits!");
     __builtin_assume(bits_ != 0);
     __builtin_assume(bits_ != 0);
     ssize_t index = unscaled_index();
     ssize_t index = unscaled_index();
 
 
@@ -102,7 +103,7 @@ class BitIndex
   // Optimized tool to index a pointer `p` by `index()`.
   // Optimized tool to index a pointer `p` by `index()`.
   template <typename T>
   template <typename T>
   auto index_ptr(T* pointer) -> T* {
   auto index_ptr(T* pointer) -> T* {
-    CARBON_DCHECK(bits_ != 0) << "Cannot get an index from zero bits!";
+    CARBON_DCHECK(bits_ != 0, "Cannot get an index from zero bits!");
     __builtin_assume(bits_ != 0);
     __builtin_assume(bits_ != 0);
     if constexpr (!ByteEncoding) {
     if constexpr (!ByteEncoding) {
       return &pointer[unscaled_index()];
       return &pointer[unscaled_index()];
@@ -191,7 +192,7 @@ class BitIndexRange : public Printable<BitIndexRange<BitIndexT>> {
     }
     }
 
 
     auto operator*() -> ssize_t& {
     auto operator*() -> ssize_t& {
-      CARBON_DCHECK(bits_ != 0) << "Cannot get an index from zero bits!";
+      CARBON_DCHECK(bits_ != 0, "Cannot get an index from zero bits!");
       __builtin_assume(bits_ != 0);
       __builtin_assume(bits_ != 0);
       index_ = BitIndexT(bits_).index();
       index_ = BitIndexT(bits_).index();
       // Note that we store the index in a member so we can return a reference
       // Note that we store the index in a member so we can return a reference
@@ -205,7 +206,7 @@ class BitIndexRange : public Printable<BitIndexRange<BitIndexT>> {
     }
     }
 
 
     auto operator++() -> Iterator& {
     auto operator++() -> Iterator& {
-      CARBON_DCHECK(bits_ != 0) << "Must not increment past the end!";
+      CARBON_DCHECK(bits_ != 0, "Must not increment past the end!");
       __builtin_assume(bits_ != 0);
       __builtin_assume(bits_ != 0);
       // Clears the least significant set bit, effectively stepping to the next
       // Clears the least significant set bit, effectively stepping to the next
       // match.
       // match.
@@ -270,7 +271,7 @@ class BitIndexRange : public Printable<BitIndexRange<BitIndexT>> {
 //   }
 //   }
 //   if (UseSIMD || DebugSIMD) {
 //   if (UseSIMD || DebugSIMD) {
 //     simd_result = SIMDOperation(...)
 //     simd_result = SIMDOperation(...)
-//     CARBON_DCHECK(result == portable_result) << ...;
+//     CARBON_DCHECK(result == portable_result, "{0}", ...);
 //   }
 //   }
 //   return UseSIMD ? simd_result : portable_result;
 //   return UseSIMD ? simd_result : portable_result;
 // }
 // }
@@ -533,9 +534,8 @@ inline auto MetadataGroup::Store(uint8_t* metadata, ssize_t index) const
 }
 }
 
 
 inline auto MetadataGroup::ClearByte(ssize_t byte_index) -> void {
 inline auto MetadataGroup::ClearByte(ssize_t byte_index) -> void {
-  CARBON_DCHECK(FastByteClear) << "Only use byte clearing when fast!";
-  CARBON_DCHECK(Size == 8)
-      << "The clear implementation assumes an 8-byte group.";
+  CARBON_DCHECK(FastByteClear, "Only use byte clearing when fast!");
+  CARBON_DCHECK(Size == 8, "The clear implementation assumes an 8-byte group.");
 
 
   metadata_ints[0] &= ~(static_cast<uint64_t>(0xff) << (byte_index * 8));
   metadata_ints[0] &= ~(static_cast<uint64_t>(0xff) << (byte_index * 8));
 }
 }
@@ -548,9 +548,10 @@ inline auto MetadataGroup::ClearDeleted() -> void {
   }
   }
   if constexpr (UseSIMD || DebugSIMD) {
   if constexpr (UseSIMD || DebugSIMD) {
     simd_g.SIMDClearDeleted();
     simd_g.SIMDClearDeleted();
-    CARBON_DCHECK(simd_g == portable_g)
-        << "SIMD cleared group '" << simd_g
-        << "' doesn't match portable cleared group '" << portable_g << "'";
+    CARBON_DCHECK(
+        simd_g == portable_g,
+        "SIMD cleared group '{0}' doesn't match portable cleared group '{1}'",
+        simd_g, portable_g);
   }
   }
   *this = UseSIMD ? simd_g : portable_g;
   *this = UseSIMD ? simd_g : portable_g;
 }
 }
@@ -559,7 +560,7 @@ inline auto MetadataGroup::Match(uint8_t tag) const -> MatchRange {
   // The caller should provide us with the present byte hash, and not set any
   // The caller should provide us with the present byte hash, and not set any
   // present bit tag on it so that this layer can manage tagging the high bit of
   // present bit tag on it so that this layer can manage tagging the high bit of
   // a present byte.
   // a present byte.
-  CARBON_DCHECK((tag & PresentMask) == 0) << llvm::formatv("{0:x}", tag);
+  CARBON_DCHECK((tag & PresentMask) == 0, "{0:x}", tag);
 
 
   MatchRange portable_result;
   MatchRange portable_result;
   MatchRange simd_result;
   MatchRange simd_result;
@@ -568,9 +569,9 @@ inline auto MetadataGroup::Match(uint8_t tag) const -> MatchRange {
   }
   }
   if constexpr (UseSIMD || DebugSIMD) {
   if constexpr (UseSIMD || DebugSIMD) {
     simd_result = SIMDMatch(tag);
     simd_result = SIMDMatch(tag);
-    CARBON_DCHECK(simd_result == portable_result)
-        << "SIMD result '" << simd_result << "' doesn't match portable result '"
-        << portable_result << "'";
+    CARBON_DCHECK(simd_result == portable_result,
+                  "SIMD result '{0}' doesn't match portable result '{1}'",
+                  simd_result, portable_result);
   }
   }
   return UseSIMD ? simd_result : portable_result;
   return UseSIMD ? simd_result : portable_result;
 }
 }
@@ -583,9 +584,9 @@ inline auto MetadataGroup::MatchPresent() const -> MatchRange {
   }
   }
   if constexpr (UseSIMD || DebugSIMD) {
   if constexpr (UseSIMD || DebugSIMD) {
     simd_result = SIMDMatchPresent();
     simd_result = SIMDMatchPresent();
-    CARBON_DCHECK(simd_result == portable_result)
-        << "SIMD result '" << simd_result << "' doesn't match portable result '"
-        << portable_result << "'";
+    CARBON_DCHECK(simd_result == portable_result,
+                  "SIMD result '{0}' doesn't match portable result '{1}'",
+                  simd_result, portable_result);
   }
   }
   return UseSIMD ? simd_result : portable_result;
   return UseSIMD ? simd_result : portable_result;
 }
 }
@@ -598,9 +599,9 @@ inline auto MetadataGroup::MatchEmpty() const -> MatchIndex {
   }
   }
   if constexpr (UseSIMD || DebugSIMD) {
   if constexpr (UseSIMD || DebugSIMD) {
     simd_result = SIMDMatchEmpty();
     simd_result = SIMDMatchEmpty();
-    CARBON_DCHECK(simd_result == portable_result)
-        << "SIMD result '" << simd_result << "' doesn't match portable result '"
-        << portable_result << "'";
+    CARBON_DCHECK(simd_result == portable_result,
+                  "SIMD result '{0}' doesn't match portable result '{1}'",
+                  simd_result, portable_result);
   }
   }
   return UseSIMD ? simd_result : portable_result;
   return UseSIMD ? simd_result : portable_result;
 }
 }
@@ -613,9 +614,9 @@ inline auto MetadataGroup::MatchDeleted() const -> MatchIndex {
   }
   }
   if constexpr (UseSIMD || DebugSIMD) {
   if constexpr (UseSIMD || DebugSIMD) {
     simd_result = SIMDMatchDeleted();
     simd_result = SIMDMatchDeleted();
-    CARBON_DCHECK(simd_result == portable_result)
-        << "SIMD result '" << simd_result << "' doesn't match portable result '"
-        << portable_result << "'";
+    CARBON_DCHECK(simd_result == portable_result,
+                  "SIMD result '{0}' doesn't match portable result '{1}'",
+                  simd_result, portable_result);
   }
   }
   return UseSIMD ? simd_result : portable_result;
   return UseSIMD ? simd_result : portable_result;
 }
 }
@@ -640,29 +641,31 @@ inline auto MetadataGroup::VerifyIndexBits(
   for (ssize_t byte_index : llvm::seq<ssize_t>(0, Size)) {
   for (ssize_t byte_index : llvm::seq<ssize_t>(0, Size)) {
     if constexpr (!ByteEncoding) {
     if constexpr (!ByteEncoding) {
       if (byte_match(metadata_bytes[byte_index])) {
       if (byte_match(metadata_bytes[byte_index])) {
-        CARBON_CHECK(((index_bits >> byte_index) & 1) == 1)
-            << "Bit not set at matching byte index: " << byte_index;
+        CARBON_CHECK(((index_bits >> byte_index) & 1) == 1,
+                     "Bit not set at matching byte index: {0}", byte_index);
         // Only the first match is needed, so stop scanning once found.
         // Only the first match is needed, so stop scanning once found.
         break;
         break;
       }
       }
 
 
-      CARBON_CHECK(((index_bits >> byte_index) & 1) == 0)
-          << "Bit set at non-matching byte index: " << byte_index;
+      CARBON_CHECK(((index_bits >> byte_index) & 1) == 0,
+                   "Bit set at non-matching byte index: {0}", byte_index);
     } else {
     } else {
       // `index_bits` is byte-encoded rather than bit encoded, so extract a
       // `index_bits` is byte-encoded rather than bit encoded, so extract a
       // byte.
       // byte.
       uint8_t index_byte = (index_bits >> (byte_index * 8)) & 0xFF;
       uint8_t index_byte = (index_bits >> (byte_index * 8)) & 0xFF;
       if (byte_match(metadata_bytes[byte_index])) {
       if (byte_match(metadata_bytes[byte_index])) {
-        CARBON_CHECK((index_byte & 0x80) == 0x80)
-            << "Should have the high bit set for a matching byte, found: "
-            << llvm::formatv("{0:x}", index_byte);
+        CARBON_CHECK(
+            (index_byte & 0x80) == 0x80,
+            "Should have the high bit set for a matching byte, found: {0:x}",
+            index_byte);
         // Only the first match is needed so stop scanning once found.
         // Only the first match is needed so stop scanning once found.
         break;
         break;
       }
       }
 
 
-      CARBON_CHECK(index_byte == 0)
-          << "Should have no bits set for an unmatched byte, found: "
-          << llvm::formatv("{0:x}", index_byte);
+      CARBON_CHECK(
+          index_byte == 0,
+          "Should have no bits set for an unmatched byte, found: {0:x}",
+          index_byte);
     }
     }
   }
   }
   return true;
   return true;
@@ -674,24 +677,26 @@ inline auto MetadataGroup::VerifyRangeBits(
   for (ssize_t byte_index : llvm::seq<ssize_t>(0, Size)) {
   for (ssize_t byte_index : llvm::seq<ssize_t>(0, Size)) {
     if constexpr (!ByteEncoding) {
     if constexpr (!ByteEncoding) {
       if (byte_match(metadata_bytes[byte_index])) {
       if (byte_match(metadata_bytes[byte_index])) {
-        CARBON_CHECK(((range_bits >> byte_index) & 1) == 1)
-            << "Bit not set at matching byte index: " << byte_index;
+        CARBON_CHECK(((range_bits >> byte_index) & 1) == 1,
+                     "Bit not set at matching byte index: {0}", byte_index);
       } else {
       } else {
-        CARBON_CHECK(((range_bits >> byte_index) & 1) == 0)
-            << "Bit set at non-matching byte index: " << byte_index;
+        CARBON_CHECK(((range_bits >> byte_index) & 1) == 0,
+                     "Bit set at non-matching byte index: {0}", byte_index);
       }
       }
     } else {
     } else {
       // `range_bits` is byte-encoded rather than bit encoded, so extract a
       // `range_bits` is byte-encoded rather than bit encoded, so extract a
       // byte.
       // byte.
       uint8_t range_byte = (range_bits >> (byte_index * 8)) & 0xFF;
       uint8_t range_byte = (range_bits >> (byte_index * 8)) & 0xFF;
       if (byte_match(metadata_bytes[byte_index])) {
       if (byte_match(metadata_bytes[byte_index])) {
-        CARBON_CHECK(range_byte == 0x80)
-            << "Should just have the high bit set for a matching byte, found: "
-            << llvm::formatv("{0:x}", range_byte);
+        CARBON_CHECK(range_byte == 0x80,
+                     "Should just have the high bit set for a matching byte, "
+                     "found: {0:x}",
+                     range_byte);
       } else {
       } else {
-        CARBON_CHECK(range_byte == 0)
-            << "Should have no bits set for an unmatched byte, found: "
-            << llvm::formatv("{0:x}", range_byte);
+        CARBON_CHECK(
+            range_byte == 0,
+            "Should have no bits set for an unmatched byte, found: {0:x}",
+            range_byte);
       }
       }
     }
     }
   }
   }
@@ -730,7 +735,7 @@ inline auto MetadataGroup::PortableMatch(uint8_t tag) const -> MatchRange {
   // The caller should provide us with the present byte hash, and not set any
   // The caller should provide us with the present byte hash, and not set any
   // present bit tag on it so that this layer can manage tagging the high bit of
   // present bit tag on it so that this layer can manage tagging the high bit of
   // a present byte.
   // a present byte.
-  CARBON_DCHECK((tag & PresentMask) == 0) << llvm::formatv("{0:x}", tag);
+  CARBON_DCHECK((tag & PresentMask) == 0, "{0:x}", tag);
 
 
   // Use a simple fallback approach for sizes beyond 8.
   // Use a simple fallback approach for sizes beyond 8.
   // TODO: Instead of a simple fallback, we should generalize the below
   // TODO: Instead of a simple fallback, we should generalize the below
@@ -783,8 +788,8 @@ inline auto MetadataGroup::PortableMatch(uint8_t tag) const -> MatchRange {
   // know that the add cannot carry, and this way it can be lowered using
   // know that the add cannot carry, and this way it can be lowered using
   // combined multiply-add instructions if available.
   // combined multiply-add instructions if available.
   uint64_t broadcast = LSBs * tag + MSBs;
   uint64_t broadcast = LSBs * tag + MSBs;
-  CARBON_DCHECK(broadcast == (LSBs * tag | MSBs))
-      << "Unexpected carry from addition!";
+  CARBON_DCHECK(broadcast == (LSBs * tag | MSBs),
+                "Unexpected carry from addition!");
 
 
   // Xor the broadcast byte pattern. This makes bytes with matches become 0, and
   // Xor the broadcast byte pattern. This makes bytes with matches become 0, and
   // clears the high-bits of non-matches. Note that if we are looking for a tag
   // clears the high-bits of non-matches. Note that if we are looking for a tag

+ 1 - 1
common/set.h

@@ -372,7 +372,7 @@ auto SetBase<InputKeyT, InputKeyContextT>::Insert(LookupKeyT lookup_key,
   requires std::invocable<InsertCallbackT, LookupKeyT, void*>
   requires std::invocable<InsertCallbackT, LookupKeyT, void*>
 {
 {
   auto [entry, inserted] = this->InsertImpl(lookup_key, key_context);
   auto [entry, inserted] = this->InsertImpl(lookup_key, key_context);
-  CARBON_DCHECK(entry) << "Should always result in a valid index.";
+  CARBON_DCHECK(entry, "Should always result in a valid index.");
 
 
   if (LLVM_LIKELY(!inserted)) {
   if (LLVM_LIKELY(!inserted)) {
     return InsertResult(false, entry->key());
     return InsertResult(false, entry->key());

+ 3 - 3
common/set_benchmark.cpp

@@ -336,12 +336,12 @@ static void BM_SetInsertSeq(benchmark::State& state) {
     SetWrapperT s;
     SetWrapperT s;
     for (auto k : keys) {
     for (auto k : keys) {
       bool inserted = s.BenchInsert(k);
       bool inserted = s.BenchInsert(k);
-      CARBON_DCHECK(inserted) << "Must be a successful insert!";
+      CARBON_DCHECK(inserted, "Must be a successful insert!");
     }
     }
 
 
     // Now insert a final random repeated key.
     // Now insert a final random repeated key.
     bool inserted = s.BenchInsert(lookup_keys[i]);
     bool inserted = s.BenchInsert(lookup_keys[i]);
-    CARBON_DCHECK(!inserted) << "Must already be in the map!";
+    CARBON_DCHECK(!inserted, "Must already be in the map!");
 
 
     // Rotate through the shuffled keys.
     // Rotate through the shuffled keys.
     i = (i + static_cast<ssize_t>(!inserted)) & (LookupKeysSize - 1);
     i = (i + static_cast<ssize_t>(!inserted)) & (LookupKeysSize - 1);
@@ -360,7 +360,7 @@ static void BM_SetInsertSeq(benchmark::State& state) {
     SetT s;
     SetT s;
     for (auto k : keys) {
     for (auto k : keys) {
       bool inserted = s.Insert(k).is_inserted();
       bool inserted = s.Insert(k).is_inserted();
-      CARBON_DCHECK(inserted) << "Must be a successful insert!";
+      CARBON_DCHECK(inserted, "Must be a successful insert!");
     }
     }
 
 
     ReportTableMetrics(s, state);
     ReportTableMetrics(s, state);

+ 3 - 3
explorer/ast/bindings.cpp

@@ -25,15 +25,15 @@ void Bindings::Add(Nonnull<const GenericBinding*> binding,
                    Nonnull<const Value*> value,
                    Nonnull<const Value*> value,
                    std::optional<Nonnull<const Value*>> witness) {
                    std::optional<Nonnull<const Value*>> witness) {
   bool added_value = args_.insert({binding, value}).second;
   bool added_value = args_.insert({binding, value}).second;
-  CARBON_CHECK(added_value) << "Add of already-existing binding";
+  CARBON_CHECK(added_value, "Add of already-existing binding");
 
 
   if (witness) {
   if (witness) {
     // TODO: Eventually we should check that we have a witness if and only if
     // TODO: Eventually we should check that we have a witness if and only if
     // the binding has an impl binding.
     // the binding has an impl binding.
     auto impl_binding = binding->impl_binding();
     auto impl_binding = binding->impl_binding();
-    CARBON_CHECK(impl_binding) << "Given witness but have no impl binding";
+    CARBON_CHECK(impl_binding, "Given witness but have no impl binding");
     bool added_witness = witnesses_.insert({*impl_binding, *witness}).second;
     bool added_witness = witnesses_.insert({*impl_binding, *witness}).second;
-    CARBON_CHECK(added_witness) << "Add of already-existing binding";
+    CARBON_CHECK(added_witness, "Add of already-existing binding");
   }
   }
 }
 }
 
 

+ 5 - 5
explorer/ast/clone_context.cpp

@@ -13,10 +13,10 @@ namespace Carbon {
 auto CloneContext::CloneBase(Nonnull<const AstNode*> node)
 auto CloneContext::CloneBase(Nonnull<const AstNode*> node)
     -> Nonnull<AstNode*> {
     -> Nonnull<AstNode*> {
   auto [it, added] = nodes_.insert({node, nullptr});
   auto [it, added] = nodes_.insert({node, nullptr});
-  CARBON_CHECK(added) << (it->second
-                              ? "node was cloned multiple times: "
-                              : "node was remapped before it was cloned: ")
-                      << *node;
+  CARBON_CHECK(
+      added, "node was {0}: {1}",
+      it->second ? "cloned multiple times" : "remapped before it was cloned",
+      *node);
 
 
   // TODO: Generate a Visit member on AstNode and use it here to avoid these
   // TODO: Generate a Visit member on AstNode and use it here to avoid these
   // macros.
   // macros.
@@ -34,7 +34,7 @@ auto CloneContext::CloneBase(Nonnull<const AstNode*> node)
 
 
   // Cloning may have invalidated our iterator; redo lookup.
   // Cloning may have invalidated our iterator; redo lookup.
   auto* result = nodes_[node];
   auto* result = nodes_[node];
-  CARBON_CHECK(result) << "CloneImpl didn't set the result pointer";
+  CARBON_CHECK(result, "CloneImpl didn't set the result pointer");
   return result;
   return result;
 }
 }
 
 

+ 1 - 1
explorer/ast/clone_context.h

@@ -131,7 +131,7 @@ class CloneContext {
   template <typename T>
   template <typename T>
   auto GetExistingClone(Nonnull<const T*> node) -> Nonnull<T*> {
   auto GetExistingClone(Nonnull<const T*> node) -> Nonnull<T*> {
     AstNode* cloned = nodes_.lookup(node);
     AstNode* cloned = nodes_.lookup(node);
-    CARBON_CHECK(cloned) << "expected node to be cloned";
+    CARBON_CHECK(cloned, "expected node to be cloned");
     return llvm::cast<T>(cloned);
     return llvm::cast<T>(cloned);
   }
   }
 
 

+ 1 - 1
explorer/ast/declaration.cpp

@@ -413,7 +413,7 @@ auto FunctionDeclaration::Create(Nonnull<Arena*> arena,
 void CallableDeclaration::PrintIndent(int indent_num_spaces,
 void CallableDeclaration::PrintIndent(int indent_num_spaces,
                                       llvm::raw_ostream& out) const {
                                       llvm::raw_ostream& out) const {
   auto name = GetName(*this);
   auto name = GetName(*this);
-  CARBON_CHECK(name) << "Unexpected missing name for `" << *this << "`.";
+  CARBON_CHECK(name, "Unexpected missing name for `{0}`.", *this);
   out.indent(indent_num_spaces) << "fn " << *name << " ";
   out.indent(indent_num_spaces) << "fn " << *name << " ";
   if (!deduced_parameters_.empty() || self_pattern_) {
   if (!deduced_parameters_.empty() || self_pattern_) {
     out << "[";
     out << "[";

+ 3 - 3
explorer/ast/declaration.h

@@ -101,7 +101,7 @@ class Declaration : public AstNode {
   // Set that this node is declared. Should only be called once, by the
   // Set that this node is declared. Should only be called once, by the
   // type-checker, once the node is ready to be named and used.
   // type-checker, once the node is ready to be named and used.
   void set_is_declared() {
   void set_is_declared() {
-    CARBON_CHECK(!is_declared_) << "should not be declared twice";
+    CARBON_CHECK(!is_declared_, "should not be declared twice");
     is_declared_ = true;
     is_declared_ = true;
   }
   }
 
 
@@ -111,7 +111,7 @@ class Declaration : public AstNode {
   // Set that this node is type-checked. Should only be called once, by the
   // Set that this node is type-checked. Should only be called once, by the
   // type-checker, once full type-checking is complete.
   // type-checker, once full type-checking is complete.
   void set_is_type_checked() {
   void set_is_type_checked() {
-    CARBON_CHECK(!is_type_checked_) << "should not be type-checked twice";
+    CARBON_CHECK(!is_type_checked_, "should not be type-checked twice");
     is_type_checked_ = true;
     is_type_checked_ = true;
   }
   }
 
 
@@ -674,7 +674,7 @@ class VariableDeclaration : public Declaration {
 
 
   // Can only be called by type-checking, if a conversion was required.
   // Can only be called by type-checking, if a conversion was required.
   void set_initializer(Nonnull<Expression*> initializer) {
   void set_initializer(Nonnull<Expression*> initializer) {
-    CARBON_CHECK(has_initializer()) << "should not add a new initializer";
+    CARBON_CHECK(has_initializer(), "should not add a new initializer");
     initializer_ = initializer;
     initializer_ = initializer;
   }
   }
 
 

+ 2 - 2
explorer/ast/element_path.h

@@ -113,8 +113,8 @@ class ElementPath : public Printable<ElementPath> {
   // Removes all trailing `BaseElement`s, errors if there are no base elements.
   // Removes all trailing `BaseElement`s, errors if there are no base elements.
   auto RemoveTrailingBaseElements() -> void {
   auto RemoveTrailingBaseElements() -> void {
     CARBON_CHECK(!components_.empty() && components_.back().element()->kind() ==
     CARBON_CHECK(!components_.empty() && components_.back().element()->kind() ==
-                                             ElementKind::BaseElement)
-        << "No base elements to remove.";
+                                             ElementKind::BaseElement,
+                 "No base elements to remove.");
     const auto r_it = std::find_if(
     const auto r_it = std::find_if(
         components_.rbegin(), components_.rend(), [](const Component& c) {
         components_.rbegin(), components_.rend(), [](const Component& c) {
           return c.element()->kind() != ElementKind::BaseElement;
           return c.element()->kind() != ElementKind::BaseElement;

+ 1 - 2
explorer/ast/expression.cpp

@@ -231,8 +231,7 @@ void Expression::Print(llvm::raw_ostream& out) const {
               << *op.arguments()[1];
               << *op.arguments()[1];
           break;
           break;
         default:
         default:
-          CARBON_FATAL() << "Unexpected argument count: "
-                         << op.arguments().size();
+          CARBON_FATAL("Unexpected argument count: {0}", op.arguments().size());
       }
       }
       out << ")";
       out << ")";
       break;
       break;

+ 4 - 3
explorer/ast/expression.h

@@ -113,7 +113,7 @@ class RewritableMixin : public Base {
   // Set the rewritten form of this expression. Can only be called during type
   // Set the rewritten form of this expression. Can only be called during type
   // checking.
   // checking.
   auto set_rewritten_form(Nonnull<const Expression*> rewritten_form) -> void {
   auto set_rewritten_form(Nonnull<const Expression*> rewritten_form) -> void {
-    CARBON_CHECK(!rewritten_form_.has_value()) << "rewritten form set twice";
+    CARBON_CHECK(!rewritten_form_.has_value(), "rewritten form set twice");
     rewritten_form_ = rewritten_form;
     rewritten_form_ = rewritten_form;
     this->set_static_type(&rewritten_form->static_type());
     this->set_static_type(&rewritten_form->static_type());
     this->set_expression_category(rewritten_form->expression_category());
     this->set_expression_category(rewritten_form->expression_category());
@@ -660,8 +660,9 @@ class StructTypeLiteral : public ConstantValueLiteral {
                              std::vector<FieldInitializer> fields)
                              std::vector<FieldInitializer> fields)
       : ConstantValueLiteral(AstNodeKind::StructTypeLiteral, loc),
       : ConstantValueLiteral(AstNodeKind::StructTypeLiteral, loc),
         fields_(std::move(fields)) {
         fields_(std::move(fields)) {
-    CARBON_CHECK(!fields_.empty())
-        << "`{}` is represented as a StructLiteral, not a StructTypeLiteral.";
+    CARBON_CHECK(
+        !fields_.empty(),
+        "`{}` is represented as a StructLiteral, not a StructTypeLiteral.");
   }
   }
 
 
   explicit StructTypeLiteral(CloneContext& context,
   explicit StructTypeLiteral(CloneContext& context,

+ 3 - 3
explorer/ast/impl_binding.h

@@ -49,14 +49,14 @@ class ImplBinding : public AstNode {
   // The constraint being implemented.
   // The constraint being implemented.
   // TODO: Rename this to `constraint`.
   // TODO: Rename this to `constraint`.
   auto interface() const -> Nonnull<const Value*> {
   auto interface() const -> Nonnull<const Value*> {
-    CARBON_CHECK(iface_) << "interface has not been set yet";
+    CARBON_CHECK(iface_, "interface has not been set yet");
     return *iface_;
     return *iface_;
   }
   }
 
 
   // Set the interface being implemented, if not set by the constructor. Should
   // Set the interface being implemented, if not set by the constructor. Should
   // only be called by typechecking.
   // only be called by typechecking.
   void set_interface(Nonnull<const Value*> iface) {
   void set_interface(Nonnull<const Value*> iface) {
-    CARBON_CHECK(!iface_) << "interface set twice";
+    CARBON_CHECK(!iface_, "interface set twice");
     iface_ = iface;
     iface_ = iface;
   }
   }
 
 
@@ -75,7 +75,7 @@ class ImplBinding : public AstNode {
   // These functions exist only so that an `ImplBinding` can be used as a
   // These functions exist only so that an `ImplBinding` can be used as a
   // `ValueNodeView` as a key in a `StaticScope`.
   // `ValueNodeView` as a key in a `StaticScope`.
   auto static_type() const -> const Value& {
   auto static_type() const -> const Value& {
-    CARBON_FATAL() << "an ImplBinding has no type";
+    CARBON_FATAL("an ImplBinding has no type");
   }
   }
   auto expression_category() const -> ExpressionCategory {
   auto expression_category() const -> ExpressionCategory {
     return ExpressionCategory::Value;
     return ExpressionCategory::Value;

+ 2 - 2
explorer/ast/pattern.h

@@ -79,7 +79,7 @@ class Pattern : public AstNode {
   // Sets the value of this pattern. Can only be called once, during
   // Sets the value of this pattern. Can only be called once, during
   // typechecking.
   // typechecking.
   void set_value(Nonnull<const Value*> value) {
   void set_value(Nonnull<const Value*> value) {
-    CARBON_CHECK(!value_) << "set_value called more than once";
+    CARBON_CHECK(!value_, "set_value called more than once");
     value_ = value;
     value_ = value;
   }
   }
 
 
@@ -307,7 +307,7 @@ class GenericBinding : public Pattern {
 
 
   // Set the index of this binding. Should be called only during type-checking.
   // Set the index of this binding. Should be called only during type-checking.
   void set_index(int index) {
   void set_index(int index) {
-    CARBON_CHECK(!index_) << "should only set depth and index once";
+    CARBON_CHECK(!index_, "should only set depth and index once");
     index_ = index;
     index_ = index;
   }
   }
 
 

+ 3 - 3
explorer/ast/statement.h

@@ -150,7 +150,7 @@ class Assign : public Statement {
   // Set the rewritten form of this statement. Can only be called during type
   // Set the rewritten form of this statement. Can only be called during type
   // checking.
   // checking.
   auto set_rewritten_form(Nonnull<const Expression*> rewritten_form) -> void {
   auto set_rewritten_form(Nonnull<const Expression*> rewritten_form) -> void {
-    CARBON_CHECK(!rewritten_form_.has_value()) << "rewritten form set twice";
+    CARBON_CHECK(!rewritten_form_.has_value(), "rewritten form set twice");
     rewritten_form_ = rewritten_form;
     rewritten_form_ = rewritten_form;
   }
   }
 
 
@@ -196,7 +196,7 @@ class IncrementDecrement : public Statement {
   // Set the rewritten form of this statement. Can only be called during type
   // Set the rewritten form of this statement. Can only be called during type
   // checking.
   // checking.
   auto set_rewritten_form(Nonnull<const Expression*> rewritten_form) -> void {
   auto set_rewritten_form(Nonnull<const Expression*> rewritten_form) -> void {
-    CARBON_CHECK(!rewritten_form_.has_value()) << "rewritten form set twice";
+    CARBON_CHECK(!rewritten_form_.has_value(), "rewritten form set twice");
     rewritten_form_ = rewritten_form;
     rewritten_form_ = rewritten_form;
   }
   }
 
 
@@ -256,7 +256,7 @@ class VariableDefinition : public Statement {
 
 
   // Can only be called by type-checking, if a conversion was required.
   // Can only be called by type-checking, if a conversion was required.
   void set_init(Nonnull<Expression*> init) {
   void set_init(Nonnull<Expression*> init) {
-    CARBON_CHECK(has_init()) << "should not add a new initializer";
+    CARBON_CHECK(has_init(), "should not add a new initializer");
     init_ = init;
     init_ = init;
   }
   }
 
 

+ 2 - 2
explorer/ast/static_scope.cpp

@@ -54,7 +54,7 @@ void StaticScope::PrintID(llvm::raw_ostream& out) const {
 
 
 void StaticScope::MarkDeclared(std::string_view name) {
 void StaticScope::MarkDeclared(std::string_view name) {
   auto it = declared_names_.find(name);
   auto it = declared_names_.find(name);
-  CARBON_CHECK(it != declared_names_.end()) << name << " not found";
+  CARBON_CHECK(it != declared_names_.end(), "{0} not found", name);
   if (it->second.status == NameStatus::KnownButNotDeclared) {
   if (it->second.status == NameStatus::KnownButNotDeclared) {
     it->second.status = NameStatus::DeclaredButNotUsable;
     it->second.status = NameStatus::DeclaredButNotUsable;
     if (trace_stream_->is_enabled()) {
     if (trace_stream_->is_enabled()) {
@@ -67,7 +67,7 @@ void StaticScope::MarkDeclared(std::string_view name) {
 
 
 void StaticScope::MarkUsable(std::string_view name) {
 void StaticScope::MarkUsable(std::string_view name) {
   auto it = declared_names_.find(name);
   auto it = declared_names_.find(name);
-  CARBON_CHECK(it != declared_names_.end()) << name << " not found";
+  CARBON_CHECK(it != declared_names_.end(), "{0} not found", name);
   it->second.status = NameStatus::Usable;
   it->second.status = NameStatus::Usable;
   if (trace_stream_->is_enabled()) {
   if (trace_stream_->is_enabled()) {
     trace_stream_->Result()
     trace_stream_->Result()

+ 22 - 24
explorer/ast/value.cpp

@@ -159,8 +159,8 @@ static auto GetPositionalElement(Nonnull<const TupleValue*> tuple,
                                  const ElementPath::Component& path_comp,
                                  const ElementPath::Component& path_comp,
                                  SourceLocation source_loc)
                                  SourceLocation source_loc)
     -> ErrorOr<Nonnull<const Value*>> {
     -> ErrorOr<Nonnull<const Value*>> {
-  CARBON_CHECK(path_comp.element()->kind() == ElementKind::PositionalElement)
-      << "Invalid non-tuple member";
+  CARBON_CHECK(path_comp.element()->kind() == ElementKind::PositionalElement,
+               "Invalid non-tuple member");
   const auto* tuple_element = cast<PositionalElement>(path_comp.element());
   const auto* tuple_element = cast<PositionalElement>(path_comp.element());
   const size_t index = tuple_element->index();
   const size_t index = tuple_element->index();
   if (index < 0 || index >= tuple->elements().size()) {
   if (index < 0 || index >= tuple->elements().size()) {
@@ -175,8 +175,8 @@ static auto GetNamedElement(Nonnull<Arena*> arena, Nonnull<const Value*> v,
                             SourceLocation source_loc,
                             SourceLocation source_loc,
                             std::optional<Nonnull<const Value*>> me_value)
                             std::optional<Nonnull<const Value*>> me_value)
     -> ErrorOr<Nonnull<const Value*>> {
     -> ErrorOr<Nonnull<const Value*>> {
-  CARBON_CHECK(field.element()->kind() == ElementKind::NamedElement)
-      << "Invalid element, expecting NamedElement";
+  CARBON_CHECK(field.element()->kind() == ElementKind::NamedElement,
+               "Invalid element, expecting NamedElement");
   const auto* member = cast<NamedElement>(field.element());
   const auto* member = cast<NamedElement>(field.element());
   const auto f = member->name();
   const auto f = member->name();
   if (field.witness().has_value()) {
   if (field.witness().has_value()) {
@@ -186,7 +186,7 @@ static auto GetNamedElement(Nonnull<Arena*> arena, Nonnull<const Value*> v,
     if (const auto* assoc_const =
     if (const auto* assoc_const =
             dyn_cast_or_null<AssociatedConstantDeclaration>(
             dyn_cast_or_null<AssociatedConstantDeclaration>(
                 member->declaration().value_or(nullptr))) {
                 member->declaration().value_or(nullptr))) {
-      CARBON_CHECK(field.interface()) << "have witness but no interface";
+      CARBON_CHECK(field.interface(), "have witness but no interface");
       // TODO: Use witness to find the value of the constant.
       // TODO: Use witness to find the value of the constant.
       return arena->New<AssociatedConstant>(v, *field.interface(), assoc_const,
       return arena->New<AssociatedConstant>(v, *field.interface(), assoc_const,
                                             witness);
                                             witness);
@@ -259,8 +259,8 @@ static auto GetNamedElement(Nonnull<Arena*> arena, Nonnull<const Value*> v,
           // Get class value matching the virtual method, and turn it into a
           // Get class value matching the virtual method, and turn it into a
           // bound method.
           // bound method.
           for (int i = 0; i < level_diff; ++i) {
           for (int i = 0; i < level_diff; ++i) {
-            CARBON_CHECK(m_class_value->base())
-                << "Error trying to access function class value";
+            CARBON_CHECK(m_class_value->base(),
+                         "Error trying to access function class value");
             m_class_value = *m_class_value->base();
             m_class_value = *m_class_value->base();
           }
           }
           return arena->New<BoundMethodValue>(
           return arena->New<BoundMethodValue>(
@@ -299,7 +299,7 @@ static auto GetNamedElement(Nonnull<Arena*> arena, Nonnull<const Value*> v,
                                        &class_type.bindings());
                                        &class_type.bindings());
     }
     }
     default:
     default:
-      CARBON_FATAL() << "named element access not supported for value " << *v;
+      CARBON_FATAL("named element access not supported for value {0}", *v);
   }
   }
 }
 }
 
 
@@ -315,7 +315,7 @@ static auto GetElement(Nonnull<Arena*> arena, Nonnull<const Value*> v,
       if (const auto* tuple = dyn_cast<TupleValue>(v)) {
       if (const auto* tuple = dyn_cast<TupleValue>(v)) {
         return GetPositionalElement(tuple, path_comp, source_loc);
         return GetPositionalElement(tuple, path_comp, source_loc);
       } else {
       } else {
-        CARBON_FATAL() << "Invalid value for positional element";
+        CARBON_FATAL("Invalid value for positional element");
       }
       }
     }
     }
     case ElementKind::BaseElement:
     case ElementKind::BaseElement:
@@ -328,7 +328,7 @@ static auto GetElement(Nonnull<Arena*> arena, Nonnull<const Value*> v,
               ptr->address().ElementAddress(path_comp.element()));
               ptr->address().ElementAddress(path_comp.element()));
         }
         }
         default:
         default:
-          CARBON_FATAL() << "Invalid value for base element";
+          CARBON_FATAL("Invalid value for base element");
       }
       }
   }
   }
 }
 }
@@ -404,9 +404,9 @@ static auto SetFieldImpl(
     }
     }
     case Value::Kind::TupleType:
     case Value::Kind::TupleType:
     case Value::Kind::TupleValue: {
     case Value::Kind::TupleValue: {
-      CARBON_CHECK((*path_begin).element()->kind() ==
-                   ElementKind::PositionalElement)
-          << "Invalid non-positional member for tuple";
+      CARBON_CHECK(
+          (*path_begin).element()->kind() == ElementKind::PositionalElement,
+          "Invalid non-positional member for tuple");
       std::vector<Nonnull<const Value*>> elements =
       std::vector<Nonnull<const Value*>> elements =
           cast<TupleValueBase>(*value).elements();
           cast<TupleValueBase>(*value).elements();
       const size_t index =
       const size_t index =
@@ -425,7 +425,7 @@ static auto SetFieldImpl(
       }
       }
     }
     }
     default:
     default:
-      CARBON_FATAL() << "field access not allowed for value " << *value;
+      CARBON_FATAL("field access not allowed for value {0}", *value);
   }
   }
 }
 }
 
 
@@ -841,7 +841,7 @@ void IntrinsicConstraint::Print(llvm::raw_ostream& out) const {
 static auto BindingMapEqual(
 static auto BindingMapEqual(
     const BindingMap& map1, const BindingMap& map2,
     const BindingMap& map1, const BindingMap& map2,
     std::optional<Nonnull<const EqualityContext*>> equality_ctx) -> bool {
     std::optional<Nonnull<const EqualityContext*>> equality_ctx) -> bool {
-  CARBON_CHECK(map1.size() == map2.size()) << "maps should have same keys";
+  CARBON_CHECK(map1.size() == map2.size(), "maps should have same keys");
   for (const auto& [key, value] : map1) {
   for (const auto& [key, value] : map1) {
     if (!ValueEqual(value, map2.at(key), equality_ctx)) {
     if (!ValueEqual(value, map2.at(key), equality_ctx)) {
       return false;
       return false;
@@ -1025,17 +1025,16 @@ auto TypeEqual(Nonnull<const Value*> t1, Nonnull<const Value*> t2,
     case Value::Kind::MixinPseudoType:
     case Value::Kind::MixinPseudoType:
     case Value::Kind::TypeOfMixinPseudoType:
     case Value::Kind::TypeOfMixinPseudoType:
     case Value::Kind::TypeOfNamespaceName:
     case Value::Kind::TypeOfNamespaceName:
-      CARBON_FATAL() << "TypeEqual used to compare non-type values\n"
-                     << *t1 << "\n"
-                     << *t2;
+      CARBON_FATAL("TypeEqual used to compare non-type values\n{0}\n{1}", *t1,
+                   *t2);
     case Value::Kind::ImplWitness:
     case Value::Kind::ImplWitness:
     case Value::Kind::BindingWitness:
     case Value::Kind::BindingWitness:
     case Value::Kind::ConstraintWitness:
     case Value::Kind::ConstraintWitness:
     case Value::Kind::ConstraintImplWitness:
     case Value::Kind::ConstraintImplWitness:
-      CARBON_FATAL() << "TypeEqual: unexpected Witness";
+      CARBON_FATAL("TypeEqual: unexpected Witness");
       break;
       break;
     case Value::Kind::AutoType:
     case Value::Kind::AutoType:
-      CARBON_FATAL() << "TypeEqual: unexpected AutoType";
+      CARBON_FATAL("TypeEqual: unexpected AutoType");
       break;
       break;
   }
   }
 }
 }
@@ -1123,8 +1122,8 @@ static auto ValueStructurallyEqual(
           GetName(cast<ParameterizedEntityName>(v1)->declaration());
           GetName(cast<ParameterizedEntityName>(v1)->declaration());
       std::optional<std::string_view> name2 =
       std::optional<std::string_view> name2 =
           GetName(cast<ParameterizedEntityName>(v2)->declaration());
           GetName(cast<ParameterizedEntityName>(v2)->declaration());
-      CARBON_CHECK(name1.has_value() && name2.has_value())
-          << "parameterized name refers to unnamed declaration";
+      CARBON_CHECK(name1.has_value() && name2.has_value(),
+                   "parameterized name refers to unnamed declaration");
       return *name1 == *name2;
       return *name1 == *name2;
     }
     }
     case Value::Kind::AssociatedConstant: {
     case Value::Kind::AssociatedConstant: {
@@ -1171,8 +1170,7 @@ static auto ValueStructurallyEqual(
     case Value::Kind::MemberName:
     case Value::Kind::MemberName:
       // TODO: support pointer comparisons once we have a clearer distinction
       // TODO: support pointer comparisons once we have a clearer distinction
       // between pointers and lvalues.
       // between pointers and lvalues.
-      CARBON_FATAL() << "ValueEqual does not support this kind of value: "
-                     << *v1;
+      CARBON_FATAL("ValueEqual does not support this kind of value: {0}", *v1);
   }
   }
 }
 }
 
 

+ 10 - 10
explorer/ast/value.h

@@ -924,8 +924,8 @@ class MixinPseudoType : public Value {
  public:
  public:
   explicit MixinPseudoType(Nonnull<const MixinDeclaration*> declaration)
   explicit MixinPseudoType(Nonnull<const MixinDeclaration*> declaration)
       : Value(Kind::MixinPseudoType), declaration_(declaration) {
       : Value(Kind::MixinPseudoType), declaration_(declaration) {
-    CARBON_CHECK(!declaration->params().has_value())
-        << "missing arguments for parameterized mixin type";
+    CARBON_CHECK(!declaration->params().has_value(),
+                 "missing arguments for parameterized mixin type");
   }
   }
   explicit MixinPseudoType(Nonnull<const MixinDeclaration*> declaration,
   explicit MixinPseudoType(Nonnull<const MixinDeclaration*> declaration,
                            Nonnull<const Bindings*> bindings)
                            Nonnull<const Bindings*> bindings)
@@ -982,8 +982,8 @@ class InterfaceType : public Value {
  public:
  public:
   explicit InterfaceType(Nonnull<const InterfaceDeclaration*> declaration)
   explicit InterfaceType(Nonnull<const InterfaceDeclaration*> declaration)
       : Value(Kind::InterfaceType), declaration_(declaration) {
       : Value(Kind::InterfaceType), declaration_(declaration) {
-    CARBON_CHECK(!declaration->params().has_value())
-        << "missing arguments for parameterized interface type";
+    CARBON_CHECK(!declaration->params().has_value(),
+                 "missing arguments for parameterized interface type");
   }
   }
   explicit InterfaceType(Nonnull<const InterfaceDeclaration*> declaration,
   explicit InterfaceType(Nonnull<const InterfaceDeclaration*> declaration,
                          Nonnull<const Bindings*> bindings)
                          Nonnull<const Bindings*> bindings)
@@ -1334,8 +1334,8 @@ class ConstraintImplWitness : public Witness {
   // element.
   // element.
   static auto Make(Nonnull<Arena*> arena, Nonnull<const Witness*> witness,
   static auto Make(Nonnull<Arena*> arena, Nonnull<const Witness*> witness,
                    int index) -> Nonnull<const Witness*> {
                    int index) -> Nonnull<const Witness*> {
-    CARBON_CHECK(!llvm::isa<ImplWitness>(witness))
-        << "impl witness has no components to access";
+    CARBON_CHECK(!llvm::isa<ImplWitness>(witness),
+                 "impl witness has no components to access");
     if (const auto* constraint_witness =
     if (const auto* constraint_witness =
             llvm::dyn_cast<ConstraintWitness>(witness)) {
             llvm::dyn_cast<ConstraintWitness>(witness)) {
       return constraint_witness->witnesses()[index];
       return constraint_witness->witnesses()[index];
@@ -1348,8 +1348,8 @@ class ConstraintImplWitness : public Witness {
       : Witness(Kind::ConstraintImplWitness),
       : Witness(Kind::ConstraintImplWitness),
         constraint_witness_(constraint_witness),
         constraint_witness_(constraint_witness),
         index_(index) {
         index_(index) {
-    CARBON_CHECK(!llvm::isa<ConstraintWitness>(constraint_witness))
-        << "should have resolved element from constraint witness";
+    CARBON_CHECK(!llvm::isa<ConstraintWitness>(constraint_witness),
+                 "should have resolved element from constraint witness");
   }
   }
 
 
   static auto classof(const Value* value) -> bool {
   static auto classof(const Value* value) -> bool {
@@ -1480,8 +1480,8 @@ class MemberName : public Value, public Printable<MemberName> {
         base_type_(base_type),
         base_type_(base_type),
         interface_(interface),
         interface_(interface),
         member_(member) {
         member_(member) {
-    CARBON_CHECK(base_type || interface)
-        << "member name must be in a type, an interface, or both";
+    CARBON_CHECK(base_type || interface,
+                 "member name must be in a type, an interface, or both");
   }
   }
 
 
   static auto classof(const Value* value) -> bool {
   static auto classof(const Value* value) -> bool {

+ 2 - 2
explorer/file_test.cpp

@@ -23,8 +23,8 @@ class ExplorerFileTest : public FileTestBase {
       : FileTestBase(test_name),
       : FileTestBase(test_name),
         prelude_line_re_(R"(prelude.carbon:(\d+))"),
         prelude_line_re_(R"(prelude.carbon:(\d+))"),
         timing_re_(R"((Time elapsed in \w+: )\d+(ms))") {
         timing_re_(R"((Time elapsed in \w+: )\d+(ms))") {
-    CARBON_CHECK(prelude_line_re_.ok()) << prelude_line_re_.error();
-    CARBON_CHECK(timing_re_.ok()) << timing_re_.error();
+    CARBON_CHECK(prelude_line_re_.ok(), "{0}", prelude_line_re_.error());
+    CARBON_CHECK(timing_re_.ok(), "{0}", timing_re_.error());
   }
   }
 
 
   auto Run(const llvm::SmallVector<llvm::StringRef>& test_args,
   auto Run(const llvm::SmallVector<llvm::StringRef>& test_args,

+ 9 - 9
explorer/fuzzing/ast_to_proto.cpp

@@ -638,10 +638,10 @@ static auto DeclarationToProto(const Declaration& declaration)
           default:
           default:
             // Parser shouldn't allow self_pattern to be anything other than
             // Parser shouldn't allow self_pattern to be anything other than
             // AddrPattern or BindingPattern
             // AddrPattern or BindingPattern
-            CARBON_FATAL()
-                << "self_pattern in method declaration can be either "
-                   "AddrPattern or BindingPattern. Actual pattern: "
-                << function.self_pattern();
+            CARBON_FATAL(
+                "self_pattern in method declaration can be either AddrPattern "
+                "or BindingPattern. Actual pattern: {0}",
+                function.self_pattern());
             break;
             break;
         }
         }
       }
       }
@@ -674,10 +674,10 @@ static auto DeclarationToProto(const Declaration& declaration)
           default:
           default:
             // Parser shouldn't allow self_pattern to be anything other than
             // Parser shouldn't allow self_pattern to be anything other than
             // AddrPattern or BindingPattern
             // AddrPattern or BindingPattern
-            CARBON_FATAL()
-                << "self_pattern in method declaration can be either "
-                   "AddrPattern or BindingPattern. Actual pattern: "
-                << function.self_pattern();
+            CARBON_FATAL(
+                "self_pattern in method declaration can be either AddrPattern "
+                "or BindingPattern. Actual pattern: {0}",
+                function.self_pattern());
             break;
             break;
         }
         }
       }
       }
@@ -833,7 +833,7 @@ static auto DeclarationToProto(const Declaration& declaration)
     }
     }
 
 
     case DeclarationKind::SelfDeclaration: {
     case DeclarationKind::SelfDeclaration: {
-      CARBON_FATAL() << "Unreachable SelfDeclaration in DeclarationToProto().";
+      CARBON_FATAL("Unreachable SelfDeclaration in DeclarationToProto().");
     }
     }
 
 
     case DeclarationKind::AliasDeclaration: {
     case DeclarationKind::AliasDeclaration: {

+ 2 - 2
explorer/fuzzing/fuzzer_util.cpp

@@ -38,10 +38,10 @@ auto ParseAndExecuteProto(const Fuzzing::Carbon& carbon) -> ErrorOr<int> {
   const ErrorOr<std::string> prelude_path =
   const ErrorOr<std::string> prelude_path =
       GetRunfilesFile("carbon/explorer/data/prelude.carbon");
       GetRunfilesFile("carbon/explorer/data/prelude.carbon");
   // Can't do anything without a prelude, so it's a fatal error.
   // Can't do anything without a prelude, so it's a fatal error.
-  CARBON_CHECK(prelude_path.ok()) << prelude_path.error();
+  CARBON_CHECK(prelude_path.ok(), "{0}", prelude_path.error());
   llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> prelude =
   llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> prelude =
       llvm::MemoryBuffer::getFile(*prelude_path);
       llvm::MemoryBuffer::getFile(*prelude_path);
-  CARBON_CHECK(!prelude.getError()) << prelude.getError().message();
+  CARBON_CHECK(!prelude.getError(), "{0}", prelude.getError().message());
   CARBON_CHECK(fs.addFile("prelude.carbon", /*ModificationTime=*/0,
   CARBON_CHECK(fs.addFile("prelude.carbon", /*ModificationTime=*/0,
                           std::move(*prelude)));
                           std::move(*prelude)));
 
 

+ 8 - 8
explorer/interpreter/action.cpp

@@ -56,19 +56,19 @@ void RuntimeScope::Bind(ValueNodeView value_node, Address address) {
   bool success =
   bool success =
       locals_.insert({value_node, heap_->arena().New<LocationValue>(address)})
       locals_.insert({value_node, heap_->arena().New<LocationValue>(address)})
           .second;
           .second;
-  CARBON_CHECK(success) << "Duplicate definition of " << value_node.base();
+  CARBON_CHECK(success, "Duplicate definition of {0}", value_node.base());
 }
 }
 
 
 void RuntimeScope::BindAndPin(ValueNodeView value_node, Address address) {
 void RuntimeScope::BindAndPin(ValueNodeView value_node, Address address) {
   Bind(value_node, address);
   Bind(value_node, address);
   bool success = bound_values_.insert(&value_node.base()).second;
   bool success = bound_values_.insert(&value_node.base()).second;
-  CARBON_CHECK(success) << "Duplicate pinned node for " << value_node.base();
+  CARBON_CHECK(success, "Duplicate pinned node for {0}", value_node.base());
   heap_->BindValueToReference(value_node, address);
   heap_->BindValueToReference(value_node, address);
 }
 }
 
 
 void RuntimeScope::BindLifetimeToScope(Address address) {
 void RuntimeScope::BindLifetimeToScope(Address address) {
-  CARBON_CHECK(address.element_path_.IsEmpty())
-      << "Cannot extend lifetime of a specific sub-element";
+  CARBON_CHECK(address.element_path_.IsEmpty(),
+               "Cannot extend lifetime of a specific sub-element");
   allocations_.push_back(address.allocation_);
   allocations_.push_back(address.allocation_);
 }
 }
 
 
@@ -77,7 +77,7 @@ void RuntimeScope::BindValue(ValueNodeView value_node,
   CARBON_CHECK(!value_node.constant_value().has_value());
   CARBON_CHECK(!value_node.constant_value().has_value());
   CARBON_CHECK(value->kind() != Value::Kind::LocationValue);
   CARBON_CHECK(value->kind() != Value::Kind::LocationValue);
   bool success = locals_.insert({value_node, value}).second;
   bool success = locals_.insert({value_node, value}).second;
-  CARBON_CHECK(success) << "Duplicate definition of " << value_node.base();
+  CARBON_CHECK(success, "Duplicate definition of {0}", value_node.base());
 }
 }
 
 
 auto RuntimeScope::Initialize(ValueNodeView value_node,
 auto RuntimeScope::Initialize(ValueNodeView value_node,
@@ -89,7 +89,7 @@ auto RuntimeScope::Initialize(ValueNodeView value_node,
   const auto* location =
   const auto* location =
       heap_->arena().New<LocationValue>(Address(allocations_.back()));
       heap_->arena().New<LocationValue>(Address(allocations_.back()));
   bool success = locals_.insert({value_node, location}).second;
   bool success = locals_.insert({value_node, location}).second;
-  CARBON_CHECK(success) << "Duplicate definition of " << value_node.base();
+  CARBON_CHECK(success, "Duplicate definition of {0}", value_node.base());
   return location;
   return location;
 }
 }
 
 
@@ -97,11 +97,11 @@ void RuntimeScope::Merge(RuntimeScope other) {
   CARBON_CHECK(heap_ == other.heap_);
   CARBON_CHECK(heap_ == other.heap_);
   for (auto& element : other.locals_) {
   for (auto& element : other.locals_) {
     bool success = locals_.insert(element).second;
     bool success = locals_.insert(element).second;
-    CARBON_CHECK(success) << "Duplicate definition of " << element.first;
+    CARBON_CHECK(success, "Duplicate definition of {0}", element.first);
   }
   }
   for (const auto* element : other.bound_values_) {
   for (const auto* element : other.bound_values_) {
     bool success = bound_values_.insert(element).second;
     bool success = bound_values_.insert(element).second;
-    CARBON_CHECK(success) << "Duplicate bound value.";
+    CARBON_CHECK(success, "Duplicate bound value.");
   }
   }
   allocations_.insert(allocations_.end(), other.allocations_.begin(),
   allocations_.insert(allocations_.end(), other.allocations_.begin(),
                       other.allocations_.end());
                       other.allocations_.end());

+ 1 - 1
explorer/interpreter/action.h

@@ -346,7 +346,7 @@ class StatementAction : public Action {
 
 
   // Sets the location provided to an initializing expression.
   // Sets the location provided to an initializing expression.
   auto set_location_created(AllocationId location_created) {
   auto set_location_created(AllocationId location_created) {
-    CARBON_CHECK(!location_created_) << "location created set twice";
+    CARBON_CHECK(!location_created_, "location created set twice");
     location_created_ = location_created;
     location_created_ = location_created;
   }
   }
   // Returns the location provided to an initializing expression, if any.
   // Returns the location provided to an initializing expression, if any.

+ 7 - 7
explorer/interpreter/action_stack.cpp

@@ -92,7 +92,7 @@ void ActionStack::MergeScope(RuntimeScope scope) {
     globals_->Merge(std::move(scope));
     globals_->Merge(std::move(scope));
     return;
     return;
   }
   }
-  CARBON_FATAL() << "No current scope";
+  CARBON_FATAL("No current scope");
 }
 }
 
 
 namespace {
 namespace {
@@ -132,9 +132,9 @@ auto ActionStack::FinishAction() -> ErrorOr<Success> {
   std::unique_ptr<Action> act = Pop();
   std::unique_ptr<Action> act = Pop();
   switch (FinishActionKindFor(act->kind())) {
   switch (FinishActionKindFor(act->kind())) {
     case FinishActionKind::Value:
     case FinishActionKind::Value:
-      CARBON_FATAL() << "This kind of action must produce a result: " << *act;
+      CARBON_FATAL("This kind of action must produce a result: {0}", *act);
     case FinishActionKind::NeverCalled:
     case FinishActionKind::NeverCalled:
-      CARBON_FATAL() << "Should not call FinishAction for: " << *act;
+      CARBON_FATAL("Should not call FinishAction for: {0}", *act);
     case FinishActionKind::NoValue:
     case FinishActionKind::NoValue:
       PopScopes(scopes_to_destroy);
       PopScopes(scopes_to_destroy);
       break;
       break;
@@ -150,9 +150,9 @@ auto ActionStack::FinishAction(Nonnull<const Value*> result)
   std::unique_ptr<Action> act = Pop();
   std::unique_ptr<Action> act = Pop();
   switch (FinishActionKindFor(act->kind())) {
   switch (FinishActionKindFor(act->kind())) {
     case FinishActionKind::NoValue:
     case FinishActionKind::NoValue:
-      CARBON_FATAL() << "This kind of action cannot produce results: " << *act;
+      CARBON_FATAL("This kind of action cannot produce results: {0}", *act);
     case FinishActionKind::NeverCalled:
     case FinishActionKind::NeverCalled:
-      CARBON_FATAL() << "Should not call FinishAction for: " << *act;
+      CARBON_FATAL("Should not call FinishAction for: {0}", *act);
     case FinishActionKind::Value:
     case FinishActionKind::Value:
       PopScopes(scopes_to_destroy);
       PopScopes(scopes_to_destroy);
       SetResult(result);
       SetResult(result);
@@ -183,8 +183,8 @@ auto ActionStack::ReplaceWith(std::unique_ptr<Action> replacement)
     -> ErrorOr<Success> {
     -> ErrorOr<Success> {
   std::unique_ptr<Action> old = Pop();
   std::unique_ptr<Action> old = Pop();
   CARBON_CHECK(FinishActionKindFor(old->kind()) ==
   CARBON_CHECK(FinishActionKindFor(old->kind()) ==
-               FinishActionKindFor(replacement->kind()))
-      << "Can't replace action " << *old << " with " << *replacement;
+                   FinishActionKindFor(replacement->kind()),
+               "Can't replace action {0} with {1}", *old, *replacement);
   Push(std::move(replacement));
   Push(std::move(replacement));
   return Success();
   return Success();
 }
 }

+ 2 - 2
explorer/interpreter/heap.cpp

@@ -116,8 +116,8 @@ auto Heap::Deallocate(AllocationId allocation) -> ErrorOr<Success> {
   if (states_[allocation.index_] != ValueState::Dead) {
   if (states_[allocation.index_] != ValueState::Dead) {
     states_[allocation.index_] = ValueState::Dead;
     states_[allocation.index_] = ValueState::Dead;
   } else {
   } else {
-    CARBON_FATAL() << "deallocating an already dead value: "
-                   << *values_[allocation.index_];
+    CARBON_FATAL("deallocating an already dead value: {0}",
+                 *values_[allocation.index_]);
   }
   }
 
 
   if (trace_stream_->is_enabled()) {
   if (trace_stream_->is_enabled()) {

+ 7 - 7
explorer/interpreter/impl_scope.cpp

@@ -28,8 +28,8 @@ void ImplScope::Add(Nonnull<const Value*> iface,
                     const TypeChecker& type_checker,
                     const TypeChecker& type_checker,
                     std::optional<TypeStructureSortKey> sort_key) {
                     std::optional<TypeStructureSortKey> sort_key) {
   if (const auto* constraint = dyn_cast<ConstraintType>(iface)) {
   if (const auto* constraint = dyn_cast<ConstraintType>(iface)) {
-    CARBON_CHECK(!sort_key)
-        << "should only be given a sort key for an impl of an interface";
+    CARBON_CHECK(!sort_key,
+                 "should only be given a sort key for an impl of an interface");
     // The caller should have substituted `.Self` for `type` already.
     // The caller should have substituted `.Self` for `type` already.
     Add(constraint->impls_constraints(), deduced, impl_bindings, witness,
     Add(constraint->impls_constraints(), deduced, impl_bindings, witness,
         type_checker);
         type_checker);
@@ -85,8 +85,8 @@ static auto DiagnoseUnequalValues(SourceLocation source_loc,
                                   Nonnull<const Value*> b_evaluated,
                                   Nonnull<const Value*> b_evaluated,
                                   Nonnull<const EqualityContext*> equality_ctx)
                                   Nonnull<const EqualityContext*> equality_ctx)
     -> Error {
     -> Error {
-  CARBON_CHECK(!ValueEqual(a_evaluated, b_evaluated, equality_ctx))
-      << "expected unequal values";
+  CARBON_CHECK(!ValueEqual(a_evaluated, b_evaluated, equality_ctx),
+               "expected unequal values");
   auto error = ProgramError(source_loc);
   auto error = ProgramError(source_loc);
   error << "constraint requires that " << *a_written;
   error << "constraint requires that " << *a_written;
   if (!ValueEqual(a_written, a_evaluated, std::nullopt)) {
   if (!ValueEqual(a_written, a_evaluated, std::nullopt)) {
@@ -110,7 +110,7 @@ auto ImplScope::Resolve(Nonnull<const Value*> constraint_type,
       std::optional<Nonnull<const Witness*>> witness,
       std::optional<Nonnull<const Witness*>> witness,
       TryResolve(constraint_type, impl_type, source_loc, type_checker, bindings,
       TryResolve(constraint_type, impl_type, source_loc, type_checker, bindings,
                  /*diagnose_missing_impl=*/true));
                  /*diagnose_missing_impl=*/true));
-  CARBON_CHECK(witness) << "should have diagnosed missing impl";
+  CARBON_CHECK(witness, "should have diagnosed missing impl");
   return *witness;
   return *witness;
 }
 }
 
 
@@ -238,7 +238,7 @@ auto ImplScope::TryResolve(Nonnull<const Value*> constraint_type,
     }
     }
     return {type_checker.MakeConstraintWitness(std::move(witnesses))};
     return {type_checker.MakeConstraintWitness(std::move(witnesses))};
   }
   }
-  CARBON_FATAL() << "expected a constraint, not " << *constraint_type;
+  CARBON_FATAL("expected a constraint, not {0}", *constraint_type);
 }
 }
 
 
 auto ImplScope::VisitEqualValues(
 auto ImplScope::VisitEqualValues(
@@ -333,7 +333,7 @@ static auto CombineResults(Nonnull<const InterfaceType*> iface_type,
       return b;
       return b;
     }
     }
   }
   }
-  CARBON_CHECK(impl_a && impl_b) << "non-final impl should not be symbolic";
+  CARBON_CHECK(impl_a && impl_b, "non-final impl should not be symbolic");
 
 
   // At this point, we're comparing two `impl` declarations, and either they're
   // At this point, we're comparing two `impl` declarations, and either they're
   // both final or neither of them is.
   // both final or neither of them is.

+ 70 - 68
explorer/interpreter/interpreter.cpp

@@ -292,8 +292,8 @@ auto Interpreter::EvalPrim(Operator op, Nonnull<const Value*> /*static_type*/,
     case Operator::BitShiftLeft:
     case Operator::BitShiftLeft:
     case Operator::BitShiftRight:
     case Operator::BitShiftRight:
     case Operator::Complement:
     case Operator::Complement:
-      CARBON_FATAL() << "operator " << OperatorToString(op)
-                     << " should always be rewritten";
+      CARBON_FATAL("operator {0} should always be rewritten",
+                   OperatorToString(op));
   }
   }
 }
 }
 
 
@@ -320,7 +320,7 @@ auto Interpreter::StepLocation() -> ErrorOr<Success> {
           Nonnull<const Value*> value,
           Nonnull<const Value*> value,
           todo_.ValueOfNode(cast<IdentifierExpression>(exp).value_node(),
           todo_.ValueOfNode(cast<IdentifierExpression>(exp).value_node(),
                             exp.source_loc()));
                             exp.source_loc()));
-      CARBON_CHECK(isa<LocationValue>(value)) << *value;
+      CARBON_CHECK(isa<LocationValue>(value), "{0}", *value);
       return todo_.FinishAction(value);
       return todo_.FinishAction(value);
     }
     }
     case ExpressionKind::SimpleMemberAccessExpression: {
     case ExpressionKind::SimpleMemberAccessExpression: {
@@ -361,8 +361,8 @@ auto Interpreter::StepLocation() -> ErrorOr<Success> {
         if (constant_value) {
         if (constant_value) {
           return todo_.FinishAction(act.results().back());
           return todo_.FinishAction(act.results().back());
         }
         }
-        CARBON_CHECK(!access.member().interface().has_value())
-            << "unexpected location interface member";
+        CARBON_CHECK(!access.member().interface().has_value(),
+                     "unexpected location interface member");
         CARBON_ASSIGN_OR_RETURN(
         CARBON_ASSIGN_OR_RETURN(
             Nonnull<const Value*> val,
             Nonnull<const Value*> val,
             Convert(act.results()[0], *access.member().base_type(),
             Convert(act.results()[0], *access.member().base_type(),
@@ -411,8 +411,8 @@ auto Interpreter::StepLocation() -> ErrorOr<Success> {
         return todo_.ReplaceWith(std::make_unique<LocationAction>(*rewrite));
         return todo_.ReplaceWith(std::make_unique<LocationAction>(*rewrite));
       }
       }
       if (op.op() != Operator::Deref) {
       if (op.op() != Operator::Deref) {
-        CARBON_FATAL()
-            << "Can't treat primitive operator expression as location: " << exp;
+        CARBON_FATAL(
+            "Can't treat primitive operator expression as location: {0}", exp);
       }
       }
       if (act.pos() == 0) {
       if (act.pos() == 0) {
         return todo_.Spawn(
         return todo_.Spawn(
@@ -442,9 +442,9 @@ auto Interpreter::StepLocation() -> ErrorOr<Success> {
     case ExpressionKind::DotSelfExpression:
     case ExpressionKind::DotSelfExpression:
     case ExpressionKind::ArrayTypeLiteral:
     case ExpressionKind::ArrayTypeLiteral:
     case ExpressionKind::BuiltinConvertExpression:
     case ExpressionKind::BuiltinConvertExpression:
-      CARBON_FATAL() << "Can't treat expression as location: " << exp;
+      CARBON_FATAL("Can't treat expression as location: {0}", exp);
     case ExpressionKind::UnimplementedExpression:
     case ExpressionKind::UnimplementedExpression:
-      CARBON_FATAL() << "Unimplemented: " << exp;
+      CARBON_FATAL("Unimplemented: {0}", exp);
   }
   }
 }
 }
 
 
@@ -478,8 +478,8 @@ auto Interpreter::EvalAssociatedConstant(
 
 
   const auto* impl_witness = dyn_cast<ImplWitness>(witness);
   const auto* impl_witness = dyn_cast<ImplWitness>(witness);
   if (!impl_witness) {
   if (!impl_witness) {
-    CARBON_CHECK(phase() == Phase::CompileTime)
-        << "symbolic witnesses should only be formed at compile time";
+    CARBON_CHECK(phase() == Phase::CompileTime,
+                 "symbolic witnesses should only be formed at compile time");
     CARBON_ASSIGN_OR_RETURN(Nonnull<const Value*> base,
     CARBON_ASSIGN_OR_RETURN(Nonnull<const Value*> base,
                             InstantiateType(&assoc->base(), source_loc));
                             InstantiateType(&assoc->base(), source_loc));
     return arena_->New<AssociatedConstant>(base, cast<InterfaceType>(interface),
     return arena_->New<AssociatedConstant>(base, cast<InterfaceType>(interface),
@@ -500,10 +500,11 @@ auto Interpreter::EvalAssociatedConstant(
     }
     }
   }
   }
   if (!result) {
   if (!result) {
-    CARBON_FATAL() << impl_witness->declaration() << " with constraint "
-                   << *constraint
-                   << " is missing value for associated constant "
-                   << *interface << "." << assoc->constant().binding().name();
+    CARBON_FATAL(
+        "{0} with constraint {1} is missing value for associated constant "
+        "{2}.{3}",
+        impl_witness->declaration(), *constraint, *interface,
+        assoc->constant().binding().name());
   }
   }
   return *result;
   return *result;
 }
 }
@@ -615,9 +616,9 @@ auto Interpreter::ConvertStructToClass(
                           InstantiateType(class_type, source_loc));
                           InstantiateType(class_type, source_loc));
   for (const auto& field : init_struct->elements()) {
   for (const auto& field : init_struct->elements()) {
     if (field.name == NominalClassValue::BaseField) {
     if (field.name == NominalClassValue::BaseField) {
-      CARBON_CHECK(class_type->base().has_value())
-          << "Invalid 'base' field for class '"
-          << class_type->declaration().name() << "' without base class.";
+      CARBON_CHECK(class_type->base().has_value(),
+                   "Invalid 'base' field for class '{0}' without base class.",
+                   class_type->declaration().name());
       CARBON_ASSIGN_OR_RETURN(
       CARBON_ASSIGN_OR_RETURN(
           auto base,
           auto base,
           Convert(field.value, class_type->base().value(), source_loc));
           Convert(field.value, class_type->base().value(), source_loc));
@@ -626,8 +627,8 @@ auto Interpreter::ConvertStructToClass(
       struct_values.push_back(field);
       struct_values.push_back(field);
     }
     }
   }
   }
-  CARBON_CHECK(!cast<NominalClassType>(inst_class)->base() || base_instance)
-      << "Invalid conversion for `" << *inst_class << "`: base class missing";
+  CARBON_CHECK(!cast<NominalClassType>(inst_class)->base() || base_instance,
+               "Invalid conversion for `{0}`: base class missing", *inst_class);
   auto* converted_init_struct =
   auto* converted_init_struct =
       arena_->New<StructValue>(std::move(struct_values));
       arena_->New<StructValue>(std::move(struct_values));
   Nonnull<const NominalClassValue** const> class_value_ptr =
   Nonnull<const NominalClassValue** const> class_value_ptr =
@@ -714,15 +715,15 @@ auto Interpreter::Convert(Nonnull<const Value*> value,
         case Value::Kind::ConstraintType:
         case Value::Kind::ConstraintType:
         case Value::Kind::NamedConstraintType:
         case Value::Kind::NamedConstraintType:
         case Value::Kind::InterfaceType: {
         case Value::Kind::InterfaceType: {
-          CARBON_CHECK(struct_val.elements().empty())
-              << "only empty structs convert to `type`";
+          CARBON_CHECK(struct_val.elements().empty(),
+                       "only empty structs convert to `type`");
           return arena_->New<StructType>();
           return arena_->New<StructType>();
         }
         }
         default: {
         default: {
           CARBON_CHECK(IsValueKindDependent(destination_type) ||
           CARBON_CHECK(IsValueKindDependent(destination_type) ||
-                       isa<TypeType, ConstraintType>(destination_type))
-              << "Can't convert value " << *value << " to type "
-              << *destination_type;
+                           (isa<TypeType, ConstraintType>(destination_type)),
+                       "Can't convert value {0} to type {1}", *value,
+                       *destination_type);
           return value;
           return value;
         }
         }
       }
       }
@@ -757,9 +758,9 @@ auto Interpreter::Convert(Nonnull<const Value*> value,
         }
         }
         default: {
         default: {
           CARBON_CHECK(IsValueKindDependent(destination_type) ||
           CARBON_CHECK(IsValueKindDependent(destination_type) ||
-                       isa<TypeType, ConstraintType>(destination_type))
-              << "Can't convert value " << *value << " to type "
-              << *destination_type;
+                           (isa<TypeType, ConstraintType>(destination_type)),
+                       "Can't convert value {0} to type {1}", *value,
+                       *destination_type);
           return value;
           return value;
         }
         }
       }
       }
@@ -832,8 +833,8 @@ auto Interpreter::Convert(Nonnull<const Value*> value,
       const auto* src_ptr = cast<PointerValue>(value);
       const auto* src_ptr = cast<PointerValue>(value);
       CARBON_ASSIGN_OR_RETURN(const auto* pointee,
       CARBON_ASSIGN_OR_RETURN(const auto* pointee,
                               heap_.Read(src_ptr->address(), source_loc))
                               heap_.Read(src_ptr->address(), source_loc))
-      CARBON_CHECK(pointee->kind() == Value::Kind::NominalClassValue)
-          << "Unexpected pointer type";
+      CARBON_CHECK(pointee->kind() == Value::Kind::NominalClassValue,
+                   "Unexpected pointer type");
 
 
       // Conversion logic for subtyping for function arguments only.
       // Conversion logic for subtyping for function arguments only.
       // TODO: Drop when able to rewrite subtyping in TypeChecker for arguments.
       // TODO: Drop when able to rewrite subtyping in TypeChecker for arguments.
@@ -945,7 +946,7 @@ auto Interpreter::CallFunction(const CallExpression& call,
                                   ExpressionResult::Value(converted_args),
                                   ExpressionResult::Value(converted_args),
                                   call.source_loc(), &function_scope,
                                   call.source_loc(), &function_scope,
                                   generic_args, trace_stream_, this->arena_);
                                   generic_args, trace_stream_, this->arena_);
-      CARBON_CHECK(success) << "Failed to bind arguments to parameters";
+      CARBON_CHECK(success, "Failed to bind arguments to parameters");
       return todo_.Spawn(std::make_unique<StatementAction>(*function.body(),
       return todo_.Spawn(std::make_unique<StatementAction>(*function.body(),
                                                            location_received),
                                                            location_received),
                          std::move(function_scope));
                          std::move(function_scope));
@@ -977,7 +978,7 @@ auto Interpreter::CallFunction(const CallExpression& call,
           return todo_.FinishAction(arena_->New<ChoiceType>(
           return todo_.FinishAction(arena_->New<ChoiceType>(
               &cast<ChoiceDeclaration>(decl), bindings));
               &cast<ChoiceDeclaration>(decl), bindings));
         default:
         default:
-          CARBON_FATAL() << "unknown kind of ParameterizedEntityName " << decl;
+          CARBON_FATAL("unknown kind of ParameterizedEntityName {0}", decl);
       }
       }
     }
     }
     default:
     default:
@@ -997,8 +998,8 @@ auto Interpreter::CallDestructor(Nonnull<const DestructorDeclaration*> fun,
   BindSelfIfPresent(fun, receiver, method_scope, generic_args,
   BindSelfIfPresent(fun, receiver, method_scope, generic_args,
                     SourceLocation::DiagnosticsIgnored());
                     SourceLocation::DiagnosticsIgnored());
 
 
-  CARBON_CHECK(method.body().has_value())
-      << "Calling a method that's missing a body";
+  CARBON_CHECK(method.body().has_value(),
+               "Calling a method that's missing a body");
 
 
   auto act = std::make_unique<StatementAction>(*method.body(), std::nullopt);
   auto act = std::make_unique<StatementAction>(*method.body(), std::nullopt);
   return todo_.Spawn(std::unique_ptr<Action>(std::move(act)),
   return todo_.Spawn(std::unique_ptr<Action>(std::move(act)),
@@ -1019,7 +1020,7 @@ void Interpreter::BindSelfIfPresent(Nonnull<const CallableDeclaration*> decl,
       bool success =
       bool success =
           PatternMatch(placeholder, receiver, source_location, &method_scope,
           PatternMatch(placeholder, receiver, source_location, &method_scope,
                        generic_args, trace_stream_, this->arena_);
                        generic_args, trace_stream_, this->arena_);
-      CARBON_CHECK(success) << "Failed to bind self";
+      CARBON_CHECK(success, "Failed to bind self");
     }
     }
   } else {
   } else {
     // Mutable self with `[addr self: Self*]`
     // Mutable self with `[addr self: Self*]`
@@ -1036,7 +1037,7 @@ void Interpreter::BindSelfIfPresent(Nonnull<const CallableDeclaration*> decl,
     }
     }
     bool success = PatternMatch(self_pattern, v, source_location, &method_scope,
     bool success = PatternMatch(self_pattern, v, source_location, &method_scope,
                                 generic_args, trace_stream_, this->arena_);
                                 generic_args, trace_stream_, this->arena_);
-    CARBON_CHECK(success) << "Failed to bind addr self";
+    CARBON_CHECK(success, "Failed to bind addr self");
   }
   }
 }
 }
 
 
@@ -1245,8 +1246,8 @@ auto Interpreter::StepExp() -> ErrorOr<Success> {
                        dyn_cast<TypeOfMemberName>(&access.static_type())) {
                        dyn_cast<TypeOfMemberName>(&access.static_type())) {
           // The result is a member name, such as in `Type.field_name`. Form a
           // The result is a member name, such as in `Type.field_name`. Form a
           // suitable member name value.
           // suitable member name value.
-          CARBON_CHECK(phase() == Phase::CompileTime)
-              << "should not form MemberNames at runtime";
+          CARBON_CHECK(phase() == Phase::CompileTime,
+                       "should not form MemberNames at runtime");
           auto found_in_interface = access.found_in_interface();
           auto found_in_interface = access.found_in_interface();
           if (act.pos() == 1 && found_in_interface) {
           if (act.pos() == 1 && found_in_interface) {
             return todo_.Spawn(std::make_unique<TypeInstantiationAction>(
             return todo_.Spawn(std::make_unique<TypeInstantiationAction>(
@@ -1365,8 +1366,8 @@ auto Interpreter::StepExp() -> ErrorOr<Success> {
             return todo_.FinishAction(act.results().back());
             return todo_.FinishAction(act.results().back());
           }
           }
         } else if (forming_member_name) {
         } else if (forming_member_name) {
-          CARBON_CHECK(phase() == Phase::CompileTime)
-              << "should not form MemberNames at runtime";
+          CARBON_CHECK(phase() == Phase::CompileTime,
+                       "should not form MemberNames at runtime");
           if (auto found_in_interface = access.member().interface();
           if (auto found_in_interface = access.member().interface();
               found_in_interface && act.pos() == 1) {
               found_in_interface && act.pos() == 1) {
             return todo_.Spawn(std::make_unique<TypeInstantiationAction>(
             return todo_.Spawn(std::make_unique<TypeInstantiationAction>(
@@ -1378,9 +1379,9 @@ auto Interpreter::StepExp() -> ErrorOr<Success> {
             if (found_in_interface) {
             if (found_in_interface) {
               found_in_interface = cast<InterfaceType>(act.results().back());
               found_in_interface = cast<InterfaceType>(act.results().back());
             }
             }
-            CARBON_CHECK(!access.member().base_type().has_value())
-                << "compound member access forming a member name should be "
-                   "performing impl lookup";
+            CARBON_CHECK(!access.member().base_type().has_value(),
+                         "compound member access forming a member name should "
+                         "be performing impl lookup");
             auto* member_name =
             auto* member_name =
                 arena_->New<MemberName>(act.results()[0], found_in_interface,
                 arena_->New<MemberName>(act.results()[0], found_in_interface,
                                         &access.member().member());
                                         &access.member().member());
@@ -1427,8 +1428,8 @@ auto Interpreter::StepExp() -> ErrorOr<Success> {
             if (access.impl().has_value()) {
             if (access.impl().has_value()) {
               witness = cast<Witness>(act.results()[1]);
               witness = cast<Witness>(act.results()[1]);
             } else {
             } else {
-              CARBON_CHECK(access.member().base_type().has_value())
-                  << "compound access should have base type or impl";
+              CARBON_CHECK(access.member().base_type().has_value(),
+                           "compound access should have base type or impl");
               CARBON_ASSIGN_OR_RETURN(
               CARBON_ASSIGN_OR_RETURN(
                   object, Convert(object, *access.member().base_type(),
                   object, Convert(object, *access.member().base_type(),
                                   exp.source_loc()));
                                   exp.source_loc()));
@@ -1582,7 +1583,7 @@ auto Interpreter::StepExp() -> ErrorOr<Success> {
           return todo_.FinishAction(act.results()[function_call_pos]);
           return todo_.FinishAction(act.results()[function_call_pos]);
         }
         }
       } else {
       } else {
-        CARBON_FATAL() << "in StepValueExp with Call pos " << act.pos();
+        CARBON_FATAL("in StepValueExp with Call pos {0}", act.pos());
       }
       }
     }
     }
     case ExpressionKind::IntrinsicExpression: {
     case ExpressionKind::IntrinsicExpression: {
@@ -1622,7 +1623,7 @@ auto Interpreter::StepExp() -> ErrorOr<Success> {
               break;
               break;
             }
             }
             default:
             default:
-              CARBON_FATAL() << "Too many format args: " << num_format_args;
+              CARBON_FATAL("Too many format args: {0}", num_format_args);
           }
           }
           // Implicit newline; currently no way to disable it.
           // Implicit newline; currently no way to disable it.
           *print_stream_ << "\n";
           *print_stream_ << "\n";
@@ -1712,9 +1713,9 @@ auto Interpreter::StepExp() -> ErrorOr<Success> {
           // reproducible across builds/platforms.
           // reproducible across builds/platforms.
           int64_t r = (generator() % range) + low;
           int64_t r = (generator() % range) + low;
           CARBON_CHECK(r >= std::numeric_limits<int32_t>::min() &&
           CARBON_CHECK(r >= std::numeric_limits<int32_t>::min() &&
-                       r <= std::numeric_limits<int32_t>::max())
-              << "Non-int32 result: " << r;
-          CARBON_CHECK(r >= low && r <= high) << "Out-of-range result: " << r;
+                           r <= std::numeric_limits<int32_t>::max(),
+                       "Non-int32 result: {0}", r);
+          CARBON_CHECK(r >= low && r <= high, "Out-of-range result: {0}", r);
           return todo_.FinishAction(arena_->New<IntValue>(r));
           return todo_.FinishAction(arena_->New<IntValue>(r));
         }
         }
         case IntrinsicExpression::Intrinsic::ImplicitAs: {
         case IntrinsicExpression::Intrinsic::ImplicitAs: {
@@ -1747,8 +1748,8 @@ auto Interpreter::StepExp() -> ErrorOr<Success> {
           return todo_.FinishAction(result);
           return todo_.FinishAction(result);
         }
         }
         case IntrinsicExpression::Intrinsic::ImplicitAsConvert: {
         case IntrinsicExpression::Intrinsic::ImplicitAsConvert: {
-          CARBON_FATAL()
-              << "__intrinsic_implicit_as_convert should have been rewritten";
+          CARBON_FATAL(
+              "__intrinsic_implicit_as_convert should have been rewritten");
         }
         }
         case IntrinsicExpression::Intrinsic::IntEq: {
         case IntrinsicExpression::Intrinsic::IntEq: {
           CARBON_CHECK(args.size() == 2);
           CARBON_CHECK(args.size() == 2);
@@ -1891,7 +1892,7 @@ auto Interpreter::StepExp() -> ErrorOr<Success> {
     }
     }
     case ExpressionKind::WhereExpression: {
     case ExpressionKind::WhereExpression: {
       auto rewrite = cast<WhereExpression>(exp).rewritten_form();
       auto rewrite = cast<WhereExpression>(exp).rewritten_form();
-      CARBON_CHECK(rewrite) << "where expression should be rewritten";
+      CARBON_CHECK(rewrite, "where expression should be rewritten");
       return todo_.ReplaceWith(std::make_unique<ExpressionAction>(
       return todo_.ReplaceWith(std::make_unique<ExpressionAction>(
           *rewrite, act.preserve_nested_categories(), act.location_received()));
           *rewrite, act.preserve_nested_categories(), act.location_received()));
     }
     }
@@ -1919,7 +1920,7 @@ auto Interpreter::StepExp() -> ErrorOr<Success> {
       }
       }
     }
     }
     case ExpressionKind::UnimplementedExpression:
     case ExpressionKind::UnimplementedExpression:
-      CARBON_FATAL() << "Unimplemented: " << exp;
+      CARBON_FATAL("Unimplemented: {0}", exp);
   }  // switch (exp->kind)
   }  // switch (exp->kind)
 }
 }
 
 
@@ -1982,7 +1983,7 @@ auto Interpreter::StepWitness() -> ErrorOr<Success> {
     }
     }
 
 
     default:
     default:
-      CARBON_FATAL() << "unexpected kind of witness " << *witness;
+      CARBON_FATAL("unexpected kind of witness {0}", *witness);
   }
   }
 }
 }
 
 
@@ -2183,11 +2184,12 @@ auto Interpreter::StepStmt() -> ErrorOr<Success> {
           const auto init_location = act.location_created();
           const auto init_location = act.location_created();
           v = v_expr ? (*v_expr)->value() : result;
           v = v_expr ? (*v_expr)->value() : result;
           if (expr_category == ExpressionCategory::Reference) {
           if (expr_category == ExpressionCategory::Reference) {
-            CARBON_CHECK(v_expr) << "Expecting ReferenceExpressionValue from "
-                                    "reference expression";
+            CARBON_CHECK(
+                v_expr,
+                "Expecting ReferenceExpressionValue from reference expression");
             v_location = (*v_expr)->address();
             v_location = (*v_expr)->address();
-            CARBON_CHECK(v_location)
-                << "Expecting a valid address from reference expression";
+            CARBON_CHECK(v_location,
+                         "Expecting a valid address from reference expression");
           } else if (has_initializing_expr && init_location &&
           } else if (has_initializing_expr && init_location &&
                      heap_.is_initialized(*init_location)) {
                      heap_.is_initialized(*init_location)) {
             // Bind even if a conversion is necessary.
             // Bind even if a conversion is necessary.
@@ -2228,9 +2230,10 @@ auto Interpreter::StepStmt() -> ErrorOr<Success> {
               PatternMatch(p, ExpressionResult(v, v_location, expr_category),
               PatternMatch(p, ExpressionResult(v, v_location, expr_category),
                            stmt.source_loc(), &scope, generic_args,
                            stmt.source_loc(), &scope, generic_args,
                            trace_stream_, this->arena_);
                            trace_stream_, this->arena_);
-          CARBON_CHECK(matched)
-              << stmt.source_loc()
-              << ": internal error in variable definition, match failed";
+          CARBON_CHECK(
+              matched,
+              "{0}: internal error in variable definition, match failed",
+              stmt.source_loc());
         }
         }
         todo_.MergeScope(std::move(scope));
         todo_.MergeScope(std::move(scope));
         return todo_.FinishAction();
         return todo_.FinishAction();
@@ -2435,9 +2438,8 @@ auto Interpreter::StepDestroy() -> ErrorOr<Success> {
           const Address var_addr =
           const Address var_addr =
               object.ElementAddress(arena_->New<NamedElement>(var));
               object.ElementAddress(arena_->New<NamedElement>(var));
           const auto v = heap_.Read(var_addr, var->source_loc());
           const auto v = heap_.Read(var_addr, var->source_loc());
-          CARBON_CHECK(v.ok())
-              << "Failed to read member `" << var->binding().name()
-              << "` from class `" << class_decl.name() << "`";
+          CARBON_CHECK(v.ok(), "Failed to read member `{0}` from class `{1}`",
+                       var->binding().name(), class_decl.name());
           return todo_.Spawn(std::make_unique<DestroyAction>(
           return todo_.Spawn(std::make_unique<DestroyAction>(
               arena_->New<LocationValue>(var_addr), *v));
               arena_->New<LocationValue>(var_addr), *v));
         } else {
         } else {
@@ -2487,7 +2489,7 @@ auto Interpreter::StepDestroy() -> ErrorOr<Success> {
       todo_.Pop();
       todo_.Pop();
       return Success();
       return Success();
   }
   }
-  CARBON_FATAL() << "Unreachable";
+  CARBON_FATAL("Unreachable");
 }
 }
 
 
 auto Interpreter::StepCleanUp() -> ErrorOr<Success> {
 auto Interpreter::StepCleanUp() -> ErrorOr<Success> {
@@ -2577,9 +2579,9 @@ auto Interpreter::Step() -> ErrorOr<Success> {
       CARBON_RETURN_IF_ERROR(StepInstantiateType());
       CARBON_RETURN_IF_ERROR(StepInstantiateType());
       break;
       break;
     case Action::Kind::ScopeAction:
     case Action::Kind::ScopeAction:
-      CARBON_FATAL() << "ScopeAction escaped ActionStack";
+      CARBON_FATAL("ScopeAction escaped ActionStack");
     case Action::Kind::RecursiveAction:
     case Action::Kind::RecursiveAction:
-      CARBON_FATAL() << "Tried to step a RecursiveAction";
+      CARBON_FATAL("Tried to step a RecursiveAction");
   }  // switch
   }  // switch
   return Success();
   return Success();
 }
 }

+ 1 - 1
explorer/interpreter/matching_impl_set.cpp

@@ -118,7 +118,7 @@ MatchingImplSet::Match::Match(Nonnull<MatchingImplSet*> parent,
 }
 }
 
 
 MatchingImplSet::Match::~Match() {
 MatchingImplSet::Match::~Match() {
-  CARBON_CHECK(parent_->matches_.back() == this) << "match stack broken";
+  CARBON_CHECK(parent_->matches_.back() == this, "match stack broken");
   parent_->matches_.pop_back();
   parent_->matches_.pop_back();
 }
 }
 
 

+ 12 - 13
explorer/interpreter/pattern_match.cpp

@@ -30,8 +30,8 @@ static auto InitializePlaceholderValue(const ValueNodeView& value_node,
       } else {
       } else {
         // Location initialized by initializing expression, bind node to
         // Location initialized by initializing expression, bind node to
         // address.
         // address.
-        CARBON_CHECK(v.address())
-            << "Missing location from initializing expression";
+        CARBON_CHECK(v.address(),
+                     "Missing location from initializing expression");
         bindings->Bind(value_node, *v.address());
         bindings->Bind(value_node, *v.address());
       }
       }
       break;
       break;
@@ -41,19 +41,18 @@ static auto InitializePlaceholderValue(const ValueNodeView& value_node,
         bindings->BindValue(value_node, v.value());
         bindings->BindValue(value_node, v.value());
       } else if (v.expression_category() == ExpressionCategory::Reference) {
       } else if (v.expression_category() == ExpressionCategory::Reference) {
         // Bind the reference expression value directly.
         // Bind the reference expression value directly.
-        CARBON_CHECK(v.address())
-            << "Missing location from reference expression";
+        CARBON_CHECK(v.address(), "Missing location from reference expression");
         bindings->BindAndPin(value_node, *v.address());
         bindings->BindAndPin(value_node, *v.address());
       } else {
       } else {
         // Location initialized by initializing expression, bind node to
         // Location initialized by initializing expression, bind node to
         // address.
         // address.
-        CARBON_CHECK(v.address())
-            << "Missing location from initializing expression";
+        CARBON_CHECK(v.address(),
+                     "Missing location from initializing expression");
         bindings->Bind(value_node, *v.address());
         bindings->Bind(value_node, *v.address());
       }
       }
       break;
       break;
     case ExpressionCategory::Initializing:
     case ExpressionCategory::Initializing:
-      CARBON_FATAL() << "Cannot pattern match an initializing expression";
+      CARBON_FATAL("Cannot pattern match an initializing expression");
       break;
       break;
   }
   }
 }
 }
@@ -135,8 +134,8 @@ auto PatternMatch(Nonnull<const Value*> p, ExpressionResult v,
           return true;
           return true;
         }
         }
         default:
         default:
-          CARBON_FATAL() << "expected a tuple value in pattern, not "
-                         << *v.value();
+          CARBON_FATAL("expected a tuple value in pattern, not {0}",
+                       *v.value());
       }
       }
     case Value::Kind::StructValue: {
     case Value::Kind::StructValue: {
       const auto& p_struct = cast<StructValue>(*p);
       const auto& p_struct = cast<StructValue>(*p);
@@ -172,12 +171,12 @@ auto PatternMatch(Nonnull<const Value*> p, ExpressionResult v,
               source_loc, bindings, generic_args, trace_stream, arena);
               source_loc, bindings, generic_args, trace_stream, arena);
         }
         }
         default:
         default:
-          CARBON_FATAL() << "expected a choice alternative in pattern, not "
-                         << *v.value();
+          CARBON_FATAL("expected a choice alternative in pattern, not {0}",
+                       *v.value());
       }
       }
     case Value::Kind::UninitializedValue:
     case Value::Kind::UninitializedValue:
-      CARBON_FATAL() << "uninitialized value is not allowed in pattern "
-                     << *v.value();
+      CARBON_FATAL("uninitialized value is not allowed in pattern {0}",
+                   *v.value());
     case Value::Kind::FunctionType:
     case Value::Kind::FunctionType:
       switch (v.value()->kind()) {
       switch (v.value()->kind()) {
         case Value::Kind::FunctionType: {
         case Value::Kind::FunctionType: {

+ 7 - 7
explorer/interpreter/resolve_names.cpp

@@ -325,8 +325,8 @@ auto NameResolver::ResolveNamesImpl(Expression& expression,
       }
       }
       if (const auto* namespace_decl = dyn_cast<NamespaceDeclaration>(base)) {
       if (const auto* namespace_decl = dyn_cast<NamespaceDeclaration>(base)) {
         auto ns_it = namespace_scopes_.find(namespace_decl);
         auto ns_it = namespace_scopes_.find(namespace_decl);
-        CARBON_CHECK(ns_it != namespace_scopes_.end())
-            << "name resolved to undeclared namespace";
+        CARBON_CHECK(ns_it != namespace_scopes_.end(),
+                     "name resolved to undeclared namespace");
         CARBON_ASSIGN_OR_RETURN(
         CARBON_ASSIGN_OR_RETURN(
             const auto value_node,
             const auto value_node,
             ns_it->second.ResolveHere(scope, access.member_name(),
             ns_it->second.ResolveHere(scope, access.member_name(),
@@ -459,7 +459,7 @@ auto NameResolver::ResolveNamesImpl(Expression& expression,
     case ExpressionKind::ValueLiteral:
     case ExpressionKind::ValueLiteral:
     case ExpressionKind::BuiltinConvertExpression:
     case ExpressionKind::BuiltinConvertExpression:
     case ExpressionKind::BaseAccessExpression:
     case ExpressionKind::BaseAccessExpression:
-      CARBON_FATAL() << "should not exist before type checking";
+      CARBON_FATAL("should not exist before type checking");
     case ExpressionKind::UnimplementedExpression:
     case ExpressionKind::UnimplementedExpression:
       return ProgramError(expression.source_loc()) << "Unimplemented";
       return ProgramError(expression.source_loc()) << "Unimplemented";
   }
   }
@@ -603,9 +603,9 @@ auto NameResolver::ResolveNamesImpl(Statement& statement,
       }
       }
       CARBON_RETURN_IF_ERROR(ResolveNames(def.pattern(), enclosing_scope));
       CARBON_RETURN_IF_ERROR(ResolveNames(def.pattern(), enclosing_scope));
       if (def.is_returned()) {
       if (def.is_returned()) {
-        CARBON_CHECK(def.pattern().kind() == PatternKind::BindingPattern)
-            << def.pattern().source_loc()
-            << "returned var definition can only be a binding pattern";
+        CARBON_CHECK(def.pattern().kind() == PatternKind::BindingPattern,
+                     "{0}returned var definition can only be a binding pattern",
+                     def.pattern().source_loc());
         CARBON_RETURN_IF_ERROR(enclosing_scope.AddReturnedVar(
         CARBON_RETURN_IF_ERROR(enclosing_scope.AddReturnedVar(
             ValueNodeView(&cast<BindingPattern>(def.pattern()))));
             ValueNodeView(&cast<BindingPattern>(def.pattern()))));
       }
       }
@@ -924,7 +924,7 @@ auto NameResolver::ResolveNamesImpl(Declaration& declaration,
     }
     }
 
 
     case DeclarationKind::SelfDeclaration: {
     case DeclarationKind::SelfDeclaration: {
-      CARBON_FATAL() << "Unreachable: resolving names for `Self` declaration";
+      CARBON_FATAL("Unreachable: resolving names for `Self` declaration");
     }
     }
 
 
     case DeclarationKind::AliasDeclaration: {
     case DeclarationKind::AliasDeclaration: {

+ 2 - 2
explorer/interpreter/resolve_unformed.cpp

@@ -140,8 +140,8 @@ static auto ResolveUnformedImpl(Nonnull<TraceStream*> trace_stream,
     case ExpressionKind::OperatorExpression: {
     case ExpressionKind::OperatorExpression: {
       const auto& opt_exp = cast<OperatorExpression>(*expression);
       const auto& opt_exp = cast<OperatorExpression>(*expression);
       if (opt_exp.op() == Operator::AddressOf) {
       if (opt_exp.op() == Operator::AddressOf) {
-        CARBON_CHECK(opt_exp.arguments().size() == 1)
-            << "OperatorExpression with op & can only have 1 argument";
+        CARBON_CHECK(opt_exp.arguments().size() == 1,
+                     "OperatorExpression with op & can only have 1 argument");
         CARBON_RETURN_IF_ERROR(
         CARBON_RETURN_IF_ERROR(
             // When a variable is taken address of, defer the unformed check to
             // When a variable is taken address of, defer the unformed check to
             // runtime. A more sound analysis can be implemented when a
             // runtime. A more sound analysis can be implemented when a

+ 5 - 5
explorer/interpreter/stack.h

@@ -32,7 +32,7 @@ struct Stack {
   //
   //
   // - Requires: !this->IsEmpty()
   // - Requires: !this->IsEmpty()
   auto Pop() -> T {
   auto Pop() -> T {
-    CARBON_CHECK(!empty()) << "Can't pop from empty stack.";
+    CARBON_CHECK(!empty(), "Can't pop from empty stack.");
     auto r = std::move(elements_.back());
     auto r = std::move(elements_.back());
     elements_.pop_back();
     elements_.pop_back();
     return r;
     return r;
@@ -42,9 +42,9 @@ struct Stack {
   //
   //
   // - Requires: n >= 0 && n <= Count()
   // - Requires: n >= 0 && n <= Count()
   void Pop(int n) {
   void Pop(int n) {
-    CARBON_CHECK(n >= 0) << "Negative pop count disallowed.";
-    CARBON_CHECK(static_cast<size_t>(n) <= elements_.size())
-        << "Can only pop as many elements as stack has.";
+    CARBON_CHECK(n >= 0, "Negative pop count disallowed.");
+    CARBON_CHECK(static_cast<size_t>(n) <= elements_.size(),
+                 "Can only pop as many elements as stack has.");
     elements_.erase(elements_.end() - n, elements_.end());
     elements_.erase(elements_.end() - n, elements_.end());
   }
   }
 
 
@@ -52,7 +52,7 @@ struct Stack {
   //
   //
   // - Requires: !this->IsEmpty()
   // - Requires: !this->IsEmpty()
   auto Top() const -> const T& {
   auto Top() const -> const T& {
-    CARBON_CHECK(!empty()) << "Empty stack has no Top().";
+    CARBON_CHECK(!empty(), "Empty stack has no Top().");
     return elements_.back();
     return elements_.back();
   }
   }
 
 

+ 67 - 65
explorer/interpreter/type_checker.cpp

@@ -109,7 +109,7 @@ static auto ExpectCompleteType(SourceLocation source_loc,
     case Value::Kind::ParameterizedEntityName:
     case Value::Kind::ParameterizedEntityName:
     case Value::Kind::MemberName:
     case Value::Kind::MemberName:
     case Value::Kind::MixinPseudoType:
     case Value::Kind::MixinPseudoType:
-      CARBON_FATAL() << "should not see non-type values";
+      CARBON_FATAL("should not see non-type values");
 
 
     case Value::Kind::IntType:
     case Value::Kind::IntType:
     case Value::Kind::BoolType:
     case Value::Kind::BoolType:
@@ -195,7 +195,7 @@ static auto ExpectConcreteType(SourceLocation source_loc,
 // Returns whether `type` is a placeholder type, which is a second-class type
 // Returns whether `type` is a placeholder type, which is a second-class type
 // that cannot be the type of a binding but can be the type of an expression.
 // that cannot be the type of a binding but can be the type of an expression.
 static auto IsPlaceholderType(Nonnull<const Value*> type) -> bool {
 static auto IsPlaceholderType(Nonnull<const Value*> type) -> bool {
-  CARBON_CHECK(IsType(type)) << "expected a type, but found " << *type;
+  CARBON_CHECK(IsType(type), "expected a type, but found {0}", *type);
   return isa<TypeOfParameterizedEntityName, TypeOfMemberName,
   return isa<TypeOfParameterizedEntityName, TypeOfMemberName,
              TypeOfMixinPseudoType, TypeOfNamespaceName>(type);
              TypeOfMixinPseudoType, TypeOfNamespaceName>(type);
 }
 }
@@ -568,14 +568,14 @@ auto TypeChecker::BuildSubtypeConversion(Nonnull<Expression*> source,
   while (!TypeEqual(cur_class, dest_class, std::nullopt)) {
   while (!TypeEqual(cur_class, dest_class, std::nullopt)) {
     const auto src = src_class->declaration().name();
     const auto src = src_class->declaration().name();
     const auto base_class = cur_class->base();
     const auto base_class = cur_class->base();
-    CARBON_CHECK(base_class) << "Invalid subtyping conversion";
+    CARBON_CHECK(base_class, "Invalid subtyping conversion");
     auto* base_expr = arena_->New<BaseAccessExpression>(
     auto* base_expr = arena_->New<BaseAccessExpression>(
         source->source_loc(), last_expr,
         source->source_loc(), last_expr,
         arena_->New<BaseElement>(arena_->New<PointerType>(*base_class)));
         arena_->New<BaseElement>(arena_->New<PointerType>(*base_class)));
     last_expr = base_expr;
     last_expr = base_expr;
     cur_class = *base_class;
     cur_class = *base_class;
   }
   }
-  CARBON_CHECK(last_expr) << "Error, no conversion was needed";
+  CARBON_CHECK(last_expr, "Error, no conversion was needed");
   return last_expr;
   return last_expr;
 }
 }
 
 
@@ -758,7 +758,7 @@ auto TypeChecker::BuildBuiltinConversion(Nonnull<Expression*> source,
       return conversion_failed();
       return conversion_failed();
   }
   }
 
 
-  CARBON_FATAL() << "unreachable";
+  CARBON_FATAL("unreachable");
 }
 }
 
 
 auto TypeChecker::ImplicitlyConvert(std::string_view context,
 auto TypeChecker::ImplicitlyConvert(std::string_view context,
@@ -892,8 +892,8 @@ auto TypeChecker::IsIntrinsicConstraintSatisfied(
   // TODO: Check to see if this constraint is known in the current impl scope.
   // TODO: Check to see if this constraint is known in the current impl scope.
   switch (constraint.kind) {
   switch (constraint.kind) {
     case IntrinsicConstraint::ImplicitAs:
     case IntrinsicConstraint::ImplicitAs:
-      CARBON_CHECK(constraint.arguments.size() == 1)
-          << "wrong number of arguments for `__intrinsic_implicit_as`";
+      CARBON_CHECK(constraint.arguments.size() == 1,
+                   "wrong number of arguments for `__intrinsic_implicit_as`");
       CARBON_ASSIGN_OR_RETURN(
       CARBON_ASSIGN_OR_RETURN(
           bool convertible,
           bool convertible,
           IsBuiltinConversion(source_loc, constraint.type,
           IsBuiltinConversion(source_loc, constraint.type,
@@ -1007,7 +1007,7 @@ auto TypeChecker::ExpectNonPlaceholderType(SourceLocation source_loc,
     return ProgramError(source_loc)
     return ProgramError(source_loc)
            << "expected `.member_name` after name of " << *namespace_type;
            << "expected `.member_name` after name of " << *namespace_type;
   }
   }
-  CARBON_FATAL() << "unknown kind of placeholder type " << *type;
+  CARBON_FATAL("unknown kind of placeholder type {0}", *type);
 }
 }
 
 
 // Argument deduction matches two values and attempts to find a set of
 // Argument deduction matches two values and attempts to find a set of
@@ -1204,8 +1204,9 @@ auto TypeChecker::ArgumentDeduction::Deduce(Nonnull<const Value*> param,
               return diagnose_missing_field(param_struct, arg_field, false);
               return diagnose_missing_field(param_struct, arg_field, false);
             }
             }
           }
           }
-          CARBON_FATAL() << "field count mismatch but no missing field; "
-                         << "duplicate field name?";
+          CARBON_FATAL(
+              "field count mismatch but no missing field; duplicate field "
+              "name?");
         }
         }
       } else {
       } else {
         for (const auto [param_field, arg_field] :
         for (const auto [param_field, arg_field] :
@@ -1350,7 +1351,7 @@ auto TypeChecker::ArgumentDeduction::Deduce(Nonnull<const Value*> param,
     }
     }
     case Value::Kind::MixinPseudoType:
     case Value::Kind::MixinPseudoType:
     case Value::Kind::TypeOfMixinPseudoType:
     case Value::Kind::TypeOfMixinPseudoType:
-      CARBON_CHECK(false) << "Type expression must not contain Mixin types";
+      CARBON_CHECK(false, "Type expression must not contain Mixin types");
   }
   }
 }
 }
 
 
@@ -2515,13 +2516,13 @@ auto TypeChecker::DeduceCallBindings(
                            /*allow_implicit_conversion=*/true));
                            /*allow_implicit_conversion=*/true));
     }
     }
   }
   }
-  CARBON_CHECK(generic_params.empty())
-      << "did not find all generic parameters in parameter list";
+  CARBON_CHECK(generic_params.empty(),
+               "did not find all generic parameters in parameter list");
 
 
   CARBON_ASSIGN_OR_RETURN(
   CARBON_ASSIGN_OR_RETURN(
       std::optional<Bindings> bindings,
       std::optional<Bindings> bindings,
       deduction.Finish(*this, impl_scope, /*diagnose_deduction_failure=*/true));
       deduction.Finish(*this, impl_scope, /*diagnose_deduction_failure=*/true));
-  CARBON_CHECK(bindings) << "should have diagnosed deduction failure";
+  CARBON_CHECK(bindings, "should have diagnosed deduction failure");
   call.set_bindings(std::move(*bindings));
   call.set_bindings(std::move(*bindings));
 
 
   // Convert the arguments to the deduced and substituted parameter type.
   // Convert the arguments to the deduced and substituted parameter type.
@@ -2791,8 +2792,9 @@ auto TypeChecker::TypeCheckExpImpl(Nonnull<Expression*> e,
     case ExpressionKind::ValueLiteral:
     case ExpressionKind::ValueLiteral:
     case ExpressionKind::BuiltinConvertExpression:
     case ExpressionKind::BuiltinConvertExpression:
     case ExpressionKind::BaseAccessExpression:
     case ExpressionKind::BaseAccessExpression:
-      CARBON_FATAL() << "attempting to type check node " << *e
-                     << " generated during type checking";
+      CARBON_FATAL(
+          "attempting to type check node {0} generated during type checking",
+          *e);
     case ExpressionKind::IndexExpression: {
     case ExpressionKind::IndexExpression: {
       auto& index = cast<IndexExpression>(*e);
       auto& index = cast<IndexExpression>(*e);
       CARBON_RETURN_IF_ERROR(TypeCheckExp(&index.object(), impl_scope));
       CARBON_RETURN_IF_ERROR(TypeCheckExp(&index.object(), impl_scope));
@@ -2943,8 +2945,8 @@ auto TypeChecker::TypeCheckExpImpl(Nonnull<Expression*> e,
                 return ProgramError(access.source_loc())
                 return ProgramError(access.source_loc())
                        << "Member access to aliases is not yet supported.";
                        << "Member access to aliases is not yet supported.";
               default:
               default:
-                CARBON_FATAL() << "member " << access.member_name()
-                               << " is not a field or method";
+                CARBON_FATAL("member {0} is not a field or method",
+                             access.member_name());
                 break;
                 break;
             }
             }
             return Success();
             return Success();
@@ -3344,8 +3346,8 @@ auto TypeChecker::TypeCheckExpImpl(Nonnull<Expression*> e,
             // This should not be possible: the name of a static member
             // This should not be possible: the name of a static member
             // function should have function type not member name type.
             // function should have function type not member name type.
             CARBON_CHECK(!has_instance || is_instance_member ||
             CARBON_CHECK(!has_instance || is_instance_member ||
-                         !member_name.base_type().has_value())
-                << "vacuous compound member access";
+                             !member_name.base_type().has_value(),
+                         "vacuous compound member access");
             // If this is instance access, remove self bound from function type
             // If this is instance access, remove self bound from function type
             if (has_instance && is_instance_member) {
             if (has_instance && is_instance_member) {
               CARBON_RETURN_IF_ERROR(set_static_type_remove_self());
               CARBON_RETURN_IF_ERROR(set_static_type_remove_self());
@@ -3365,8 +3367,7 @@ auto TypeChecker::TypeCheckExpImpl(Nonnull<Expression*> e,
           access.set_expression_category(access.object().expression_category());
           access.set_expression_category(access.object().expression_category());
           return Success();
           return Success();
         default:
         default:
-          CARBON_FATAL() << "member " << member_name
-                         << " is not a field or method";
+          CARBON_FATAL("member {0} is not a field or method", member_name);
           break;
           break;
       }
       }
 
 
@@ -3674,10 +3675,11 @@ auto TypeChecker::TypeCheckExpImpl(Nonnull<Expression*> e,
 
 
           // Currently the only kinds of parameterized entities we support are
           // Currently the only kinds of parameterized entities we support are
           // types.
           // types.
-          CARBON_CHECK(
-              isa<ClassDeclaration, InterfaceDeclaration, ConstraintDeclaration,
-                  ChoiceDeclaration>(param_name.declaration()))
-              << "unknown type of ParameterizedEntityName for " << param_name;
+          CARBON_CHECK((isa<ClassDeclaration, InterfaceDeclaration,
+                            ConstraintDeclaration, ChoiceDeclaration>(
+                           param_name.declaration())),
+                       "unknown type of ParameterizedEntityName for {0}",
+                       param_name);
           call.set_static_type(arena_->New<TypeType>());
           call.set_static_type(arena_->New<TypeType>());
           call.set_expression_category(ExpressionCategory::Value);
           call.set_expression_category(ExpressionCategory::Value);
           return Success();
           return Success();
@@ -4109,7 +4111,7 @@ auto TypeChecker::TypeCheckExpImpl(Nonnull<Expression*> e,
       return Success();
       return Success();
     }
     }
     case ExpressionKind::UnimplementedExpression:
     case ExpressionKind::UnimplementedExpression:
-      CARBON_FATAL() << "Unimplemented: " << *e;
+      CARBON_FATAL("Unimplemented: {0}", *e);
     case ExpressionKind::ArrayTypeLiteral: {
     case ExpressionKind::ArrayTypeLiteral: {
       auto& array_literal = cast<ArrayTypeLiteral>(*e);
       auto& array_literal = cast<ArrayTypeLiteral>(*e);
       CARBON_ASSIGN_OR_RETURN(
       CARBON_ASSIGN_OR_RETURN(
@@ -4200,18 +4202,18 @@ auto TypeChecker::TypeCheckTypeExp(Nonnull<Expression*> type_expression,
                         arena_->New<TypeType>()));
                         arena_->New<TypeType>()));
   CARBON_ASSIGN_OR_RETURN(Nonnull<const Value*> type,
   CARBON_ASSIGN_OR_RETURN(Nonnull<const Value*> type,
                           InterpExp(type_expression));
                           InterpExp(type_expression));
-  CARBON_CHECK(IsType(type))
-      << "type expression did not produce a type, got " << *type;
+  CARBON_CHECK(IsType(type), "type expression did not produce a type, got {0}",
+               *type);
   if (concrete) {
   if (concrete) {
     if (TypeIsDeduceable(type)) {
     if (TypeIsDeduceable(type)) {
       return ProgramError(type_expression->source_loc())
       return ProgramError(type_expression->source_loc())
              << "`auto` is not permitted in this context";
              << "`auto` is not permitted in this context";
     }
     }
-    CARBON_CHECK(IsNonDeduceableType(type))
-        << "unknown kind of non-concrete type " << *type;
+    CARBON_CHECK(IsNonDeduceableType(type),
+                 "unknown kind of non-concrete type {0}", *type);
   }
   }
-  CARBON_CHECK(!IsPlaceholderType(type))
-      << "should be no way to write a placeholder type";
+  CARBON_CHECK(!IsPlaceholderType(type),
+               "should be no way to write a placeholder type");
   return type;
   return type;
 }
 }
 
 
@@ -4325,9 +4327,10 @@ auto TypeChecker::TypeCheckPattern(
                               arena_->New<TypeType>()));
                               arena_->New<TypeType>()));
         CARBON_ASSIGN_OR_RETURN(type, InterpExp(converted));
         CARBON_ASSIGN_OR_RETURN(type, InterpExp(converted));
       }
       }
-      CARBON_CHECK(IsType(type))
-          << "conversion to type succeeded but didn't produce a type, got "
-          << *type;
+      CARBON_CHECK(
+          IsType(type),
+          "conversion to type succeeded but didn't produce a type, got {0}",
+          *type);
       if (expected) {
       if (expected) {
         // TODO: Per proposal #2188, we should be performing conversions at
         // TODO: Per proposal #2188, we should be performing conversions at
         // this level rather than on the overall initializer.
         // this level rather than on the overall initializer.
@@ -4348,11 +4351,11 @@ auto TypeChecker::TypeCheckPattern(
         CARBON_RETURN_IF_ERROR(ExpectResolvedBindingType(binding, type));
         CARBON_RETURN_IF_ERROR(ExpectResolvedBindingType(binding, type));
       }
       }
 
 
-      CARBON_CHECK(IsNonDeduceableType(type))
-          << "did not resolve " << binding << " to concrete type, got "
-          << *type;
-      CARBON_CHECK(!IsPlaceholderType(type))
-          << "should be no way to write a placeholder type";
+      CARBON_CHECK(IsNonDeduceableType(type),
+                   "did not resolve {0} to concrete type, got {1}", binding,
+                   *type);
+      CARBON_CHECK(!IsPlaceholderType(type),
+                   "should be no way to write a placeholder type");
       binding.set_static_type(type);
       binding.set_static_type(type);
       binding.set_value(binding.name() != AnonymousName
       binding.set_value(binding.name() != AnonymousName
                             ? arena_->New<BindingPlaceholderValue>(&binding)
                             ? arena_->New<BindingPlaceholderValue>(&binding)
@@ -4897,7 +4900,7 @@ auto TypeChecker::DeclareCallableDeclaration(Nonnull<CallableDeclaration*> f,
                                              const ScopeInfo& scope_info)
                                              const ScopeInfo& scope_info)
     -> ErrorOr<Success> {
     -> ErrorOr<Success> {
   const auto name = GetName(*f);
   const auto name = GetName(*f);
-  CARBON_CHECK(name) << "Unexpected missing name for `" << *f << "`.";
+  CARBON_CHECK(name, "Unexpected missing name for `{0}`.", *f);
   if (trace_stream_->is_enabled()) {
   if (trace_stream_->is_enabled()) {
     trace_stream_->Start() << "declaring function `" << *name << "` ("
     trace_stream_->Start() << "declaring function `" << *name << "` ("
                            << f->source_loc() << ")\n";
                            << f->source_loc() << ")\n";
@@ -4997,7 +5000,7 @@ auto TypeChecker::DeclareCallableDeclaration(Nonnull<CallableDeclaration*> f,
           arena_->New<DestructorValue>(cast<DestructorDeclaration>(f)));
           arena_->New<DestructorValue>(cast<DestructorDeclaration>(f)));
       break;
       break;
     default:
     default:
-      CARBON_FATAL() << "f is not a callable declaration";
+      CARBON_FATAL("f is not a callable declaration");
   }
   }
 
 
   if (name == "Main") {
   if (name == "Main") {
@@ -5027,7 +5030,7 @@ auto TypeChecker::TypeCheckCallableDeclaration(Nonnull<CallableDeclaration*> f,
                                                const ImplScope& impl_scope)
                                                const ImplScope& impl_scope)
     -> ErrorOr<Success> {
     -> ErrorOr<Success> {
   auto name = GetName(*f);
   auto name = GetName(*f);
-  CARBON_CHECK(name) << "Unexpected missing name for `" << *f << "`.";
+  CARBON_CHECK(name, "Unexpected missing name for `{0}`.", *f);
   if (trace_stream_->is_enabled()) {
   if (trace_stream_->is_enabled()) {
     trace_stream_->Start() << "checking function `" << *name << "` ("
     trace_stream_->Start() << "checking function `" << *name << "` ("
                            << f->source_loc() << ")\n";
                            << f->source_loc() << ")\n";
@@ -5165,8 +5168,8 @@ auto TypeChecker::DeclareClassDeclaration(Nonnull<ClassDeclaration*> class_decl,
              << "Error declaring `" << fun->name() << "`"
              << "Error declaring `" << fun->name() << "`"
              << ": class functions cannot be virtual.";
              << ": class functions cannot be virtual.";
     }
     }
-    CARBON_CHECK(!fun->name().is_qualified())
-        << "qualified function name not permitted in class scope";
+    CARBON_CHECK(!fun->name().is_qualified(),
+                 "qualified function name not permitted in class scope");
 
 
     if (fun->virt_override() == VirtualOverride::Abstract &&
     if (fun->virt_override() == VirtualOverride::Abstract &&
         fun->body().has_value()) {
         fun->body().has_value()) {
@@ -5312,8 +5315,8 @@ auto TypeChecker::TypeCheckClassDeclaration(
   }
   }
   auto [it, inserted] =
   auto [it, inserted] =
       collected_members_.insert({class_decl, CollectedMembersMap()});
       collected_members_.insert({class_decl, CollectedMembersMap()});
-  CARBON_CHECK(inserted) << "Adding class " << class_decl->name()
-                         << " to collected_members_ must not fail";
+  CARBON_CHECK(inserted, "Adding class {0} to collected_members_ must not fail",
+               class_decl->name());
   for (Nonnull<Declaration*> m : class_decl->members()) {
   for (Nonnull<Declaration*> m : class_decl->members()) {
     CARBON_RETURN_IF_ERROR(TypeCheckDeclaration(m, class_scope, class_decl));
     CARBON_RETURN_IF_ERROR(TypeCheckDeclaration(m, class_scope, class_decl));
     CARBON_RETURN_IF_ERROR(CollectMember(class_decl, m));
     CARBON_RETURN_IF_ERROR(CollectMember(class_decl, m));
@@ -5459,8 +5462,8 @@ auto TypeChecker::DeclareConstraintTypeDeclaration(
     Nonnull<ConstraintTypeDeclaration*> constraint_decl,
     Nonnull<ConstraintTypeDeclaration*> constraint_decl,
     const ScopeInfo& scope_info) -> ErrorOr<Success> {
     const ScopeInfo& scope_info) -> ErrorOr<Success> {
   CARBON_CHECK(
   CARBON_CHECK(
-      isa<InterfaceDeclaration, ConstraintDeclaration>(constraint_decl))
-      << "unexpected kind of constraint type declaration";
+      (isa<InterfaceDeclaration, ConstraintDeclaration>(constraint_decl)),
+      "unexpected kind of constraint type declaration");
   bool is_interface = isa<InterfaceDeclaration>(constraint_decl);
   bool is_interface = isa<InterfaceDeclaration>(constraint_decl);
 
 
   if (trace_stream_->is_enabled()) {
   if (trace_stream_->is_enabled()) {
@@ -5635,9 +5638,8 @@ auto TypeChecker::DeclareConstraintTypeDeclaration(
       }
       }
 
 
       default: {
       default: {
-        CARBON_FATAL()
-            << "unexpected declaration in constraint type declaration:\n"
-            << *m;
+        CARBON_FATAL(
+            "unexpected declaration in constraint type declaration:\n{0}", *m);
         break;
         break;
       }
       }
     }
     }
@@ -5728,7 +5730,7 @@ auto TypeChecker::CheckImplIsComplete(Nonnull<const InterfaceType*> iface_type,
     } else {
     } else {
       // Every member function must be declared.
       // Every member function must be declared.
       std::optional<std::string_view> mem_name = GetName(*m);
       std::optional<std::string_view> mem_name = GetName(*m);
-      CARBON_CHECK(mem_name.has_value()) << "unnamed interface member " << *m;
+      CARBON_CHECK(mem_name.has_value(), "unnamed interface member {0}", *m);
 
 
       std::optional<Nonnull<const Declaration*>> mem =
       std::optional<Nonnull<const Declaration*>> mem =
           FindMember(*mem_name, impl_decl->members());
           FindMember(*mem_name, impl_decl->members());
@@ -6129,11 +6131,11 @@ static auto IsValidTypeForAliasTarget(Nonnull<const Value*> type) -> bool {
     case Value::Kind::AlternativeConstructorValue:
     case Value::Kind::AlternativeConstructorValue:
     case Value::Kind::StringValue:
     case Value::Kind::StringValue:
     case Value::Kind::UninitializedValue:
     case Value::Kind::UninitializedValue:
-      CARBON_FATAL() << "type of alias target is not a type: " << *type;
+      CARBON_FATAL("type of alias target is not a type: {0}", *type);
 
 
     case Value::Kind::AutoType:
     case Value::Kind::AutoType:
     case Value::Kind::VariableType:
     case Value::Kind::VariableType:
-      CARBON_FATAL() << "pattern type in alias target: " << *type;
+      CARBON_FATAL("pattern type in alias target: {0}", *type);
 
 
     case Value::Kind::IntType:
     case Value::Kind::IntType:
     case Value::Kind::BoolType:
     case Value::Kind::BoolType:
@@ -6291,7 +6293,7 @@ auto TypeChecker::TypeCheckDeclaration(
       break;
       break;
     }
     }
     case DeclarationKind::SelfDeclaration: {
     case DeclarationKind::SelfDeclaration: {
-      CARBON_FATAL() << "Unreachable TypeChecker `Self` declaration";
+      CARBON_FATAL("Unreachable TypeChecker `Self` declaration");
     }
     }
     case DeclarationKind::AliasDeclaration: {
     case DeclarationKind::AliasDeclaration: {
       break;
       break;
@@ -6418,7 +6420,7 @@ auto TypeChecker::DeclareDeclaration(Nonnull<Declaration*> d,
     }
     }
 
 
     case DeclarationKind::SelfDeclaration: {
     case DeclarationKind::SelfDeclaration: {
-      CARBON_FATAL() << "Unreachable TypeChecker declare `Self` declaration";
+      CARBON_FATAL("Unreachable TypeChecker declare `Self` declaration");
     }
     }
 
 
     case DeclarationKind::AliasDeclaration: {
     case DeclarationKind::AliasDeclaration: {
@@ -6490,8 +6492,8 @@ auto TypeChecker::CollectMember(Nonnull<const Declaration*> enclosing_decl,
                                 Nonnull<const Declaration*> member_decl)
                                 Nonnull<const Declaration*> member_decl)
     -> ErrorOr<Success> {
     -> ErrorOr<Success> {
   CARBON_CHECK(isa<MixinDeclaration>(enclosing_decl) ||
   CARBON_CHECK(isa<MixinDeclaration>(enclosing_decl) ||
-               isa<ClassDeclaration>(enclosing_decl))
-      << "Can't collect members for " << *enclosing_decl;
+                   isa<ClassDeclaration>(enclosing_decl),
+               "Can't collect members for {0}", *enclosing_decl);
   auto member_name = GetName(*member_decl);
   auto member_name = GetName(*member_decl);
   if (!member_name.has_value()) {
   if (!member_name.has_value()) {
     // No need to collect members without a name
     // No need to collect members without a name
@@ -6532,7 +6534,7 @@ auto TypeChecker::FindCollectedMembers(Nonnull<const Declaration*> decl)
       return it->second;
       return it->second;
     }
     }
     default:
     default:
-      CARBON_FATAL() << "Can't collect members for " << *decl;
+      CARBON_FATAL("Can't collect members for {0}", *decl);
   }
   }
 }
 }
 
 
@@ -6585,8 +6587,8 @@ auto TypeChecker::InstantiateImplDeclaration(
         std::optional<Nonnull<const Value*>> witness;
         std::optional<Nonnull<const Value*>> witness;
         if (auto impl = param->impl_binding()) {
         if (auto impl = param->impl_binding()) {
           auto it = bindings->witnesses().find(*impl);
           auto it = bindings->witnesses().find(*impl);
-          CARBON_CHECK(it != bindings->witnesses().end())
-              << "no witness for generic binding";
+          CARBON_CHECK(it != bindings->witnesses().end(),
+                       "no witness for generic binding");
           witness = it->second;
           witness = it->second;
         }
         }
         new_bindings.Add(clone, value, witness);
         new_bindings.Add(clone, value, witness);
@@ -6604,8 +6606,8 @@ auto TypeChecker::InstantiateImplDeclaration(
   // TODO: It's probably not correct to use the top-level impl scope here. It's
   // TODO: It's probably not correct to use the top-level impl scope here. It's
   // not obvious what we should use, though -- which impls are in scope in
   // not obvious what we should use, though -- which impls are in scope in
   // template instantiation?
   // template instantiation?
-  CARBON_CHECK(top_level_impl_scope_)
-      << "can't perform template instantiation with no top-level scope";
+  CARBON_CHECK(top_level_impl_scope_,
+               "can't perform template instantiation with no top-level scope");
   ImplScope scope(*top_level_impl_scope_);
   ImplScope scope(*top_level_impl_scope_);
 
 
   // Bring all impls from any checked generic bindings in the template
   // Bring all impls from any checked generic bindings in the template

+ 2 - 2
explorer/interpreter/type_utils.cpp

@@ -81,7 +81,7 @@ auto IsType(Nonnull<const Value*> value) -> bool {
 }
 }
 
 
 auto TypeIsDeduceable(Nonnull<const Value*> type) -> bool {
 auto TypeIsDeduceable(Nonnull<const Value*> type) -> bool {
-  CARBON_CHECK(IsType(type)) << "expected a type, but found " << *type;
+  CARBON_CHECK(IsType(type), "expected a type, but found {0}", *type);
 
 
   switch (type->kind()) {
   switch (type->kind()) {
     case Value::Kind::IntValue:
     case Value::Kind::IntValue:
@@ -108,7 +108,7 @@ auto TypeIsDeduceable(Nonnull<const Value*> type) -> bool {
     case Value::Kind::ParameterizedEntityName:
     case Value::Kind::ParameterizedEntityName:
     case Value::Kind::MemberName:
     case Value::Kind::MemberName:
     case Value::Kind::MixinPseudoType:
     case Value::Kind::MixinPseudoType:
-      CARBON_FATAL() << "non-type value";
+      CARBON_FATAL("non-type value");
     case Value::Kind::IntType:
     case Value::Kind::IntType:
     case Value::Kind::BoolType:
     case Value::Kind::BoolType:
     case Value::Kind::TypeType:
     case Value::Kind::TypeType:

+ 2 - 2
explorer/syntax/parse.cpp

@@ -36,8 +36,8 @@ static auto ParseImpl(yyscan_t scanner, Nonnull<Arena*> arena,
   }
   }
 
 
   // Return parse results.
   // Return parse results.
-  CARBON_CHECK(ast != std::nullopt)
-      << "parser validated syntax yet didn't produce an AST.";
+  CARBON_CHECK(ast != std::nullopt,
+               "parser validated syntax yet didn't produce an AST.");
   return *ast;
   return *ast;
 }
 }
 
 

+ 1 - 2
explorer/syntax/prelude.cpp

@@ -19,8 +19,7 @@ void AddPrelude(llvm::vfs::FileSystem& fs, std::string_view prelude_file_name,
     // Try again with tracing, to help diagnose the problem.
     // Try again with tracing, to help diagnose the problem.
     ErrorOr<AST> trace_parse_result =
     ErrorOr<AST> trace_parse_result =
         Parse(fs, arena, prelude_file_name, FileKind::Prelude, true);
         Parse(fs, arena, prelude_file_name, FileKind::Prelude, true);
-    CARBON_FATAL() << "Failed to parse prelude:\n"
-                   << trace_parse_result.error();
+    CARBON_FATAL("Failed to parse prelude:\n{0}", trace_parse_result.error());
   }
   }
   const auto& prelude = *parse_result;
   const auto& prelude = *parse_result;
   declarations->insert(declarations->begin(), prelude.declarations.begin(),
   declarations->insert(declarations->begin(), prelude.declarations.begin(),

+ 2 - 2
migrate_cpp/rewriter_test.cpp

@@ -27,8 +27,8 @@ class Annotations {
     }
     }
     start_ = index;
     start_ = index;
     end_ = annotated_source.find("]]$", index);
     end_ = annotated_source.find("]]$", index);
-    CARBON_CHECK(end_ != llvm::StringRef::npos)
-        << "Found `$[[` but no matching `]]$`";
+    CARBON_CHECK(end_ != llvm::StringRef::npos,
+                 "Found `$[[` but no matching `]]$`");
     source_code_ = (llvm::Twine(annotated_source.substr(0, start_)) +
     source_code_ = (llvm::Twine(annotated_source.substr(0, start_)) +
                     annotated_source.substr(start_ + 3, end_ - start_ - 3) +
                     annotated_source.substr(start_ + 3, end_ - start_ - 3) +
                     annotated_source.substr(end_ + 3))
                     annotated_source.substr(end_ + 3))

+ 4 - 3
testing/base/global_exe_path.cpp

@@ -14,13 +14,14 @@ static constinit std::optional<std::string> exe_path = {};
 namespace Carbon::Testing {
 namespace Carbon::Testing {
 
 
 auto GetExePath() -> llvm::StringRef {
 auto GetExePath() -> llvm::StringRef {
-  CARBON_CHECK(exe_path)
-      << "Must not query the executable path until after it has been set!";
+  CARBON_CHECK(
+      exe_path,
+      "Must not query the executable path until after it has been set!");
   return *exe_path;
   return *exe_path;
 }
 }
 
 
 auto SetExePath(const char* argv_zero) -> void {
 auto SetExePath(const char* argv_zero) -> void {
-  CARBON_CHECK(!exe_path) << "Must not call `SetExePath` more than once!";
+  CARBON_CHECK(!exe_path, "Must not call `SetExePath` more than once!");
   exe_path.emplace(Carbon::FindExecutablePath(argv_zero));
   exe_path.emplace(Carbon::FindExecutablePath(argv_zero));
 }
 }
 
 

+ 21 - 21
testing/base/source_gen.cpp

@@ -152,10 +152,11 @@ auto SourceGen::ClassGenState::GetValidTypeName() -> llvm::StringRef {
       return type_names_.pop_back_val();
       return type_names_.pop_back_val();
     }
     }
 
 
-    CARBON_CHECK(last_type_name_index_ != initial_last_type_name_index)
-        << "Failed to find a valid type name with " << type_names_.size()
-        << " candidates, an initial index of " << initial_last_type_name_index
-        << ", and with " << class_names_.size() << " classes left to emit!";
+    CARBON_CHECK(last_type_name_index_ != initial_last_type_name_index,
+                 "Failed to find a valid type name with {0} candidates, an "
+                 "initial index of {1}, and with {2} classes left to emit!",
+                 type_names_.size(), initial_last_type_name_index,
+                 class_names_.size());
   }
   }
 }
 }
 
 
@@ -319,8 +320,8 @@ auto SourceGen::GenAPIFileDenseDecls(int target_lines,
   // needs a blank line.
   // needs a blank line.
   constexpr int NumFileCommentLines = 4;
   constexpr int NumFileCommentLines = 4;
   double avg_class_lines = EstimateAvgClassDefLines(params.class_params);
   double avg_class_lines = EstimateAvgClassDefLines(params.class_params);
-  CARBON_CHECK(target_lines > NumFileCommentLines + avg_class_lines)
-      << "Not enough target lines to generate a single class!";
+  CARBON_CHECK(target_lines > NumFileCommentLines + avg_class_lines,
+               "Not enough target lines to generate a single class!");
   int num_classes = static_cast<double>(target_lines - NumFileCommentLines) /
   int num_classes = static_cast<double>(target_lines - NumFileCommentLines) /
                     (avg_class_lines + 1);
                     (avg_class_lines + 1);
   int expected_lines =
   int expected_lines =
@@ -372,9 +373,9 @@ auto SourceGen::GetShuffledIdentifiers(int number, int min_length,
 auto SourceGen::GetShuffledUniqueIdentifiers(int number, int min_length,
 auto SourceGen::GetShuffledUniqueIdentifiers(int number, int min_length,
                                              int max_length, bool uniform)
                                              int max_length, bool uniform)
     -> llvm::SmallVector<llvm::StringRef> {
     -> llvm::SmallVector<llvm::StringRef> {
-  CARBON_CHECK(min_length >= 4)
-      << "Cannot trivially guarantee enough distinct, unique identifiers for "
-         "lengths <= 3";
+  CARBON_CHECK(min_length >= 4,
+               "Cannot trivially guarantee enough distinct, unique identifiers "
+               "for lengths <= 3");
   llvm::SmallVector<llvm::StringRef> idents =
   llvm::SmallVector<llvm::StringRef> idents =
       GetUniqueIdentifiers(number, min_length, max_length, uniform);
       GetUniqueIdentifiers(number, min_length, max_length, uniform);
   std::shuffle(idents.begin(), idents.end(), rng_);
   std::shuffle(idents.begin(), idents.end(), rng_);
@@ -398,9 +399,9 @@ auto SourceGen::GetIdentifiers(int number, int min_length, int max_length,
 auto SourceGen::GetUniqueIdentifiers(int number, int min_length, int max_length,
 auto SourceGen::GetUniqueIdentifiers(int number, int min_length, int max_length,
                                      bool uniform)
                                      bool uniform)
     -> llvm::SmallVector<llvm::StringRef> {
     -> llvm::SmallVector<llvm::StringRef> {
-  CARBON_CHECK(min_length >= 4)
-      << "Cannot trivially guarantee enough distinct, unique identifiers for "
-         "lengths <= 3";
+  CARBON_CHECK(min_length >= 4,
+               "Cannot trivially guarantee enough distinct, unique identifiers "
+               "for lengths <= 3");
   llvm::SmallVector<llvm::StringRef> idents =
   llvm::SmallVector<llvm::StringRef> idents =
       GetIdentifiersImpl(number, min_length, max_length, uniform,
       GetIdentifiersImpl(number, min_length, max_length, uniform,
                          [this](int length, int length_count,
                          [this](int length, int length_count,
@@ -634,10 +635,10 @@ auto SourceGen::GetIdentifiersImpl(int number, int min_length, int max_length,
                                    llvm::function_ref<AppendFn> append)
                                    llvm::function_ref<AppendFn> append)
     -> llvm::SmallVector<llvm::StringRef> {
     -> llvm::SmallVector<llvm::StringRef> {
   CARBON_CHECK(min_length <= max_length);
   CARBON_CHECK(min_length <= max_length);
-  CARBON_CHECK(uniform || max_length <= 64)
-      << "Cannot produce a meaningful non-uniform distribution of lengths "
-         "longer than 64 as those are exceedingly rare in our observed data "
-         "sets.";
+  CARBON_CHECK(
+      uniform || max_length <= 64,
+      "Cannot produce a meaningful non-uniform distribution of lengths longer "
+      "than 64 as those are exceedingly rare in our observed data sets.");
 
 
   llvm::SmallVector<llvm::StringRef> idents;
   llvm::SmallVector<llvm::StringRef> idents;
   idents.reserve(number);
   idents.reserve(number);
@@ -667,11 +668,10 @@ auto SourceGen::GetIdentifiersImpl(int number, int min_length, int max_length,
     }
     }
     append(length, length_count, idents);
     append(length, length_count, idents);
   }
   }
-  CARBON_CHECK(number_rem == 0)
-      << "Unexpected number remaining: " << number_rem;
-  CARBON_CHECK(static_cast<int>(idents.size()) == number)
-      << "Ended up with " << idents.size()
-      << " identifiers instead of the requested " << number;
+  CARBON_CHECK(number_rem == 0, "Unexpected number remaining: {0}", number_rem);
+  CARBON_CHECK(static_cast<int>(idents.size()) == number,
+               "Ended up with {0} identifiers instead of the requested {1}",
+               idents.size(), number);
 
 
   return idents;
   return idents;
 }
 }

+ 13 - 13
testing/file_test/autoupdate.cpp

@@ -21,8 +21,8 @@ static auto ParseLineNumber(absl::string_view matched_line_number) -> int {
   trimmed = trimmed.trim();
   trimmed = trimmed.trim();
   // NOLINTNEXTLINE(google-runtime-int): API requirement.
   // NOLINTNEXTLINE(google-runtime-int): API requirement.
   long long val;
   long long val;
-  CARBON_CHECK(!llvm::getAsSignedInteger(trimmed, 10, val))
-      << matched_line_number;
+  CARBON_CHECK(!llvm::getAsSignedInteger(trimmed, 10, val), "{0}",
+               matched_line_number);
   return val;
   return val;
 }
 }
 
 
@@ -60,7 +60,7 @@ auto FileTestAutoupdater::CheckLine::RemapLineNumbers(
       RE2::PartialMatch(line_cursor, *replacement_->re, &matched_line_number);
       RE2::PartialMatch(line_cursor, *replacement_->re, &matched_line_number);
     }
     }
     if (matched_line_number.empty()) {
     if (matched_line_number.empty()) {
-      CARBON_CHECK(found_one) << line_;
+      CARBON_CHECK(found_one, "{0}", line_);
       return;
       return;
     }
     }
     found_one = true;
     found_one = true;
@@ -195,9 +195,9 @@ auto FileTestAutoupdater::BuildCheckLines(llvm::StringRef output,
       absl::string_view filename;
       absl::string_view filename;
       if (RE2::PartialMatch(line, *default_file_re_, &filename)) {
       if (RE2::PartialMatch(line, *default_file_re_, &filename)) {
         auto it = file_to_number_map.find(filename);
         auto it = file_to_number_map.find(filename);
-        CARBON_CHECK(it != file_to_number_map.end())
-            << "default_file_re had unexpected match in '" << line << "' (`"
-            << default_file_re_->pattern() << "`)";
+        CARBON_CHECK(it != file_to_number_map.end(),
+                     "default_file_re had unexpected match in '{0}' (`{1}`)",
+                     line, default_file_re_->pattern());
         default_file_number = it->second;
         default_file_number = it->second;
       }
       }
     }
     }
@@ -218,7 +218,7 @@ auto FileTestAutoupdater::AddRemappedNonCheckLine() -> void {
 }
 }
 
 
 auto FileTestAutoupdater::AddTips() -> void {
 auto FileTestAutoupdater::AddTips() -> void {
-  CARBON_CHECK(tips_.empty()) << "Should only add tips once";
+  CARBON_CHECK(tips_.empty(), "Should only add tips once");
 
 
   tips_.reserve(4);
   tips_.reserve(4);
   // This puts commands on a single line so that they can be easily copied.
   // This puts commands on a single line so that they can be easily copied.
@@ -278,12 +278,12 @@ auto FileTestAutoupdater::StartSplitFile() -> void {
   // Advance the file.
   // Advance the file.
   ++output_file_number_;
   ++output_file_number_;
   output_line_number_ = 0;
   output_line_number_ = 0;
-  CARBON_CHECK(output_file_number_ == non_check_line_->file_number())
-      << "Non-sequential file: " << non_check_line_->file_number();
+  CARBON_CHECK(output_file_number_ == non_check_line_->file_number(),
+               "Non-sequential file: {0}", non_check_line_->file_number());
 
 
   // Each following file has precisely one split line.
   // Each following file has precisely one split line.
-  CARBON_CHECK(non_check_line_->line_number() < 1)
-      << "Expected a split line, got " << *non_check_line_;
+  CARBON_CHECK(non_check_line_->line_number() < 1,
+               "Expected a split line, got {0}", *non_check_line_);
   // The split line is ignored when calculating line counts.
   // The split line is ignored when calculating line counts.
   new_lines_.push_back(non_check_line_);
   new_lines_.push_back(non_check_line_);
 
 
@@ -300,8 +300,8 @@ auto FileTestAutoupdater::Run(bool dry_run) -> bool {
   // Print everything until the autoupdate line.
   // Print everything until the autoupdate line.
   while (non_check_line_->line_number() != autoupdate_line_number_) {
   while (non_check_line_->line_number() != autoupdate_line_number_) {
     CARBON_CHECK(non_check_line_ != non_check_lines_.end() &&
     CARBON_CHECK(non_check_line_ != non_check_lines_.end() &&
-                 non_check_line_->file_number() == 0)
-        << "Missed autoupdate?";
+                     non_check_line_->file_number() == 0,
+                 "Missed autoupdate?");
     AddRemappedNonCheckLine();
     AddRemappedNonCheckLine();
     ++non_check_line_;
     ++non_check_line_;
   }
   }

+ 6 - 5
testing/file_test/autoupdate.h

@@ -62,11 +62,12 @@ class FileTestAutoupdater {
             [&](const CheckLine& line) { return line.line_number() != -1; })),
             [&](const CheckLine& line) { return line.line_number() != -1; })),
         non_check_line_(non_check_lines_.begin()) {
         non_check_line_(non_check_lines_.begin()) {
     for (const auto& replacement : line_number_replacements_) {
     for (const auto& replacement : line_number_replacements_) {
-      CARBON_CHECK(replacement.has_file || default_file_re_)
-          << "For replacement with pattern `" << replacement.re->pattern()
-          << "` to have has_file=false, override GetDefaultFileRE.";
-      CARBON_CHECK(replacement.re->ok())
-          << "Invalid line replacement RE2: " << replacement.re->error();
+      CARBON_CHECK(replacement.has_file || default_file_re_,
+                   "For replacement with pattern `{0}` to have has_file=false, "
+                   "override GetDefaultFileRE.",
+                   replacement.re->pattern());
+      CARBON_CHECK(replacement.re->ok(), "Invalid line replacement RE2: {0}",
+                   replacement.re->error());
     }
     }
   }
   }
 
 

+ 3 - 3
testing/file_test/file_test_base.cpp

@@ -900,10 +900,10 @@ static auto GetTests() -> llvm::SmallVector<std::string> {
   }
   }
 
 
   // Extracts tests from the target file.
   // Extracts tests from the target file.
-  CARBON_CHECK(!absl::GetFlag(FLAGS_test_targets_file).empty())
-      << "Missing --test_targets_file.";
+  CARBON_CHECK(!absl::GetFlag(FLAGS_test_targets_file).empty(),
+               "Missing --test_targets_file.");
   auto content = ReadFile(absl::GetFlag(FLAGS_test_targets_file));
   auto content = ReadFile(absl::GetFlag(FLAGS_test_targets_file));
-  CARBON_CHECK(content.ok()) << content.error();
+  CARBON_CHECK(content.ok(), "{0}", content.error());
   llvm::SmallVector<std::string> all_tests;
   llvm::SmallVector<std::string> all_tests;
   for (llvm::StringRef file_ref : llvm::split(*content, "\n")) {
   for (llvm::StringRef file_ref : llvm::split(*content, "\n")) {
     if (file_ref.empty()) {
     if (file_ref.empty()) {

+ 3 - 3
toolchain/base/value_store.h

@@ -151,7 +151,7 @@ class ValueStore
   // Stores the value and returns an ID to reference it.
   // Stores the value and returns an ID to reference it.
   auto Add(ValueType value) -> IdT {
   auto Add(ValueType value) -> IdT {
     IdT id(values_.size());
     IdT id(values_.size());
-    CARBON_CHECK(id.index >= 0) << "Id overflow";
+    CARBON_CHECK(id.index >= 0, "Id overflow");
     values_.push_back(std::move(value));
     values_.push_back(std::move(value));
     return id;
     return id;
   }
   }
@@ -165,13 +165,13 @@ class ValueStore
 
 
   // Returns a mutable value for an ID.
   // Returns a mutable value for an ID.
   auto Get(IdT id) -> RefType {
   auto Get(IdT id) -> RefType {
-    CARBON_DCHECK(id.index >= 0) << id;
+    CARBON_DCHECK(id.index >= 0, "{0}", id);
     return values_[id.index];
     return values_[id.index];
   }
   }
 
 
   // Returns the value for an ID.
   // Returns the value for an ID.
   auto Get(IdT id) const -> ConstRefType {
   auto Get(IdT id) const -> ConstRefType {
-    CARBON_DCHECK(id.index >= 0) << id;
+    CARBON_DCHECK(id.index >= 0, "{0}", id);
     return values_[id.index];
     return values_[id.index];
   }
   }
 
 

+ 1 - 1
toolchain/base/yaml.h

@@ -94,7 +94,7 @@ struct llvm::yaml::ScalarTraits<Carbon::Yaml::OutputScalar> {
   }
   }
   static auto input(StringRef /*scalar*/, void* /*ctxt*/,
   static auto input(StringRef /*scalar*/, void* /*ctxt*/,
                     Carbon::Yaml::OutputScalar& /*value*/) -> StringRef {
                     Carbon::Yaml::OutputScalar& /*value*/) -> StringRef {
-    CARBON_FATAL() << "Input is unsupported.";
+    CARBON_FATAL("Input is unsupported.");
   }
   }
   static auto mustQuote(StringRef /*value*/) -> QuotingType {
   static auto mustQuote(StringRef /*value*/) -> QuotingType {
     return QuotingType::None;
     return QuotingType::None;

+ 19 - 20
toolchain/check/check.cpp

@@ -555,8 +555,8 @@ class DeferredDefinitionWorklist {
 
 
   // CHECK that the work list has no further work.
   // CHECK that the work list has no further work.
   auto VerifyEmpty() {
   auto VerifyEmpty() {
-    CARBON_CHECK(worklist_.empty() && entered_scopes_.empty())
-        << "Tasks left behind on worklist.";
+    CARBON_CHECK(worklist_.empty() && entered_scopes_.empty(),
+                 "Tasks left behind on worklist.");
   }
   }
 
 
  private:
  private:
@@ -627,8 +627,8 @@ auto DeferredDefinitionWorklist::SuspendFinishedScopeAndPush(Context& context)
   // worklist. We stay in that scope rather than suspending then immediately
   // worklist. We stay in that scope rather than suspending then immediately
   // resuming it.
   // resuming it.
   CARBON_CHECK(
   CARBON_CHECK(
-      holds_alternative<EnterDeferredDefinitionScope>(worklist_.back()))
-      << "Unexpected task in worklist.";
+      holds_alternative<EnterDeferredDefinitionScope>(worklist_.back()),
+      "Unexpected task in worklist.");
   worklist_.pop_back();
   worklist_.pop_back();
   CARBON_VLOG("{0}Handle EnterDeferredDefinitionScope (non-nested)\n",
   CARBON_VLOG("{0}Handle EnterDeferredDefinitionScope (non-nested)\n",
               VlogPrefix);
               VlogPrefix);
@@ -690,8 +690,8 @@ class NodeIdTraversal {
   auto PerformTask(
   auto PerformTask(
       DeferredDefinitionWorklist::EnterDeferredDefinitionScope&& enter)
       DeferredDefinitionWorklist::EnterDeferredDefinitionScope&& enter)
       -> void {
       -> void {
-    CARBON_CHECK(enter.suspended_name)
-        << "Entering a scope with no suspension information.";
+    CARBON_CHECK(enter.suspended_name,
+                 "Entering a scope with no suspension information.");
     context_.decl_name_stack().Restore(std::move(*enter.suspended_name));
     context_.decl_name_stack().Restore(std::move(*enter.suspended_name));
   }
   }
 
 
@@ -815,12 +815,10 @@ static auto DiagnoseMissingDefinitions(Context& context,
       case SemIR::InterfaceDecl::Kind: {
       case SemIR::InterfaceDecl::Kind: {
         // TODO: handle `interface` as well, once we can test it without
         // TODO: handle `interface` as well, once we can test it without
         // triggering https://github.com/carbon-language/carbon-lang/issues/4071
         // triggering https://github.com/carbon-language/carbon-lang/issues/4071
-        CARBON_FATAL()
-            << "TODO: Support interfaces in DiagnoseMissingDefinitions";
+        CARBON_FATAL("TODO: Support interfaces in DiagnoseMissingDefinitions");
       }
       }
       default: {
       default: {
-        CARBON_FATAL() << "Unexpected inst in definitions_required: "
-                       << decl_inst;
+        CARBON_FATAL("Unexpected inst in definitions_required: {0}", decl_inst);
       }
       }
     }
     }
   }
   }
@@ -851,14 +849,15 @@ static auto ProcessNodeIds(Context& context, llvm::raw_ostream* vlog_stream,
     auto parse_kind = context.parse_tree().node_kind(node_id);
     auto parse_kind = context.parse_tree().node_kind(node_id);
 
 
     switch (parse_kind) {
     switch (parse_kind) {
-#define CARBON_PARSE_NODE_KIND(Name)                                         \
-  case Parse::NodeKind::Name: {                                              \
-    if (!HandleParseNode(context, Parse::Name##Id(node_id))) {               \
-      CARBON_CHECK(err_tracker.seen_error())                                 \
-          << "Handle" #Name " returned false without printing a diagnostic"; \
-      return false;                                                          \
-    }                                                                        \
-    break;                                                                   \
+#define CARBON_PARSE_NODE_KIND(Name)                                 \
+  case Parse::NodeKind::Name: {                                      \
+    if (!HandleParseNode(context, Parse::Name##Id(node_id))) {       \
+      CARBON_CHECK(err_tracker.seen_error(),                         \
+                   "Handle" #Name                                    \
+                   " returned false without printing a diagnostic"); \
+      return false;                                                  \
+    }                                                                \
+    break;                                                           \
   }
   }
 #include "toolchain/parse/node_kind.def"
 #include "toolchain/parse/node_kind.def"
     }
     }
@@ -919,8 +918,8 @@ static auto CheckParseTree(
 
 
 #ifndef NDEBUG
 #ifndef NDEBUG
   if (auto verify = sem_ir.Verify(); !verify.ok()) {
   if (auto verify = sem_ir.Verify(); !verify.ok()) {
-    CARBON_FATAL() << sem_ir << "Built invalid semantics IR: " << verify.error()
-                   << "\n";
+    CARBON_FATAL("{0}Built invalid semantics IR: {1}\n", sem_ir,
+                 verify.error());
   }
   }
 #endif
 #endif
 }
 }

+ 1 - 1
toolchain/check/check_fuzzer.cpp

@@ -15,7 +15,7 @@ static const InstallPaths* install_paths = nullptr;
 
 
 // NOLINTNEXTLINE(readability-non-const-parameter): External API required types.
 // NOLINTNEXTLINE(readability-non-const-parameter): External API required types.
 extern "C" auto LLVMFuzzerInitialize(int* argc, char*** argv) -> int {
 extern "C" auto LLVMFuzzerInitialize(int* argc, char*** argv) -> int {
-  CARBON_CHECK(*argc >= 1) << "Need the `argv[0]` value to initialize!";
+  CARBON_CHECK(*argc >= 1, "Need the `argv[0]` value to initialize!");
   install_paths = new InstallPaths(
   install_paths = new InstallPaths(
       InstallPaths::MakeForBazelRunfiles(FindExecutablePath((*argv)[0])));
       InstallPaths::MakeForBazelRunfiles(FindExecutablePath((*argv)[0])));
   return 0;
   return 0;

+ 31 - 30
toolchain/check/context.cpp

@@ -142,9 +142,10 @@ auto Context::CheckCompatibleImportedNodeKind(
   auto& import_ir_inst = import_ir_insts().Get(imported_loc_id);
   auto& import_ir_inst = import_ir_insts().Get(imported_loc_id);
   const auto* import_ir = import_irs().Get(import_ir_inst.ir_id).sem_ir;
   const auto* import_ir = import_irs().Get(import_ir_inst.ir_id).sem_ir;
   auto imported_kind = import_ir->insts().Get(import_ir_inst.inst_id).kind();
   auto imported_kind = import_ir->insts().Get(import_ir_inst.inst_id).kind();
-  CARBON_CHECK(HasCompatibleImportedNodeKind(imported_kind, kind))
-      << "Node of kind " << kind
-      << " created with location of imported node of kind " << imported_kind;
+  CARBON_CHECK(
+      HasCompatibleImportedNodeKind(imported_kind, kind),
+      "Node of kind {0} created with location of imported node of kind {1}",
+      kind, imported_kind);
 }
 }
 
 
 auto Context::AddInstInNoBlock(SemIR::LocIdAndInst loc_id_and_inst)
 auto Context::AddInstInNoBlock(SemIR::LocIdAndInst loc_id_and_inst)
@@ -218,7 +219,7 @@ auto Context::DiagnoseNameNotFound(SemIRLoc loc, SemIR::NameId name_id)
 auto Context::NoteIncompleteClass(SemIR::ClassId class_id,
 auto Context::NoteIncompleteClass(SemIR::ClassId class_id,
                                   DiagnosticBuilder& builder) -> void {
                                   DiagnosticBuilder& builder) -> void {
   const auto& class_info = classes().Get(class_id);
   const auto& class_info = classes().Get(class_id);
-  CARBON_CHECK(!class_info.is_defined()) << "Class is not incomplete";
+  CARBON_CHECK(!class_info.is_defined(), "Class is not incomplete");
   if (class_info.definition_id.is_valid()) {
   if (class_info.definition_id.is_valid()) {
     CARBON_DIAGNOSTIC(ClassIncompleteWithinDefinition, Note,
     CARBON_DIAGNOSTIC(ClassIncompleteWithinDefinition, Note,
                       "Class is incomplete within its definition.");
                       "Class is incomplete within its definition.");
@@ -233,7 +234,7 @@ auto Context::NoteIncompleteClass(SemIR::ClassId class_id,
 auto Context::NoteUndefinedInterface(SemIR::InterfaceId interface_id,
 auto Context::NoteUndefinedInterface(SemIR::InterfaceId interface_id,
                                      DiagnosticBuilder& builder) -> void {
                                      DiagnosticBuilder& builder) -> void {
   const auto& interface_info = interfaces().Get(interface_id);
   const auto& interface_info = interfaces().Get(interface_id);
-  CARBON_CHECK(!interface_info.is_defined()) << "Interface is not incomplete";
+  CARBON_CHECK(!interface_info.is_defined(), "Interface is not incomplete");
   if (interface_info.is_being_defined()) {
   if (interface_info.is_being_defined()) {
     CARBON_DIAGNOSTIC(InterfaceUndefinedWithinDefinition, Note,
     CARBON_DIAGNOSTIC(InterfaceUndefinedWithinDefinition, Note,
                       "Interface is currently being defined.");
                       "Interface is currently being defined.");
@@ -389,7 +390,7 @@ static auto DiagnoseInvalidQualifiedNameAccess(Context& context, SemIRLoc loc,
                        class_info.adapt_id)) {
                        class_info.adapt_id)) {
       parent_type_id = adapt_decl->adapted_type_id;
       parent_type_id = adapt_decl->adapted_type_id;
     } else {
     } else {
-      CARBON_FATAL() << "Expected parent for parent access";
+      CARBON_FATAL("Expected parent for parent access");
     }
     }
   }
   }
 
 
@@ -615,7 +616,7 @@ auto Context::AddDominatedBlockAndBranchIf(Parse::NodeId node_id,
 
 
 auto Context::AddConvergenceBlockAndPush(Parse::NodeId node_id, int num_blocks)
 auto Context::AddConvergenceBlockAndPush(Parse::NodeId node_id, int num_blocks)
     -> void {
     -> void {
-  CARBON_CHECK(num_blocks >= 2) << "no convergence";
+  CARBON_CHECK(num_blocks >= 2, "no convergence");
 
 
   SemIR::InstBlockId new_block_id = SemIR::InstBlockId::Unreachable;
   SemIR::InstBlockId new_block_id = SemIR::InstBlockId::Unreachable;
   for ([[maybe_unused]] auto _ : llvm::seq(num_blocks)) {
   for ([[maybe_unused]] auto _ : llvm::seq(num_blocks)) {
@@ -633,7 +634,7 @@ auto Context::AddConvergenceBlockAndPush(Parse::NodeId node_id, int num_blocks)
 auto Context::AddConvergenceBlockWithArgAndPush(
 auto Context::AddConvergenceBlockWithArgAndPush(
     Parse::NodeId node_id, std::initializer_list<SemIR::InstId> block_args)
     Parse::NodeId node_id, std::initializer_list<SemIR::InstId> block_args)
     -> SemIR::InstId {
     -> SemIR::InstId {
-  CARBON_CHECK(block_args.size() >= 2) << "no convergence";
+  CARBON_CHECK(block_args.size() >= 2, "no convergence");
 
 
   SemIR::InstBlockId new_block_id = SemIR::InstBlockId::Unreachable;
   SemIR::InstBlockId new_block_id = SemIR::InstBlockId::Unreachable;
   for (auto arg_id : block_args) {
   for (auto arg_id : block_args) {
@@ -671,8 +672,8 @@ auto Context::SetBlockArgResultBeforeConstantUse(SemIR::InstId select_id,
     const_id = constant_values().Get(literal.value().value.ToBool() ? if_true
     const_id = constant_values().Get(literal.value().value.ToBool() ? if_true
                                                                     : if_false);
                                                                     : if_false);
   } else {
   } else {
-    CARBON_CHECK(cond_const_id == SemIR::ConstantId::Error)
-        << "Unexpected constant branch condition.";
+    CARBON_CHECK(cond_const_id == SemIR::ConstantId::Error,
+                 "Unexpected constant branch condition.");
     const_id = SemIR::ConstantId::Error;
     const_id = SemIR::ConstantId::Error;
   }
   }
 
 
@@ -684,11 +685,11 @@ auto Context::SetBlockArgResultBeforeConstantUse(SemIR::InstId select_id,
 }
 }
 
 
 auto Context::AddCurrentCodeBlockToFunction(Parse::NodeId node_id) -> void {
 auto Context::AddCurrentCodeBlockToFunction(Parse::NodeId node_id) -> void {
-  CARBON_CHECK(!inst_block_stack().empty()) << "no current code block";
+  CARBON_CHECK(!inst_block_stack().empty(), "no current code block");
 
 
   if (return_scope_stack().empty()) {
   if (return_scope_stack().empty()) {
-    CARBON_CHECK(node_id.is_valid())
-        << "No current function, but node_id not provided";
+    CARBON_CHECK(node_id.is_valid(),
+                 "No current function, but node_id not provided");
     TODO(node_id,
     TODO(node_id,
          "Control flow expressions are currently only supported inside "
          "Control flow expressions are currently only supported inside "
          "functions.");
          "functions.");
@@ -798,16 +799,16 @@ class TypeCompleter {
         if (!AddNestedIncompleteTypes(inst)) {
         if (!AddNestedIncompleteTypes(inst)) {
           return false;
           return false;
         }
         }
-        CARBON_CHECK(work_list_.size() >= old_work_list_size)
-            << "AddNestedIncompleteTypes should not remove work items";
+        CARBON_CHECK(work_list_.size() >= old_work_list_size,
+                     "AddNestedIncompleteTypes should not remove work items");
         work_list_[old_work_list_size - 1].phase = Phase::BuildValueRepr;
         work_list_[old_work_list_size - 1].phase = Phase::BuildValueRepr;
         break;
         break;
 
 
       case Phase::BuildValueRepr: {
       case Phase::BuildValueRepr: {
         auto value_rep = BuildValueRepr(type_id, inst);
         auto value_rep = BuildValueRepr(type_id, inst);
         context_.types().SetValueRepr(type_id, value_rep);
         context_.types().SetValueRepr(type_id, value_rep);
-        CARBON_CHECK(old_work_list_size == work_list_.size())
-            << "BuildValueRepr should not change work items";
+        CARBON_CHECK(old_work_list_size == work_list_.size(),
+                     "BuildValueRepr should not change work items");
         work_list_.pop_back();
         work_list_.pop_back();
 
 
         // Also complete the value representation type, if necessary. This
         // Also complete the value representation type, if necessary. This
@@ -919,11 +920,11 @@ class TypeCompleter {
   // Gets the value representation of a nested type, which should already be
   // Gets the value representation of a nested type, which should already be
   // complete.
   // complete.
   auto GetNestedValueRepr(SemIR::TypeId nested_type_id) const {
   auto GetNestedValueRepr(SemIR::TypeId nested_type_id) const {
-    CARBON_CHECK(context_.types().IsComplete(nested_type_id))
-        << "Nested type should already be complete";
+    CARBON_CHECK(context_.types().IsComplete(nested_type_id),
+                 "Nested type should already be complete");
     auto value_rep = context_.types().GetValueRepr(nested_type_id);
     auto value_rep = context_.types().GetValueRepr(nested_type_id);
-    CARBON_CHECK(value_rep.kind != SemIR::ValueRepr::Unknown)
-        << "Complete type should have a value representation";
+    CARBON_CHECK(value_rep.kind != SemIR::ValueRepr::Unknown,
+                 "Complete type should have a value representation");
     return value_rep;
     return value_rep;
   }
   }
 
 
@@ -1105,7 +1106,7 @@ class TypeCompleter {
     requires(InstT::Kind.is_type() == SemIR::InstIsType::Never)
     requires(InstT::Kind.is_type() == SemIR::InstIsType::Never)
   auto BuildValueReprForInst(SemIR::TypeId /*type_id*/, InstT inst) const
   auto BuildValueReprForInst(SemIR::TypeId /*type_id*/, InstT inst) const
       -> SemIR::ValueRepr {
       -> SemIR::ValueRepr {
-    CARBON_FATAL() << "Type refers to non-type inst " << inst;
+    CARBON_FATAL("Type refers to non-type inst {0}", inst);
   }
   }
 
 
   // Builds and returns the value representation for the given type. All nested
   // Builds and returns the value representation for the given type. All nested
@@ -1173,16 +1174,16 @@ auto Context::TryToDefineType(SemIR::TypeId type_id,
 
 
 auto Context::GetTypeIdForTypeConstant(SemIR::ConstantId constant_id)
 auto Context::GetTypeIdForTypeConstant(SemIR::ConstantId constant_id)
     -> SemIR::TypeId {
     -> SemIR::TypeId {
-  CARBON_CHECK(constant_id.is_constant())
-      << "Canonicalizing non-constant type: " << constant_id;
+  CARBON_CHECK(constant_id.is_constant(),
+               "Canonicalizing non-constant type: {0}", constant_id);
   auto type_id =
   auto type_id =
       insts().Get(constant_values().GetInstId(constant_id)).type_id();
       insts().Get(constant_values().GetInstId(constant_id)).type_id();
   // TODO: For now, we allow values of facet type to be used as types.
   // TODO: For now, we allow values of facet type to be used as types.
   CARBON_CHECK(type_id == SemIR::TypeId::TypeType ||
   CARBON_CHECK(type_id == SemIR::TypeId::TypeType ||
-               types().Is<SemIR::InterfaceType>(type_id) ||
-               constant_id == SemIR::ConstantId::Error)
-      << "Forming type ID for non-type constant of type "
-      << types().GetAsInst(type_id);
+                   types().Is<SemIR::InterfaceType>(type_id) ||
+                   constant_id == SemIR::ConstantId::Error,
+               "Forming type ID for non-type constant of type {0}",
+               types().GetAsInst(type_id));
 
 
   return SemIR::TypeId::ForTypeConstant(constant_id);
   return SemIR::TypeId::ForTypeConstant(constant_id);
 }
 }
@@ -1205,7 +1206,7 @@ static auto GetCompleteTypeImpl(Context& context, EachArgT... each_arg)
     -> SemIR::TypeId {
     -> SemIR::TypeId {
   auto type_id = GetTypeImpl<InstT>(context, each_arg...);
   auto type_id = GetTypeImpl<InstT>(context, each_arg...);
   bool complete = context.TryToCompleteType(type_id);
   bool complete = context.TryToCompleteType(type_id);
-  CARBON_CHECK(complete) << "Type completion should not fail";
+  CARBON_CHECK(complete, "Type completion should not fail");
   return type_id;
   return type_id;
 }
 }
 
 
@@ -1231,7 +1232,7 @@ auto Context::GetBuiltinType(SemIR::BuiltinInstKind kind) -> SemIR::TypeId {
   auto type_id = GetTypeIdForTypeInst(SemIR::InstId::ForBuiltin(kind));
   auto type_id = GetTypeIdForTypeInst(SemIR::InstId::ForBuiltin(kind));
   // To keep client code simpler, complete builtin types before returning them.
   // To keep client code simpler, complete builtin types before returning them.
   bool complete = TryToCompleteType(type_id);
   bool complete = TryToCompleteType(type_id);
-  CARBON_CHECK(complete) << "Failed to complete builtin type";
+  CARBON_CHECK(complete, "Failed to complete builtin type");
   return type_id;
   return type_id;
 }
 }
 
 

+ 1 - 2
toolchain/check/context.h

@@ -363,8 +363,7 @@ class Context {
   // Sets the total number of IRs which exist. This is used to prepare a map
   // Sets the total number of IRs which exist. This is used to prepare a map
   // from IR to imported IR.
   // from IR to imported IR.
   auto SetTotalIRCount(int num_irs) -> void {
   auto SetTotalIRCount(int num_irs) -> void {
-    CARBON_CHECK(check_ir_map_.empty())
-        << "SetTotalIRCount is only called once";
+    CARBON_CHECK(check_ir_map_.empty(), "SetTotalIRCount is only called once");
     check_ir_map_.resize(num_irs, SemIR::ImportIRId::Invalid);
     check_ir_map_.resize(num_irs, SemIR::ImportIRId::Invalid);
   }
   }
 
 

+ 13 - 16
toolchain/check/convert.cpp

@@ -66,8 +66,7 @@ static auto FindReturnSlotForInitializer(SemIR::File& sem_ir,
         return sem_ir.inst_blocks().Get(call.args_id).back();
         return sem_ir.inst_blocks().Get(call.args_id).back();
       }
       }
       default:
       default:
-        CARBON_FATAL() << "Initialization from unexpected inst "
-                       << init_untyped;
+        CARBON_FATAL("Initialization from unexpected inst {0}", init_untyped);
     }
     }
   }
   }
 }
 }
@@ -80,10 +79,10 @@ static auto MarkInitializerFor(SemIR::File& sem_ir, SemIR::InstId init_id,
   if (return_slot_id.is_valid()) {
   if (return_slot_id.is_valid()) {
     // Replace the temporary in the return slot with a reference to our target.
     // Replace the temporary in the return slot with a reference to our target.
     CARBON_CHECK(sem_ir.insts().Get(return_slot_id).kind() ==
     CARBON_CHECK(sem_ir.insts().Get(return_slot_id).kind() ==
-                 SemIR::TemporaryStorage::Kind)
-        << "Return slot for initializer does not contain a temporary; "
-        << "initialized multiple times? Have "
-        << sem_ir.insts().Get(return_slot_id);
+                     SemIR::TemporaryStorage::Kind,
+                 "Return slot for initializer does not contain a temporary; "
+                 "initialized multiple times? Have {0}",
+                 sem_ir.insts().Get(return_slot_id));
     target_block.MergeReplacing(return_slot_id, target_id);
     target_block.MergeReplacing(return_slot_id, target_id);
   }
   }
 }
 }
@@ -100,10 +99,10 @@ static auto FinalizeTemporary(Context& context, SemIR::InstId init_id,
   if (return_slot_id.is_valid()) {
   if (return_slot_id.is_valid()) {
     // The return slot should already have a materialized temporary in it.
     // The return slot should already have a materialized temporary in it.
     CARBON_CHECK(sem_ir.insts().Get(return_slot_id).kind() ==
     CARBON_CHECK(sem_ir.insts().Get(return_slot_id).kind() ==
-                 SemIR::TemporaryStorage::Kind)
-        << "Return slot for initializer does not contain a temporary; "
-        << "initialized multiple times? Have "
-        << sem_ir.insts().Get(return_slot_id);
+                     SemIR::TemporaryStorage::Kind,
+                 "Return slot for initializer does not contain a temporary; "
+                 "initialized multiple times? Have {0}",
+                 sem_ir.insts().Get(return_slot_id));
     auto init = sem_ir.insts().Get(init_id);
     auto init = sem_ir.insts().Get(init_id);
     return context.AddInst<SemIR::Temporary>(sem_ir.insts().GetLocId(init_id),
     return context.AddInst<SemIR::Temporary>(sem_ir.insts().GetLocId(init_id),
                                              {.type_id = init.type_id(),
                                              {.type_id = init.type_id(),
@@ -423,8 +422,7 @@ static auto ConvertStructToStructOrClass(Context& context,
     for (auto [i, field_id] : llvm::enumerate(src_elem_fields)) {
     for (auto [i, field_id] : llvm::enumerate(src_elem_fields)) {
       auto result = src_field_indexes.Insert(
       auto result = src_field_indexes.Insert(
           context.insts().GetAs<SemIR::StructTypeField>(field_id).name_id, i);
           context.insts().GetAs<SemIR::StructTypeField>(field_id).name_id, i);
-      CARBON_CHECK(result.is_inserted())
-          << "Duplicate field in source structure";
+      CARBON_CHECK(result.is_inserted(), "Duplicate field in source structure");
     }
     }
   }
   }
 
 
@@ -496,8 +494,8 @@ static auto ConvertStructToStructOrClass(Context& context,
 
 
   if (is_class) {
   if (is_class) {
     target.init_block->InsertHere();
     target.init_block->InsertHere();
-    CARBON_CHECK(is_init)
-        << "Converting directly to a class value is not supported";
+    CARBON_CHECK(is_init,
+                 "Converting directly to a class value is not supported");
     return context.AddInst<SemIR::ClassInit>(value_loc_id,
     return context.AddInst<SemIR::ClassInit>(value_loc_id,
                                              {.type_id = target.type_id,
                                              {.type_id = target.type_id,
                                               .elements_id = new_block.id(),
                                               .elements_id = new_block.id(),
@@ -1004,8 +1002,7 @@ auto Convert(Context& context, SemIR::LocId loc_id, SemIR::InstId expr_id,
   switch (SemIR::GetExprCategory(sem_ir, expr_id)) {
   switch (SemIR::GetExprCategory(sem_ir, expr_id)) {
     case SemIR::ExprCategory::NotExpr:
     case SemIR::ExprCategory::NotExpr:
     case SemIR::ExprCategory::Mixed:
     case SemIR::ExprCategory::Mixed:
-      CARBON_FATAL() << "Unexpected expression " << expr
-                     << " after builtin conversions";
+      CARBON_FATAL("Unexpected expression {0} after builtin conversions", expr);
 
 
     case SemIR::ExprCategory::Error:
     case SemIR::ExprCategory::Error:
       return SemIR::InstId::BuiltinError;
       return SemIR::InstId::BuiltinError;

+ 2 - 3
toolchain/check/decl_introducer_state.h

@@ -74,9 +74,8 @@ class DeclIntroducerStateStack {
   template <Lex::TokenKind::RawEnumType Kind>
   template <Lex::TokenKind::RawEnumType Kind>
     requires(IsDeclIntroducer<Kind>())
     requires(IsDeclIntroducer<Kind>())
   auto Pop() -> DeclIntroducerState {
   auto Pop() -> DeclIntroducerState {
-    CARBON_CHECK(stack_.back().kind == Kind)
-        << "Found: " << stack_.back().kind
-        << " expected: " << Lex::TokenKind::Make(Kind);
+    CARBON_CHECK(stack_.back().kind == Kind, "Found: {0} expected: {1}",
+                 stack_.back().kind, Lex::TokenKind::Make(Kind));
     return stack_.pop_back_val();
     return stack_.pop_back_val();
   }
   }
 
 

+ 24 - 24
toolchain/check/decl_name_stack.cpp

@@ -23,9 +23,9 @@ auto DeclNameStack::NameContext::prev_inst_id() -> SemIR::InstId {
       return SemIR::InstId::Invalid;
       return SemIR::InstId::Invalid;
 
 
     case NameContext::State::Empty:
     case NameContext::State::Empty:
-      CARBON_FATAL()
-          << "Name is missing, not expected to call existing_inst_id (but "
-             "that may change based on error handling).";
+      CARBON_FATAL(
+          "Name is missing, not expected to call existing_inst_id (but that "
+          "may change based on error handling).");
 
 
     case NameContext::State::Resolved:
     case NameContext::State::Resolved:
       return resolved_inst_id;
       return resolved_inst_id;
@@ -34,7 +34,7 @@ auto DeclNameStack::NameContext::prev_inst_id() -> SemIR::InstId {
       return SemIR::InstId::Invalid;
       return SemIR::InstId::Invalid;
 
 
     case NameContext::State::Finished:
     case NameContext::State::Finished:
-      CARBON_FATAL() << "Finished state should only be used internally";
+      CARBON_FATAL("Finished state should only be used internally");
   }
   }
 }
 }
 
 
@@ -59,8 +59,8 @@ auto DeclNameStack::PushScopeAndStartName() -> void {
 }
 }
 
 
 auto DeclNameStack::FinishName(const NameComponent& name) -> NameContext {
 auto DeclNameStack::FinishName(const NameComponent& name) -> NameContext {
-  CARBON_CHECK(decl_name_stack_.back().state != NameContext::State::Finished)
-      << "Finished name twice";
+  CARBON_CHECK(decl_name_stack_.back().state != NameContext::State::Finished,
+               "Finished name twice");
 
 
   ApplyAndLookupName(decl_name_stack_.back(), name.name_loc_id, name.name_id);
   ApplyAndLookupName(decl_name_stack_.back(), name.name_loc_id, name.name_id);
 
 
@@ -70,8 +70,8 @@ auto DeclNameStack::FinishName(const NameComponent& name) -> NameContext {
 }
 }
 
 
 auto DeclNameStack::FinishImplName() -> NameContext {
 auto DeclNameStack::FinishImplName() -> NameContext {
-  CARBON_CHECK(decl_name_stack_.back().state == NameContext::State::Empty)
-      << "Impl has a name";
+  CARBON_CHECK(decl_name_stack_.back().state == NameContext::State::Empty,
+               "Impl has a name");
 
 
   NameContext result = decl_name_stack_.back();
   NameContext result = decl_name_stack_.back();
   decl_name_stack_.back().state = NameContext::State::Finished;
   decl_name_stack_.back().state = NameContext::State::Finished;
@@ -79,15 +79,15 @@ auto DeclNameStack::FinishImplName() -> NameContext {
 }
 }
 
 
 auto DeclNameStack::PopScope() -> void {
 auto DeclNameStack::PopScope() -> void {
-  CARBON_CHECK(decl_name_stack_.back().state == NameContext::State::Finished)
-      << "Missing call to FinishName before PopScope";
+  CARBON_CHECK(decl_name_stack_.back().state == NameContext::State::Finished,
+               "Missing call to FinishName before PopScope");
   context_->scope_stack().PopTo(decl_name_stack_.back().initial_scope_index);
   context_->scope_stack().PopTo(decl_name_stack_.back().initial_scope_index);
   decl_name_stack_.pop_back();
   decl_name_stack_.pop_back();
 }
 }
 
 
 auto DeclNameStack::Suspend() -> SuspendedName {
 auto DeclNameStack::Suspend() -> SuspendedName {
-  CARBON_CHECK(decl_name_stack_.back().state == NameContext::State::Finished)
-      << "Missing call to FinishName before Suspend";
+  CARBON_CHECK(decl_name_stack_.back().state == NameContext::State::Finished,
+               "Missing call to FinishName before Suspend");
   SuspendedName result = {.name_context = decl_name_stack_.pop_back_val(),
   SuspendedName result = {.name_context = decl_name_stack_.pop_back_val(),
                           .scopes = {}};
                           .scopes = {}};
   auto scope_index = result.name_context.initial_scope_index;
   auto scope_index = result.name_context.initial_scope_index;
@@ -95,17 +95,17 @@ auto DeclNameStack::Suspend() -> SuspendedName {
   while (scope_stack.PeekIndex() > scope_index) {
   while (scope_stack.PeekIndex() > scope_index) {
     result.scopes.push_back(scope_stack.Suspend());
     result.scopes.push_back(scope_stack.Suspend());
   }
   }
-  CARBON_CHECK(scope_stack.PeekIndex() == scope_index)
-      << "Scope index " << scope_index << " does not enclose the current scope "
-      << scope_stack.PeekIndex();
+  CARBON_CHECK(scope_stack.PeekIndex() == scope_index,
+               "Scope index {0} does not enclose the current scope {1}",
+               scope_index, scope_stack.PeekIndex());
   return result;
   return result;
 }
 }
 
 
 auto DeclNameStack::Restore(SuspendedName sus) -> void {
 auto DeclNameStack::Restore(SuspendedName sus) -> void {
   // The parent state must be the same when a name is restored.
   // The parent state must be the same when a name is restored.
   CARBON_CHECK(context_->scope_stack().PeekIndex() ==
   CARBON_CHECK(context_->scope_stack().PeekIndex() ==
-               sus.name_context.initial_scope_index)
-      << "Name restored at the wrong position in the name stack.";
+                   sus.name_context.initial_scope_index,
+               "Name restored at the wrong position in the name stack.");
 
 
   // clang-tidy warns that the `std::move` below has no effect. While that's
   // clang-tidy warns that the `std::move` below has no effect. While that's
   // true, this `move` defends against `NameContext` growing more state later.
   // true, this `move` defends against `NameContext` growing more state later.
@@ -164,15 +164,15 @@ auto DeclNameStack::AddName(NameContext name_context, SemIR::InstId target_id,
         };
         };
         auto result = name_scope.name_map.Insert(
         auto result = name_scope.name_map.Insert(
             name_context.unresolved_name_id, add_scope);
             name_context.unresolved_name_id, add_scope);
-        CARBON_CHECK(result.is_inserted())
-            << "Duplicate names should have been resolved previously: "
-            << name_context.unresolved_name_id << " in "
-            << name_context.parent_scope_id;
+        CARBON_CHECK(
+            result.is_inserted(),
+            "Duplicate names should have been resolved previously: {0} in {1}",
+            name_context.unresolved_name_id, name_context.parent_scope_id);
       }
       }
       break;
       break;
 
 
     default:
     default:
-      CARBON_FATAL() << "Should not be calling AddName";
+      CARBON_FATAL("Should not be calling AddName");
       break;
       break;
   }
   }
 }
 }
@@ -284,7 +284,7 @@ static auto CheckQualifierIsResolved(
     Context& context, const DeclNameStack::NameContext& name_context) -> bool {
     Context& context, const DeclNameStack::NameContext& name_context) -> bool {
   switch (name_context.state) {
   switch (name_context.state) {
     case DeclNameStack::NameContext::State::Empty:
     case DeclNameStack::NameContext::State::Empty:
-      CARBON_FATAL() << "No qualifier to resolve";
+      CARBON_FATAL("No qualifier to resolve");
 
 
     case DeclNameStack::NameContext::State::Resolved:
     case DeclNameStack::NameContext::State::Resolved:
       return true;
       return true;
@@ -297,7 +297,7 @@ static auto CheckQualifierIsResolved(
       return false;
       return false;
 
 
     case DeclNameStack::NameContext::State::Finished:
     case DeclNameStack::NameContext::State::Finished:
-      CARBON_FATAL() << "Added a qualifier after calling FinishName";
+      CARBON_FATAL("Added a qualifier after calling FinishName");
 
 
     case DeclNameStack::NameContext::State::Error:
     case DeclNameStack::NameContext::State::Error:
       // Already in an error state, so return without examining.
       // Already in an error state, so return without examining.

+ 4 - 4
toolchain/check/deduce.cpp

@@ -156,10 +156,10 @@ auto DeduceGenericCallArguments(
         auto& entity_name = context.entity_names().Get(bind.entity_name_id);
         auto& entity_name = context.entity_names().Get(bind.entity_name_id);
         auto index = entity_name.bind_index;
         auto index = entity_name.bind_index;
         if (index.is_valid() && index >= first_deduced_index) {
         if (index.is_valid() && index >= first_deduced_index) {
-          CARBON_CHECK(static_cast<size_t>(index.index) < result_arg_ids.size())
-              << "Deduced value for unexpected index " << index
-              << "; expected to deduce " << result_arg_ids.size()
-              << " arguments.";
+          CARBON_CHECK(static_cast<size_t>(index.index) < result_arg_ids.size(),
+                       "Deduced value for unexpected index {0}; expected to "
+                       "deduce {1} arguments.",
+                       index, result_arg_ids.size());
           auto arg_const_inst_id =
           auto arg_const_inst_id =
               context.constant_values().GetConstantInstId(arg_id);
               context.constant_values().GetConstantInstId(arg_id);
           if (arg_const_inst_id.is_valid()) {
           if (arg_const_inst_id.is_valid()) {

+ 22 - 21
toolchain/check/eval.cpp

@@ -77,9 +77,10 @@ class EvalContext {
               specifics().Get(specific_id_).generic_id &&
               specifics().Get(specific_id_).generic_id &&
           symbolic_info.index.region() == specific_eval_info_->region) {
           symbolic_info.index.region() == specific_eval_info_->region) {
         auto inst_id = specific_eval_info_->values[symbolic_info.index.index()];
         auto inst_id = specific_eval_info_->values[symbolic_info.index.index()];
-        CARBON_CHECK(inst_id.is_valid())
-            << "Forward reference in eval block: index "
-            << symbolic_info.index.index() << " referenced before evaluation";
+        CARBON_CHECK(inst_id.is_valid(),
+                     "Forward reference in eval block: index {0} referenced "
+                     "before evaluation",
+                     symbolic_info.index.index());
         return constant_values().Get(inst_id);
         return constant_values().Get(inst_id);
       }
       }
     }
     }
@@ -464,14 +465,14 @@ static auto PerformAggregateAccess(EvalContext& eval_context, SemIR::Inst inst)
                 aggregate_id)) {
                 aggregate_id)) {
       auto elements = eval_context.inst_blocks().Get(aggregate->elements_id);
       auto elements = eval_context.inst_blocks().Get(aggregate->elements_id);
       auto index = static_cast<size_t>(access_inst.index.index);
       auto index = static_cast<size_t>(access_inst.index.index);
-      CARBON_CHECK(index < elements.size()) << "Access out of bounds.";
+      CARBON_CHECK(index < elements.size(), "Access out of bounds.");
       // `Phase` is not used here. If this element is a template constant, then
       // `Phase` is not used here. If this element is a template constant, then
       // so is the result of indexing, even if the aggregate also contains a
       // so is the result of indexing, even if the aggregate also contains a
       // symbolic context.
       // symbolic context.
       return eval_context.GetConstantValue(elements[index]);
       return eval_context.GetConstantValue(elements[index]);
     } else {
     } else {
-      CARBON_CHECK(phase != Phase::Template)
-          << "Failed to evaluate template constant " << inst;
+      CARBON_CHECK(phase != Phase::Template,
+                   "Failed to evaluate template constant {0}", inst);
     }
     }
   }
   }
   return MakeNonConstantResult(phase);
   return MakeNonConstantResult(phase);
@@ -490,8 +491,8 @@ static auto PerformAggregateIndex(EvalContext& eval_context, SemIR::Inst inst)
   }
   }
   auto index = eval_context.insts().TryGetAs<SemIR::IntLiteral>(index_id);
   auto index = eval_context.insts().TryGetAs<SemIR::IntLiteral>(index_id);
   if (!index) {
   if (!index) {
-    CARBON_CHECK(phase != Phase::Template)
-        << "Template constant integer should be a literal";
+    CARBON_CHECK(phase != Phase::Template,
+                 "Template constant integer should be a literal");
     return MakeNonConstantResult(phase);
     return MakeNonConstantResult(phase);
   }
   }
 
 
@@ -529,15 +530,15 @@ static auto PerformAggregateIndex(EvalContext& eval_context, SemIR::Inst inst)
   auto aggregate =
   auto aggregate =
       eval_context.insts().TryGetAs<SemIR::AnyAggregateValue>(aggregate_id);
       eval_context.insts().TryGetAs<SemIR::AnyAggregateValue>(aggregate_id);
   if (!aggregate) {
   if (!aggregate) {
-    CARBON_CHECK(phase != Phase::Template)
-        << "Unexpected representation for template constant aggregate";
+    CARBON_CHECK(phase != Phase::Template,
+                 "Unexpected representation for template constant aggregate");
     return MakeNonConstantResult(phase);
     return MakeNonConstantResult(phase);
   }
   }
 
 
   auto elements = eval_context.inst_blocks().Get(aggregate->elements_id);
   auto elements = eval_context.inst_blocks().Get(aggregate->elements_id);
   // We checked this for the array case above.
   // We checked this for the array case above.
-  CARBON_CHECK(index_val.ult(elements.size()))
-      << "Index out of bounds in tuple indexing";
+  CARBON_CHECK(index_val.ult(elements.size()),
+               "Index out of bounds in tuple indexing");
   return eval_context.GetConstantValue(elements[index_val.getZExtValue()]);
   return eval_context.GetConstantValue(elements[index_val.getZExtValue()]);
 }
 }
 
 
@@ -649,7 +650,7 @@ static auto PerformBuiltinUnaryIntOp(Context& context, SemIRLoc loc,
       op_val.flipAllBits();
       op_val.flipAllBits();
       break;
       break;
     default:
     default:
-      CARBON_FATAL() << "Unexpected builtin kind";
+      CARBON_FATAL("Unexpected builtin kind");
   }
   }
 
 
   return MakeIntResult(context, op.type_id, std::move(op_val));
   return MakeIntResult(context, op.type_id, std::move(op_val));
@@ -774,7 +775,7 @@ static auto PerformBuiltinBinaryIntOp(Context& context, SemIRLoc loc,
       break;
       break;
 
 
     default:
     default:
-      CARBON_FATAL() << "Unexpected operation kind.";
+      CARBON_FATAL("Unexpected operation kind.");
   }
   }
 
 
   if (overflow) {
   if (overflow) {
@@ -823,7 +824,7 @@ static auto PerformBuiltinIntComparison(Context& context,
       result = is_signed ? lhs_val.sge(rhs_val) : lhs_val.sge(rhs_val);
       result = is_signed ? lhs_val.sge(rhs_val) : lhs_val.sge(rhs_val);
       break;
       break;
     default:
     default:
-      CARBON_FATAL() << "Unexpected operation kind.";
+      CARBON_FATAL("Unexpected operation kind.");
   }
   }
 
 
   return MakeBoolResult(context, bool_type_id, result);
   return MakeBoolResult(context, bool_type_id, result);
@@ -842,7 +843,7 @@ static auto PerformBuiltinUnaryFloatOp(Context& context,
       op_val.changeSign();
       op_val.changeSign();
       break;
       break;
     default:
     default:
-      CARBON_FATAL() << "Unexpected builtin kind";
+      CARBON_FATAL("Unexpected builtin kind");
   }
   }
 
 
   return MakeFloatResult(context, op.type_id, std::move(op_val));
   return MakeFloatResult(context, op.type_id, std::move(op_val));
@@ -875,7 +876,7 @@ static auto PerformBuiltinBinaryFloatOp(Context& context,
       result_val = lhs_val / rhs_val;
       result_val = lhs_val / rhs_val;
       break;
       break;
     default:
     default:
-      CARBON_FATAL() << "Unexpected operation kind.";
+      CARBON_FATAL("Unexpected operation kind.");
   }
   }
 
 
   return MakeFloatResult(context, lhs.type_id, std::move(result_val));
   return MakeFloatResult(context, lhs.type_id, std::move(result_val));
@@ -912,7 +913,7 @@ static auto PerformBuiltinFloatComparison(
       result = lhs_val >= rhs_val;
       result = lhs_val >= rhs_val;
       break;
       break;
     default:
     default:
-      CARBON_FATAL() << "Unexpected operation kind.";
+      CARBON_FATAL("Unexpected operation kind.");
   }
   }
 
 
   return MakeBoolResult(context, bool_type_id, result);
   return MakeBoolResult(context, bool_type_id, result);
@@ -926,7 +927,7 @@ static auto MakeConstantForBuiltinCall(Context& context, SemIRLoc loc,
                                        Phase phase) -> SemIR::ConstantId {
                                        Phase phase) -> SemIR::ConstantId {
   switch (builtin_kind) {
   switch (builtin_kind) {
     case SemIR::BuiltinFunctionKind::None:
     case SemIR::BuiltinFunctionKind::None:
-      CARBON_FATAL() << "Not a builtin function.";
+      CARBON_FATAL("Not a builtin function.");
 
 
     case SemIR::BuiltinFunctionKind::PrintInt: {
     case SemIR::BuiltinFunctionKind::PrintInt: {
       // Providing a constant result would allow eliding the function call.
       // Providing a constant result would allow eliding the function call.
@@ -1483,8 +1484,8 @@ auto TryEvalInstInContext(EvalContext& eval_context, SemIR::InstId inst_id,
       break;
       break;
 
 
     case SemIR::ImportRefUnloaded::Kind:
     case SemIR::ImportRefUnloaded::Kind:
-      CARBON_FATAL()
-          << "ImportRefUnloaded should be loaded before TryEvalInst: " << inst;
+      CARBON_FATAL("ImportRefUnloaded should be loaded before TryEvalInst: {0}",
+                   inst);
   }
   }
   return SemIR::ConstantId::NotConstant;
   return SemIR::ConstantId::NotConstant;
 }
 }

+ 26 - 24
toolchain/check/generic.cpp

@@ -73,9 +73,10 @@ class RebuildGenericConstantInEvalBlockCallbacks final
     if (!const_id.is_valid()) {
     if (!const_id.is_valid()) {
       // An unloaded import ref should never contain anything we need to
       // An unloaded import ref should never contain anything we need to
       // substitute into. Don't trigger loading it here.
       // substitute into. Don't trigger loading it here.
-      CARBON_CHECK(context_.insts().Is<SemIR::ImportRefUnloaded>(inst_id))
-          << "Substituting into instruction with invalid constant ID: "
-          << context_.insts().Get(inst_id);
+      CARBON_CHECK(
+          context_.insts().Is<SemIR::ImportRefUnloaded>(inst_id),
+          "Substituting into instruction with invalid constant ID: {0}",
+          context_.insts().Get(inst_id));
       return true;
       return true;
     }
     }
     if (!const_id.is_symbolic()) {
     if (!const_id.is_symbolic()) {
@@ -174,9 +175,9 @@ static auto AddGenericConstantToEvalBlock(
       SubstInst(context, const_inst_id,
       SubstInst(context, const_inst_id,
                 RebuildGenericConstantInEvalBlockCallbacks(
                 RebuildGenericConstantInEvalBlockCallbacks(
                     context, generic_id, region, constants_in_generic));
                     context, generic_id, region, constants_in_generic));
-  CARBON_CHECK(new_inst_id != const_inst_id)
-      << "Did not apply any substitutions to symbolic constant "
-      << context.insts().Get(const_inst_id);
+  CARBON_CHECK(new_inst_id != const_inst_id,
+               "Did not apply any substitutions to symbolic constant {0}",
+               context.insts().Get(const_inst_id));
   return context.constant_values().Get(new_inst_id);
   return context.constant_values().Get(new_inst_id);
 }
 }
 
 
@@ -192,9 +193,9 @@ static auto PopulateConstantsFromDeclaration(
   for (auto inst_id : decl_eval_block) {
   for (auto inst_id : decl_eval_block) {
     auto const_inst_id = context.constant_values().GetConstantInstId(inst_id);
     auto const_inst_id = context.constant_values().GetConstantInstId(inst_id);
     auto result = constants_in_generic.Insert(const_inst_id, inst_id);
     auto result = constants_in_generic.Insert(const_inst_id, inst_id);
-    CARBON_CHECK(result.is_inserted())
-        << "Duplicate constant in generic decl eval block: "
-        << context.insts().Get(const_inst_id);
+    CARBON_CHECK(result.is_inserted(),
+                 "Duplicate constant in generic decl eval block: {0}",
+                 context.insts().Get(const_inst_id));
   }
   }
 }
 }
 
 
@@ -252,12 +253,13 @@ static auto MakeGenericEvalBlock(Context& context, SemIR::GenericId generic_id,
     }
     }
   }
   }
 
 
-  CARBON_CHECK(num_dependent_insts ==
-               context.generic_region_stack().PeekDependentInsts().size())
-      << "Building eval block added new dependent insts, for example "
-      << context.insts().Get(context.generic_region_stack()
-                                 .PeekDependentInsts()[num_dependent_insts]
-                                 .inst_id);
+  CARBON_CHECK(
+      num_dependent_insts ==
+          context.generic_region_stack().PeekDependentInsts().size(),
+      "Building eval block added new dependent insts, for example {0}",
+      context.insts().Get(context.generic_region_stack()
+                              .PeekDependentInsts()[num_dependent_insts]
+                              .inst_id));
 
 
   return context.inst_block_stack().Pop();
   return context.inst_block_stack().Pop();
 }
 }
@@ -283,11 +285,11 @@ auto RebuildGenericEvalBlock(Context& context, SemIR::GenericId generic_id,
     // Build a constant in the inst block.
     // Build a constant in the inst block.
     AddGenericConstantToEvalBlock(context, generic_id, region,
     AddGenericConstantToEvalBlock(context, generic_id, region,
                                   constants_in_generic, inst_id);
                                   constants_in_generic, inst_id);
-    CARBON_CHECK(context.inst_block_stack().PeekCurrentBlockContents().size() ==
-                 i + 1)
-        << "Produced "
-        << (context.inst_block_stack().PeekCurrentBlockContents().size() - i)
-        << " instructions when importing " << context.insts().Get(inst_id);
+    CARBON_CHECK(
+        context.inst_block_stack().PeekCurrentBlockContents().size() == i + 1,
+        "Produced {0} instructions when importing {1}",
+        (context.inst_block_stack().PeekCurrentBlockContents().size() - i),
+        context.insts().Get(inst_id));
   }
   }
 
 
   return context.inst_block_stack().Pop();
   return context.inst_block_stack().Pop();
@@ -299,9 +301,9 @@ auto FinishGenericDecl(Context& context, SemIR::InstId decl_id)
       context.scope_stack().compile_time_bindings_stack().PeekAllValues();
       context.scope_stack().compile_time_bindings_stack().PeekAllValues();
 
 
   if (all_bindings.empty()) {
   if (all_bindings.empty()) {
-    CARBON_CHECK(context.generic_region_stack().PeekDependentInsts().empty())
-        << "Have dependent instructions but no compile time bindings are in "
-           "scope.";
+    CARBON_CHECK(context.generic_region_stack().PeekDependentInsts().empty(),
+                 "Have dependent instructions but no compile time bindings are "
+                 "in scope.");
     context.generic_region_stack().Pop();
     context.generic_region_stack().Pop();
     return SemIR::GenericId::Invalid;
     return SemIR::GenericId::Invalid;
   }
   }
@@ -396,7 +398,7 @@ auto ResolveSpecificDefinition(Context& context, SemIR::SpecificId specific_id)
     -> bool {
     -> bool {
   auto& specific = context.specifics().Get(specific_id);
   auto& specific = context.specifics().Get(specific_id);
   auto generic_id = specific.generic_id;
   auto generic_id = specific.generic_id;
-  CARBON_CHECK(generic_id.is_valid()) << "Specific with no generic ID";
+  CARBON_CHECK(generic_id.is_valid(), "Specific with no generic ID");
 
 
   if (!specific.definition_block_id.is_valid()) {
   if (!specific.definition_block_id.is_valid()) {
     // Evaluate the eval block for the definition of the generic.
     // Evaluate the eval block for the definition of the generic.

+ 4 - 4
toolchain/check/handle_binding_pattern.cpp

@@ -108,8 +108,8 @@ static auto HandleAnyBindingPattern(Context& context, Parse::NodeId node_id,
                                        cast_type_id);
                                        cast_type_id);
       });
       });
       if (parent_class_decl) {
       if (parent_class_decl) {
-        CARBON_CHECK(context_node_kind == Parse::NodeKind::VariableIntroducer)
-            << "`returned var` at class scope";
+        CARBON_CHECK(context_node_kind == Parse::NodeKind::VariableIntroducer,
+                     "`returned var` at class scope");
         auto& class_info = context.classes().Get(parent_class_decl->class_id);
         auto& class_info = context.classes().Get(parent_class_decl->class_id);
         auto field_type_id = context.GetUnboundElementType(
         auto field_type_id = context.GetUnboundElementType(
             class_info.self_type_id, cast_type_id);
             class_info.self_type_id, cast_type_id);
@@ -185,8 +185,8 @@ static auto HandleAnyBindingPattern(Context& context, Parse::NodeId node_id,
     }
     }
 
 
     default:
     default:
-      CARBON_FATAL() << "Found a pattern binding in unexpected context "
-                     << context_node_kind;
+      CARBON_FATAL("Found a pattern binding in unexpected context {0}",
+                   context_node_kind);
   }
   }
   return true;
   return true;
 }
 }

+ 4 - 4
toolchain/check/handle_class.cpp

@@ -408,8 +408,8 @@ auto HandleParseNode(Context& context, Parse::AdaptDeclId node_id) -> bool {
     } else if (auto* adapted_class_info =
     } else if (auto* adapted_class_info =
                    TryGetAsClass(context, adapted_type_id)) {
                    TryGetAsClass(context, adapted_type_id)) {
       extended_scope_id = adapted_class_info->scope_id;
       extended_scope_id = adapted_class_info->scope_id;
-      CARBON_CHECK(adapted_class_info->scope_id.is_valid())
-          << "Complete class should have a scope";
+      CARBON_CHECK(adapted_class_info->scope_id.is_valid(),
+                   "Complete class should have a scope");
     } else {
     } else {
       // TODO: Accept any type that has a scope.
       // TODO: Accept any type that has a scope.
       context.TODO(node_id, "extending non-class type");
       context.TODO(node_id, "extending non-class type");
@@ -489,8 +489,8 @@ static auto CheckBaseType(Context& context, Parse::NodeId node_id,
     DiagnoseBaseIsFinal(context, node_id, base_type_id);
     DiagnoseBaseIsFinal(context, node_id, base_type_id);
   }
   }
 
 
-  CARBON_CHECK(base_class_info->scope_id.is_valid())
-      << "Complete class should have a scope";
+  CARBON_CHECK(base_class_info->scope_id.is_valid(),
+               "Complete class should have a scope");
   return {.type_id = base_type_id, .scope_id = base_class_info->scope_id};
   return {.type_id = base_type_id, .scope_id = base_class_info->scope_id};
 }
 }
 
 

+ 1 - 1
toolchain/check/handle_if_statement.cpp

@@ -68,7 +68,7 @@ auto HandleParseNode(Context& context, Parse::IfStatementId node_id) -> bool {
     }
     }
 
 
     default: {
     default: {
-      CARBON_FATAL() << "Unexpected parse node at start of `if`: " << kind;
+      CARBON_FATAL("Unexpected parse node at start of `if`: {0}", kind);
     }
     }
   }
   }
 
 

+ 2 - 2
toolchain/check/handle_interface.cpp

@@ -137,8 +137,8 @@ auto HandleParseNode(Context& context,
   auto& interface_info = context.interfaces().Get(interface_id);
   auto& interface_info = context.interfaces().Get(interface_id);
 
 
   // Track that this declaration is the definition.
   // Track that this declaration is the definition.
-  CARBON_CHECK(!interface_info.is_defined())
-      << "Can't merge with defined interfaces.";
+  CARBON_CHECK(!interface_info.is_defined(),
+               "Can't merge with defined interfaces.");
   interface_info.definition_id = interface_decl_id;
   interface_info.definition_id = interface_decl_id;
   interface_info.scope_id =
   interface_info.scope_id =
       context.name_scopes().Add(interface_decl_id, SemIR::NameId::Invalid,
       context.name_scopes().Add(interface_decl_id, SemIR::NameId::Invalid,

+ 2 - 2
toolchain/check/handle_let_and_var.cpp

@@ -237,8 +237,8 @@ auto HandleParseNode(Context& context, Parse::LetDeclId node_id) -> bool {
   // the computation of the value.
   // the computation of the value.
   // TODO: Support other kinds of pattern here.
   // TODO: Support other kinds of pattern here.
   auto bind_name = pattern.inst.As<SemIR::AnyBindName>();
   auto bind_name = pattern.inst.As<SemIR::AnyBindName>();
-  CARBON_CHECK(!bind_name.value_id.is_valid())
-      << "Binding should not already have a value!";
+  CARBON_CHECK(!bind_name.value_id.is_valid(),
+               "Binding should not already have a value!");
   bind_name.value_id =
   bind_name.value_id =
       decl_info->init_id ? *decl_info->init_id : SemIR::InstId::BuiltinError;
       decl_info->init_id ? *decl_info->init_id : SemIR::InstId::BuiltinError;
   context.ReplaceInstBeforeConstantUse(decl_info->pattern_id, bind_name);
   context.ReplaceInstBeforeConstantUse(decl_info->pattern_id, bind_name);

+ 1 - 1
toolchain/check/handle_name.cpp

@@ -104,7 +104,7 @@ static auto HandleNameAsExpr(Context& context, Parse::NodeId node_id,
   auto value = context.insts().Get(result.inst_id);
   auto value = context.insts().Get(result.inst_id);
   auto type_id = SemIR::GetTypeInSpecific(context.sem_ir(), result.specific_id,
   auto type_id = SemIR::GetTypeInSpecific(context.sem_ir(), result.specific_id,
                                           value.type_id());
                                           value.type_id());
-  CARBON_CHECK(type_id.is_valid()) << "Missing type for " << value;
+  CARBON_CHECK(type_id.is_valid(), "Missing type for {0}", value);
 
 
   // If the named entity has a constant value that depends on its specific,
   // If the named entity has a constant value that depends on its specific,
   // store the specific too.
   // store the specific too.

+ 2 - 2
toolchain/check/handle_noop.cpp

@@ -29,8 +29,8 @@ auto HandleParseNode(Context& context, Parse::InvalidParseSubtreeId node_id)
 
 
 auto HandleParseNode(Context& /*context*/, Parse::PlaceholderId /*node_id*/)
 auto HandleParseNode(Context& /*context*/, Parse::PlaceholderId /*node_id*/)
     -> bool {
     -> bool {
-  CARBON_FATAL()
-      << "Placeholder node should always be replaced before parse completes";
+  CARBON_FATAL(
+      "Placeholder node should always be replaced before parse completes");
 }
 }
 
 
 }  // namespace Carbon::Check
 }  // namespace Carbon::Check

+ 2 - 2
toolchain/check/handle_struct.cpp

@@ -125,8 +125,8 @@ auto HandleParseNode(Context& context, Parse::StructTypeLiteralId node_id)
   context.node_stack()
   context.node_stack()
       .PopAndDiscardSoloNodeId<Parse::NodeKind::StructTypeLiteralStart>();
       .PopAndDiscardSoloNodeId<Parse::NodeKind::StructTypeLiteralStart>();
 
 
-  CARBON_CHECK(refs_id != SemIR::InstBlockId::Empty)
-      << "{} is handled by StructLiteral.";
+  CARBON_CHECK(refs_id != SemIR::InstBlockId::Empty,
+               "{{}} is handled by StructLiteral.");
 
 
   if (DiagnoseDuplicateNames(context, refs_id, "struct type literal")) {
   if (DiagnoseDuplicateNames(context, refs_id, "struct type literal")) {
     context.node_stack().Push(node_id, SemIR::InstId::BuiltinError);
     context.node_stack().Push(node_id, SemIR::InstId::BuiltinError);

+ 10 - 10
toolchain/check/impl.cpp

@@ -54,12 +54,12 @@ static auto GetSelfSpecificForInterfaceMemberWithSelfType(
   // Add the `Self` argument.
   // Add the `Self` argument.
   CARBON_CHECK(
   CARBON_CHECK(
       context.entity_names()
       context.entity_names()
-          .Get(context.insts()
-                   .GetAs<SemIR::BindSymbolicName>(bindings[arg_ids.size()])
-                   .entity_name_id)
-          .name_id == SemIR::NameId::SelfType)
-      << "Expected a Self binding, found "
-      << context.insts().Get(bindings[arg_ids.size()]);
+              .Get(context.insts()
+                       .GetAs<SemIR::BindSymbolicName>(bindings[arg_ids.size()])
+                       .entity_name_id)
+              .name_id == SemIR::NameId::SelfType,
+      "Expected a Self binding, found {0}",
+      context.insts().Get(bindings[arg_ids.size()]));
   arg_ids.push_back(context.types().GetInstId(self_type_id));
   arg_ids.push_back(context.types().GetInstId(self_type_id));
 
 
   // Take any trailing argument values from the self specific.
   // Take any trailing argument values from the self specific.
@@ -150,7 +150,7 @@ static auto BuildInterfaceWitness(
     decl_id =
     decl_id =
         context.constant_values().GetInstId(SemIR::GetConstantValueInSpecific(
         context.constant_values().GetInstId(SemIR::GetConstantValueInSpecific(
             context.sem_ir(), interface_type.specific_id, decl_id));
             context.sem_ir(), interface_type.specific_id, decl_id));
-    CARBON_CHECK(decl_id.is_valid()) << "Non-constant associated entity";
+    CARBON_CHECK(decl_id.is_valid(), "Non-constant associated entity");
     auto decl = context.insts().Get(decl_id);
     auto decl = context.insts().Get(decl_id);
     CARBON_KIND_SWITCH(decl) {
     CARBON_KIND_SWITCH(decl) {
       case CARBON_KIND(SemIR::StructValue struct_value): {
       case CARBON_KIND(SemIR::StructValue struct_value): {
@@ -160,7 +160,7 @@ static auto BuildInterfaceWitness(
         auto type_inst = context.types().GetAsInst(struct_value.type_id);
         auto type_inst = context.types().GetAsInst(struct_value.type_id);
         auto fn_type = type_inst.TryAs<SemIR::FunctionType>();
         auto fn_type = type_inst.TryAs<SemIR::FunctionType>();
         if (!fn_type) {
         if (!fn_type) {
-          CARBON_FATAL() << "Unexpected type: " << type_inst;
+          CARBON_FATAL("Unexpected type: {0}", type_inst);
         }
         }
         auto& fn = context.functions().Get(fn_type->function_id);
         auto& fn = context.functions().Get(fn_type->function_id);
         auto [impl_decl_id, _] = context.LookupNameInExactScope(
         auto [impl_decl_id, _] = context.LookupNameInExactScope(
@@ -190,8 +190,8 @@ static auto BuildInterfaceWitness(
                      "impl of interface with associated constant");
                      "impl of interface with associated constant");
         return SemIR::InstId::BuiltinError;
         return SemIR::InstId::BuiltinError;
       default:
       default:
-        CARBON_CHECK(decl_id == SemIR::InstId::BuiltinError)
-            << "Unexpected kind of associated entity " << decl;
+        CARBON_CHECK(decl_id == SemIR::InstId::BuiltinError,
+                     "Unexpected kind of associated entity {0}", decl);
         table.push_back(SemIR::InstId::BuiltinError);
         table.push_back(SemIR::InstId::BuiltinError);
         break;
         break;
     }
     }

+ 6 - 6
toolchain/check/import.cpp

@@ -63,7 +63,7 @@ static auto GetImportName(const SemIR::File& import_sem_ir,
     }
     }
 
 
     default:
     default:
-      CARBON_FATAL() << "Unsupported export kind: " << import_inst;
+      CARBON_FATAL("Unsupported export kind: {0}", import_inst);
   }
   }
 }
 }
 
 
@@ -152,9 +152,9 @@ static auto CacheCopiedNamespace(
     SemIR::NameScopeId import_scope_id, SemIR::NameScopeId to_scope_id)
     SemIR::NameScopeId import_scope_id, SemIR::NameScopeId to_scope_id)
     -> void {
     -> void {
   auto result = copied_namespaces.Insert(import_scope_id, to_scope_id);
   auto result = copied_namespaces.Insert(import_scope_id, to_scope_id);
-  CARBON_CHECK(result.is_inserted() || result.value() == to_scope_id)
-      << "Copy result for namespace changed from " << import_scope_id << " to "
-      << to_scope_id;
+  CARBON_CHECK(result.is_inserted() || result.value() == to_scope_id,
+               "Copy result for namespace changed from {0} to {1}",
+               import_scope_id, to_scope_id);
 }
 }
 
 
 // Copies a namespace from the import IR, returning its ID. This may diagnose
 // Copies a namespace from the import IR, returning its ID. This may diagnose
@@ -431,8 +431,8 @@ auto ImportLibrariesFromOtherPackage(Context& context,
                                      IdentifierId package_id,
                                      IdentifierId package_id,
                                      llvm::ArrayRef<SemIR::ImportIR> import_irs,
                                      llvm::ArrayRef<SemIR::ImportIR> import_irs,
                                      bool has_load_error) -> void {
                                      bool has_load_error) -> void {
-  CARBON_CHECK(has_load_error || !import_irs.empty())
-      << "There should be either a load error or at least one IR.";
+  CARBON_CHECK(has_load_error || !import_irs.empty(),
+               "There should be either a load error or at least one IR.");
 
 
   auto name_id = SemIR::NameId::ForIdentifier(package_id);
   auto name_id = SemIR::NameId::ForIdentifier(package_id);
 
 

+ 18 - 18
toolchain/check/import_ref.cpp

@@ -36,8 +36,8 @@ auto SetApiImportIR(Context& context, SemIR::ImportIR import_ir) -> void {
     // We don't have a check_ir_id, so add without touching check_ir_map.
     // We don't have a check_ir_id, so add without touching check_ir_map.
     ir_id = InternalAddImportIR(context, import_ir);
     ir_id = InternalAddImportIR(context, import_ir);
   }
   }
-  CARBON_CHECK(ir_id == SemIR::ImportIRId::ApiForImpl)
-      << "ApiForImpl must be the first IR";
+  CARBON_CHECK(ir_id == SemIR::ImportIRId::ApiForImpl,
+               "ApiForImpl must be the first IR");
 }
 }
 
 
 auto AddImportIR(Context& context, SemIR::ImportIR import_ir)
 auto AddImportIR(Context& context, SemIR::ImportIR import_ir)
@@ -244,9 +244,9 @@ class ImportRefResolver {
       auto [new_const_id, retry] =
       auto [new_const_id, retry] =
           TryResolveInst(work.inst_id, existing.const_id);
           TryResolveInst(work.inst_id, existing.const_id);
 
 
-      CARBON_CHECK(!existing.const_id.is_valid() ||
-                   existing.const_id == new_const_id)
-          << "Constant value changed in third phase.";
+      CARBON_CHECK(
+          !existing.const_id.is_valid() || existing.const_id == new_const_id,
+          "Constant value changed in third phase.");
       if (!existing.const_id.is_valid()) {
       if (!existing.const_id.is_valid()) {
         SetResolvedConstId(work.inst_id, existing.indirect_insts, new_const_id);
         SetResolvedConstId(work.inst_id, existing.indirect_insts, new_const_id);
       }
       }
@@ -394,8 +394,8 @@ class ImportRefResolver {
       }
       }
       cursor_inst_id = ir_inst.inst_id;
       cursor_inst_id = ir_inst.inst_id;
 
 
-      CARBON_CHECK(cursor_ir != prev_ir || cursor_inst_id != prev_inst_id)
-          << cursor_ir->insts().Get(cursor_inst_id);
+      CARBON_CHECK(cursor_ir != prev_ir || cursor_inst_id != prev_inst_id,
+                   "{0}", cursor_ir->insts().Get(cursor_inst_id));
 
 
       if (auto const_id =
       if (auto const_id =
               context_.import_ir_constant_values()[cursor_ir_id.index].Get(
               context_.import_ir_constant_values()[cursor_ir_id.index].Get(
@@ -426,8 +426,8 @@ class ImportRefResolver {
   // Returns true if new unresolved constants were found as part of this
   // Returns true if new unresolved constants were found as part of this
   // `Resolve` step.
   // `Resolve` step.
   auto HasNewWork() -> bool {
   auto HasNewWork() -> bool {
-    CARBON_CHECK(initial_work_ <= work_stack_.size())
-        << "Work shouldn't decrease";
+    CARBON_CHECK(initial_work_ <= work_stack_.size(),
+                 "Work shouldn't decrease");
     return initial_work_ < work_stack_.size();
     return initial_work_ < work_stack_.size();
   }
   }
 
 
@@ -586,7 +586,7 @@ class ImportRefResolver {
             .generic_id;
             .generic_id;
       }
       }
       default: {
       default: {
-        CARBON_FATAL() << "Unexpected type for generic declaration: " << type;
+        CARBON_FATAL("Unexpected type for generic declaration: {0}", type);
       }
       }
     }
     }
   }
   }
@@ -736,7 +736,7 @@ class ImportRefResolver {
             break;
             break;
           }
           }
           default: {
           default: {
-            CARBON_FATAL() << "Unexpected kind: " << bind_inst->kind;
+            CARBON_FATAL("Unexpected kind: {0}", bind_inst->kind);
           }
           }
         }
         }
       }
       }
@@ -829,8 +829,8 @@ class ImportRefResolver {
         break;
         break;
       }
       }
     }
     }
-    CARBON_FATAL() << "Unexpected instruction kind for name scope: "
-                   << name_scope_inst;
+    CARBON_FATAL("Unexpected instruction kind for name scope: {0}",
+                 name_scope_inst);
   }
   }
 
 
   // Given an imported entity base, returns an incomplete, local version of it.
   // Given an imported entity base, returns an incomplete, local version of it.
@@ -961,8 +961,8 @@ class ImportRefResolver {
     } else {
     } else {
       // Third phase: perform a consistency check and produce the constant we
       // Third phase: perform a consistency check and produce the constant we
       // created in the second phase.
       // created in the second phase.
-      CARBON_CHECK(result.const_id == inner_const_id)
-          << "Constant value changed in third phase.";
+      CARBON_CHECK(result.const_id == inner_const_id,
+                   "Constant value changed in third phase.");
       result.const_id = const_id;
       result.const_id = const_id;
     }
     }
 
 
@@ -1104,7 +1104,7 @@ class ImportRefResolver {
   auto ResolveAsUntyped(SemIR::Inst inst) -> ResolveResult {
   auto ResolveAsUntyped(SemIR::Inst inst) -> ResolveResult {
     CARBON_CHECK(!HasNewWork());
     CARBON_CHECK(!HasNewWork());
     auto result = TryEvalInst(context_, SemIR::InstId::Invalid, inst);
     auto result = TryEvalInst(context_, SemIR::InstId::Invalid, inst);
-    CARBON_CHECK(result.is_constant()) << inst << " is not constant";
+    CARBON_CHECK(result.is_constant(), "{0} is not constant", inst);
     return {.const_id = result};
     return {.const_id = result};
   }
   }
 
 
@@ -1602,8 +1602,8 @@ class ImportRefResolver {
     new_interface.body_block_id = context_.inst_block_stack().Pop();
     new_interface.body_block_id = context_.inst_block_stack().Pop();
     new_interface.self_param_id = self_param_id;
     new_interface.self_param_id = self_param_id;
 
 
-    CARBON_CHECK(import_scope.extended_scopes.empty())
-        << "Interfaces don't currently have extended scopes to support.";
+    CARBON_CHECK(import_scope.extended_scopes.empty(),
+                 "Interfaces don't currently have extended scopes to support.");
   }
   }
 
 
   auto TryResolveTypedInst(SemIR::InterfaceDecl inst,
   auto TryResolveTypedInst(SemIR::InterfaceDecl inst,

+ 5 - 5
toolchain/check/inst_block_stack.cpp

@@ -12,8 +12,8 @@ namespace Carbon::Check {
 
 
 auto InstBlockStack::Push(SemIR::InstBlockId id) -> void {
 auto InstBlockStack::Push(SemIR::InstBlockId id) -> void {
   CARBON_VLOG("{0} Push {1}\n", name_, id_stack_.size());
   CARBON_VLOG("{0} Push {1}\n", name_, id_stack_.size());
-  CARBON_CHECK(id_stack_.size() < (1 << 20))
-      << "Excessive stack size: likely infinite loop";
+  CARBON_CHECK(id_stack_.size() < (1 << 20),
+               "Excessive stack size: likely infinite loop");
   id_stack_.push_back(id);
   id_stack_.push_back(id);
   insts_stack_.PushArray();
   insts_stack_.PushArray();
 }
 }
@@ -25,7 +25,7 @@ auto InstBlockStack::Push(SemIR::InstBlockId id,
 }
 }
 
 
 auto InstBlockStack::PeekOrAdd(int depth) -> SemIR::InstBlockId {
 auto InstBlockStack::PeekOrAdd(int depth) -> SemIR::InstBlockId {
-  CARBON_CHECK(static_cast<int>(id_stack_.size()) > depth) << "no such block";
+  CARBON_CHECK(static_cast<int>(id_stack_.size()) > depth, "no such block");
   int index = id_stack_.size() - depth - 1;
   int index = id_stack_.size() - depth - 1;
   auto& slot = id_stack_[index];
   auto& slot = id_stack_[index];
   if (!slot.is_valid()) {
   if (!slot.is_valid()) {
@@ -35,7 +35,7 @@ auto InstBlockStack::PeekOrAdd(int depth) -> SemIR::InstBlockId {
 }
 }
 
 
 auto InstBlockStack::Pop() -> SemIR::InstBlockId {
 auto InstBlockStack::Pop() -> SemIR::InstBlockId {
-  CARBON_CHECK(!empty()) << "no current block";
+  CARBON_CHECK(!empty(), "no current block");
   auto id = id_stack_.pop_back_val();
   auto id = id_stack_.pop_back_val();
   auto insts = insts_stack_.PeekArray();
   auto insts = insts_stack_.PeekArray();
 
 
@@ -55,7 +55,7 @@ auto InstBlockStack::Pop() -> SemIR::InstBlockId {
 }
 }
 
 
 auto InstBlockStack::PopAndDiscard() -> void {
 auto InstBlockStack::PopAndDiscard() -> void {
-  CARBON_CHECK(!empty()) << "no current block";
+  CARBON_CHECK(!empty(), "no current block");
   id_stack_.pop_back();
   id_stack_.pop_back();
   insts_stack_.PopArray();
   insts_stack_.PopArray();
   CARBON_VLOG("{0} PopAndDiscard {1}\n", name_, id_stack_.size());
   CARBON_VLOG("{0} PopAndDiscard {1}\n", name_, id_stack_.size());

+ 3 - 3
toolchain/check/inst_block_stack.h

@@ -54,7 +54,7 @@ class InstBlockStack {
 
 
   // Adds the given instruction ID to the block at the top of the stack.
   // Adds the given instruction ID to the block at the top of the stack.
   auto AddInstId(SemIR::InstId inst_id) -> void {
   auto AddInstId(SemIR::InstId inst_id) -> void {
-    CARBON_CHECK(!empty()) << "no current block";
+    CARBON_CHECK(!empty(), "no current block");
     insts_stack_.AppendToTop(inst_id);
     insts_stack_.AppendToTop(inst_id);
   }
   }
 
 
@@ -65,7 +65,7 @@ class InstBlockStack {
 
 
   // Returns a view of the contents of the top instruction block on the stack.
   // Returns a view of the contents of the top instruction block on the stack.
   auto PeekCurrentBlockContents() const -> llvm::ArrayRef<SemIR::InstId> {
   auto PeekCurrentBlockContents() const -> llvm::ArrayRef<SemIR::InstId> {
-    CARBON_CHECK(!empty()) << "no current block";
+    CARBON_CHECK(!empty(), "no current block");
     return insts_stack_.PeekArray();
     return insts_stack_.PeekArray();
   }
   }
 
 
@@ -75,7 +75,7 @@ class InstBlockStack {
 
 
   // Runs verification that the processing cleanly finished.
   // Runs verification that the processing cleanly finished.
   auto VerifyOnFinish() const -> void {
   auto VerifyOnFinish() const -> void {
-    CARBON_CHECK(empty()) << id_stack_.size();
+    CARBON_CHECK(empty(), "{0}", id_stack_.size());
   }
   }
 
 
   auto empty() const -> bool { return id_stack_.empty(); }
   auto empty() const -> bool { return id_stack_.empty(); }

+ 12 - 11
toolchain/check/lexical_lookup.h

@@ -43,13 +43,14 @@ class LexicalLookup {
   // Returns the lexical lookup results for a name.
   // Returns the lexical lookup results for a name.
   auto Get(SemIR::NameId name_id) -> llvm::SmallVector<Result, 2>& {
   auto Get(SemIR::NameId name_id) -> llvm::SmallVector<Result, 2>& {
     auto index = GetLookupIndex(name_id);
     auto index = GetLookupIndex(name_id);
-    CARBON_CHECK(index < lookup_.size())
-        << "An identifier was added after the Context was initialized. "
-           "Currently, we expect that new identifiers will never be used with "
-           "lexical lookup (they're added for things like detecting name "
-           "collisions in imports). That might change with metaprogramming: if "
-           "it does, we may need to start resizing `lookup_`, either on each "
-           "identifier addition or in Get` where this CHECK currently fires.";
+    CARBON_CHECK(
+        index < lookup_.size(),
+        "An identifier was added after the Context was initialized. Currently, "
+        "we expect that new identifiers will never be used with lexical lookup "
+        "(they're added for things like detecting name collisions in imports). "
+        "That might change with metaprogramming: if it does, we may need to "
+        "start resizing `lookup_`, either on each identifier addition or in "
+        "Get` where this CHECK currently fires.");
     return lookup_[index];
     return lookup_[index];
   }
   }
 
 
@@ -57,10 +58,10 @@ class LexicalLookup {
   auto Suspend(SemIR::NameId name_id) -> SuspendedResult {
   auto Suspend(SemIR::NameId name_id) -> SuspendedResult {
     auto index = GetLookupIndex(name_id);
     auto index = GetLookupIndex(name_id);
     auto& results = lookup_[index];
     auto& results = lookup_[index];
-    CARBON_CHECK(!results.empty())
-        << "Suspending a nonexistent result for " << name_id << ".";
-    CARBON_CHECK(index <= std::numeric_limits<uint32_t>::max())
-        << "Unexpectedly large index " << index << " for name ID";
+    CARBON_CHECK(!results.empty(), "Suspending a nonexistent result for {0}.",
+                 name_id);
+    CARBON_CHECK(index <= std::numeric_limits<uint32_t>::max(),
+                 "Unexpectedly large index {0} for name ID", index);
     return {.index = static_cast<uint32_t>(index),
     return {.index = static_cast<uint32_t>(index),
             .inst_id = results.pop_back_val().inst_id};
             .inst_id = results.pop_back_val().inst_id};
   }
   }

+ 5 - 6
toolchain/check/member_access.cpp

@@ -80,8 +80,7 @@ static auto GetClassElementIndex(Context& context, SemIR::InstId element_id)
   if (auto base = element_inst.TryAs<SemIR::BaseDecl>()) {
   if (auto base = element_inst.TryAs<SemIR::BaseDecl>()) {
     return base->index;
     return base->index;
   }
   }
-  CARBON_FATAL() << "Unexpected value " << element_inst
-                 << " in class element name";
+  CARBON_FATAL("Unexpected value {0} in class element name", element_inst);
 }
 }
 
 
 // Returns whether `function_id` is an instance method, that is, whether it has
 // Returns whether `function_id` is an instance method, that is, whether it has
@@ -321,7 +320,7 @@ static auto LookupMemberNameInScope(Context& context, SemIR::LocId loc_id,
   auto inst = context.insts().Get(result.inst_id);
   auto inst = context.insts().Get(result.inst_id);
   auto type_id = SemIR::GetTypeInSpecific(context.sem_ir(), result.specific_id,
   auto type_id = SemIR::GetTypeInSpecific(context.sem_ir(), result.specific_id,
                                           inst.type_id());
                                           inst.type_id());
-  CARBON_CHECK(type_id.is_valid()) << "Missing type for member " << inst;
+  CARBON_CHECK(type_id.is_valid(), "Missing type for member {0}", inst);
 
 
   // If the named entity has a constant value that depends on its specific,
   // If the named entity has a constant value that depends on its specific,
   // store the specific too.
   // store the specific too.
@@ -372,9 +371,9 @@ static auto PerformInstanceBinding(Context& context, SemIR::LocId loc_id,
       // Find the specified element, which could be either a field or a base
       // Find the specified element, which could be either a field or a base
       // class, and build an element access expression.
       // class, and build an element access expression.
       auto element_id = context.constant_values().GetConstantInstId(member_id);
       auto element_id = context.constant_values().GetConstantInstId(member_id);
-      CARBON_CHECK(element_id.is_valid())
-          << "Non-constant value " << context.insts().Get(member_id)
-          << " of unbound element type";
+      CARBON_CHECK(element_id.is_valid(),
+                   "Non-constant value {0} of unbound element type",
+                   context.insts().Get(member_id));
       auto index = GetClassElementIndex(context, element_id);
       auto index = GetClassElementIndex(context, element_id);
       auto access_id = context.AddInst<SemIR::ClassElementAccess>(
       auto access_id = context.AddInst<SemIR::ClassElementAccess>(
           loc_id, {.type_id = unbound_element_type.element_type_id,
           loc_id, {.type_id = unbound_element_type.element_type_id,

+ 6 - 6
toolchain/check/merge.cpp

@@ -348,12 +348,12 @@ static auto CheckRedeclParamSyntax(Context& context,
       !prev_first_param_node_id.is_valid()) {
       !prev_first_param_node_id.is_valid()) {
     return true;
     return true;
   }
   }
-  CARBON_CHECK(new_last_param_node_id.is_valid())
-      << "new_last_param_node_id.is_valid should match "
-         "new_first_param_node_id.is_valid";
-  CARBON_CHECK(prev_last_param_node_id.is_valid())
-      << "prev_last_param_node_id.is_valid should match "
-         "prev_first_param_node_id.is_valid";
+  CARBON_CHECK(new_last_param_node_id.is_valid(),
+               "new_last_param_node_id.is_valid should match "
+               "new_first_param_node_id.is_valid");
+  CARBON_CHECK(prev_last_param_node_id.is_valid(),
+               "prev_last_param_node_id.is_valid should match "
+               "prev_first_param_node_id.is_valid");
 
 
   auto new_range = Parse::Tree::PostorderIterator::MakeRange(
   auto new_range = Parse::Tree::PostorderIterator::MakeRange(
       new_first_param_node_id, new_last_param_node_id);
       new_first_param_node_id, new_last_param_node_id);

+ 1 - 1
toolchain/check/node_stack.cpp

@@ -14,7 +14,7 @@ auto NodeStack::PrintForStackDump(SemIR::Formatter& formatter, int indent,
     if constexpr (Kind == Id::Kind::None) {
     if constexpr (Kind == Id::Kind::None) {
       output << "no value\n";
       output << "no value\n";
     } else if constexpr (Kind == Id::Kind::Invalid) {
     } else if constexpr (Kind == Id::Kind::Invalid) {
-      CARBON_FATAL() << "Should not be in node stack";
+      CARBON_FATAL("Should not be in node stack");
     } else if constexpr (Kind == Id::KindFor<SemIR::InstId>()) {
     } else if constexpr (Kind == Id::KindFor<SemIR::InstId>()) {
       output << "\n";
       output << "\n";
       formatter.PrintInst(id.As<Id::KindFor<SemIR::InstId>()>(), indent + 4,
       formatter.PrintInst(id.As<Id::KindFor<SemIR::InstId>()>(), indent + 4,

+ 19 - 20
toolchain/check/node_stack.h

@@ -79,11 +79,11 @@ class NodeStack {
   // IR generated by the node.
   // IR generated by the node.
   auto Push(Parse::NodeId node_id) -> void {
   auto Push(Parse::NodeId node_id) -> void {
     auto kind = parse_tree_->node_kind(node_id);
     auto kind = parse_tree_->node_kind(node_id);
-    CARBON_CHECK(NodeKindToIdKind(kind) == Id::Kind::None)
-        << "Parse kind expects an Id: " << kind;
+    CARBON_CHECK(NodeKindToIdKind(kind) == Id::Kind::None,
+                 "Parse kind expects an Id: {0}", kind);
     CARBON_VLOG("Node Push {0}: {1} -> <none>\n", stack_.size(), kind);
     CARBON_VLOG("Node Push {0}: {1} -> <none>\n", stack_.size(), kind);
-    CARBON_CHECK(stack_.size() < (1 << 20))
-        << "Excessive stack size: likely infinite loop";
+    CARBON_CHECK(stack_.size() < (1 << 20),
+                 "Excessive stack size: likely infinite loop");
     stack_.push_back({.node_id = node_id, .id = Id()});
     stack_.push_back({.node_id = node_id, .id = Id()});
   }
   }
 
 
@@ -91,14 +91,13 @@ class NodeStack {
   template <typename IdT>
   template <typename IdT>
   auto Push(Parse::NodeId node_id, IdT id) -> void {
   auto Push(Parse::NodeId node_id, IdT id) -> void {
     auto kind = parse_tree_->node_kind(node_id);
     auto kind = parse_tree_->node_kind(node_id);
-    CARBON_CHECK(NodeKindToIdKind(kind) == Id::KindFor<IdT>())
-        << "Parse kind expected a different IdT: " << kind << " -> " << id
-        << "\n";
-    CARBON_CHECK(id.is_valid())
-        << "Push called with invalid id: " << parse_tree_->node_kind(node_id);
+    CARBON_CHECK(NodeKindToIdKind(kind) == Id::KindFor<IdT>(),
+                 "Parse kind expected a different IdT: {0} -> {1}\n", kind, id);
+    CARBON_CHECK(id.is_valid(), "Push called with invalid id: {0}",
+                 parse_tree_->node_kind(node_id));
     CARBON_VLOG("Node Push {0}: {1} -> {2}\n", stack_.size(), kind, id);
     CARBON_VLOG("Node Push {0}: {1} -> {2}\n", stack_.size(), kind, id);
-    CARBON_CHECK(stack_.size() < (1 << 20))
-        << "Excessive stack size: likely infinite loop";
+    CARBON_CHECK(stack_.size() < (1 << 20),
+                 "Excessive stack size: likely infinite loop");
     stack_.push_back({.node_id = node_id, .id = Id(id)});
     stack_.push_back({.node_id = node_id, .id = Id(id)});
   }
   }
 
 
@@ -690,27 +689,27 @@ class NodeStack {
   // Require a Parse::NodeKind be mapped to a particular Id::Kind.
   // Require a Parse::NodeKind be mapped to a particular Id::Kind.
   auto RequireIdKind(Parse::NodeKind parse_kind, Id::Kind id_kind) const
   auto RequireIdKind(Parse::NodeKind parse_kind, Id::Kind id_kind) const
       -> void {
       -> void {
-    CARBON_CHECK(NodeKindToIdKind(parse_kind) == id_kind)
-        << "Unexpected Id::Kind mapping for " << parse_kind << ": expected "
-        << static_cast<int>(id_kind) << ", found "
-        << static_cast<int>(NodeKindToIdKind(parse_kind));
+    CARBON_CHECK(NodeKindToIdKind(parse_kind) == id_kind,
+                 "Unexpected Id::Kind mapping for {0}: expected {1}, found {2}",
+                 parse_kind, static_cast<int>(id_kind),
+                 static_cast<int>(NodeKindToIdKind(parse_kind)));
   }
   }
 
 
   // Require an entry to have the given Parse::NodeKind.
   // Require an entry to have the given Parse::NodeKind.
   template <const Parse::NodeKind& RequiredParseKind>
   template <const Parse::NodeKind& RequiredParseKind>
   auto RequireParseKind(Parse::NodeId node_id) const -> void {
   auto RequireParseKind(Parse::NodeId node_id) const -> void {
     auto actual_kind = parse_tree_->node_kind(node_id);
     auto actual_kind = parse_tree_->node_kind(node_id);
-    CARBON_CHECK(RequiredParseKind == actual_kind)
-        << "Expected " << RequiredParseKind << ", found " << actual_kind;
+    CARBON_CHECK(RequiredParseKind == actual_kind, "Expected {0}, found {1}",
+                 RequiredParseKind, actual_kind);
   }
   }
 
 
   // Require an entry to have the given Parse::NodeCategory.
   // Require an entry to have the given Parse::NodeCategory.
   template <Parse::NodeCategory::RawEnumType RequiredParseCategory>
   template <Parse::NodeCategory::RawEnumType RequiredParseCategory>
   auto RequireParseCategory(Parse::NodeId node_id) const -> void {
   auto RequireParseCategory(Parse::NodeId node_id) const -> void {
     auto kind = parse_tree_->node_kind(node_id);
     auto kind = parse_tree_->node_kind(node_id);
-    CARBON_CHECK(kind.category().HasAnyOf(RequiredParseCategory))
-        << "Expected " << RequiredParseCategory << ", found " << kind
-        << " with category " << kind.category();
+    CARBON_CHECK(kind.category().HasAnyOf(RequiredParseCategory),
+                 "Expected {0}, found {1} with category {2}",
+                 RequiredParseCategory, kind, kind.category());
   }
   }
 
 
   // The file's parse tree.
   // The file's parse tree.

+ 4 - 4
toolchain/check/return.cpp

@@ -11,8 +11,8 @@ namespace Carbon::Check {
 
 
 // Gets the function that lexically encloses the current location.
 // Gets the function that lexically encloses the current location.
 static auto GetCurrentFunction(Context& context) -> SemIR::Function& {
 static auto GetCurrentFunction(Context& context) -> SemIR::Function& {
-  CARBON_CHECK(!context.return_scope_stack().empty())
-      << "Handling return but not in a function";
+  CARBON_CHECK(!context.return_scope_stack().empty(),
+               "Handling return but not in a function");
   auto function_id = context.insts()
   auto function_id = context.insts()
                          .GetAs<SemIR::FunctionDecl>(
                          .GetAs<SemIR::FunctionDecl>(
                              context.return_scope_stack().back().decl_id)
                              context.return_scope_stack().back().decl_id)
@@ -23,8 +23,8 @@ static auto GetCurrentFunction(Context& context) -> SemIR::Function& {
 // Gets the currently in scope `returned var`, if any, that would be returned
 // Gets the currently in scope `returned var`, if any, that would be returned
 // by a `return var;`.
 // by a `return var;`.
 static auto GetCurrentReturnedVar(Context& context) -> SemIR::InstId {
 static auto GetCurrentReturnedVar(Context& context) -> SemIR::InstId {
-  CARBON_CHECK(!context.return_scope_stack().empty())
-      << "Handling return but not in a function";
+  CARBON_CHECK(!context.return_scope_stack().empty(),
+               "Handling return but not in a function");
   return context.return_scope_stack().back().returned_var;
   return context.return_scope_stack().back().returned_var;
 }
 }
 
 

+ 32 - 30
toolchain/check/scope_stack.cpp

@@ -10,7 +10,7 @@
 namespace Carbon::Check {
 namespace Carbon::Check {
 
 
 auto ScopeStack::VerifyOnFinish() -> void {
 auto ScopeStack::VerifyOnFinish() -> void {
-  CARBON_CHECK(scope_stack_.empty()) << scope_stack_.size();
+  CARBON_CHECK(scope_stack_.empty(), "{0}", scope_stack_.size());
 }
 }
 
 
 auto ScopeStack::Push(SemIR::InstId scope_inst_id, SemIR::NameScopeId scope_id,
 auto ScopeStack::Push(SemIR::InstId scope_inst_id, SemIR::NameScopeId scope_id,
@@ -41,13 +41,13 @@ auto ScopeStack::Push(SemIR::InstId scope_inst_id, SemIR::NameScopeId scope_id,
     // For lexical lookups, unqualified lookup doesn't know how to find the
     // For lexical lookups, unqualified lookup doesn't know how to find the
     // associated specific, so if we start adding lexical scopes associated with
     // associated specific, so if we start adding lexical scopes associated with
     // specifics, we'll need to somehow track them in lookup.
     // specifics, we'll need to somehow track them in lookup.
-    CARBON_CHECK(!specific_id.is_valid())
-        << "Lexical scope should not have an associated specific.";
+    CARBON_CHECK(!specific_id.is_valid(),
+                 "Lexical scope should not have an associated specific.");
   }
   }
 
 
   // TODO: Handle this case more gracefully.
   // TODO: Handle this case more gracefully.
-  CARBON_CHECK(next_scope_index_.index != std::numeric_limits<int32_t>::max())
-      << "Ran out of scopes";
+  CARBON_CHECK(next_scope_index_.index != std::numeric_limits<int32_t>::max(),
+               "Ran out of scopes");
   ++next_scope_index_.index;
   ++next_scope_index_.index;
 }
 }
 
 
@@ -56,8 +56,8 @@ auto ScopeStack::Pop() -> void {
 
 
   scope.names.ForEach([&](SemIR::NameId str_id) {
   scope.names.ForEach([&](SemIR::NameId str_id) {
     auto& lexical_results = lexical_lookup_.Get(str_id);
     auto& lexical_results = lexical_lookup_.Get(str_id);
-    CARBON_CHECK(lexical_results.back().scope_index == scope.index)
-        << "Inconsistent scope index for name " << str_id;
+    CARBON_CHECK(lexical_results.back().scope_index == scope.index,
+                 "Inconsistent scope index for name {0}", str_id);
     lexical_results.pop_back();
     lexical_results.pop_back();
   });
   });
 
 
@@ -74,10 +74,11 @@ auto ScopeStack::Pop() -> void {
 
 
   CARBON_CHECK(
   CARBON_CHECK(
       scope.next_compile_time_bind_index.index ==
       scope.next_compile_time_bind_index.index ==
-      static_cast<int32_t>(compile_time_binding_stack_.all_values_size()))
-      << "Wrong number of entries in compile-time binding stack, have "
-      << compile_time_binding_stack_.all_values_size() << ", expected "
-      << scope.next_compile_time_bind_index.index;
+          static_cast<int32_t>(compile_time_binding_stack_.all_values_size()),
+      "Wrong number of entries in compile-time binding stack, have {0}, "
+      "expected {1}",
+      compile_time_binding_stack_.all_values_size(),
+      scope.next_compile_time_bind_index.index);
   compile_time_binding_stack_.PopArray();
   compile_time_binding_stack_.PopArray();
 }
 }
 
 
@@ -85,9 +86,9 @@ auto ScopeStack::PopTo(ScopeIndex index) -> void {
   while (PeekIndex() > index) {
   while (PeekIndex() > index) {
     Pop();
     Pop();
   }
   }
-  CARBON_CHECK(PeekIndex() == index)
-      << "Scope index " << index << " does not enclose the current scope "
-      << PeekIndex();
+  CARBON_CHECK(PeekIndex() == index,
+               "Scope index {0} does not enclose the current scope {1}", index,
+               PeekIndex());
 }
 }
 
 
 auto ScopeStack::LookupInCurrentScope(SemIR::NameId name_id) -> SemIR::InstId {
 auto ScopeStack::LookupInCurrentScope(SemIR::NameId name_id) -> SemIR::InstId {
@@ -135,8 +136,8 @@ auto ScopeStack::LookupOrAddName(SemIR::NameId name_id, SemIR::InstId target_id)
     -> SemIR::InstId {
     -> SemIR::InstId {
   if (!scope_stack_.back().names.Insert(name_id).is_inserted()) {
   if (!scope_stack_.back().names.Insert(name_id).is_inserted()) {
     auto existing = lexical_lookup_.Get(name_id).back().inst_id;
     auto existing = lexical_lookup_.Get(name_id).back().inst_id;
-    CARBON_CHECK(existing.is_valid())
-        << "Name in scope but not in lexical lookups";
+    CARBON_CHECK(existing.is_valid(),
+                 "Name in scope but not in lexical lookups");
     return existing;
     return existing;
   }
   }
   ++scope_stack_.back().num_names;
   ++scope_stack_.back().num_names;
@@ -144,24 +145,25 @@ auto ScopeStack::LookupOrAddName(SemIR::NameId name_id, SemIR::InstId target_id)
   // TODO: Reject if we previously performed a failed lookup for this name
   // TODO: Reject if we previously performed a failed lookup for this name
   // in this scope or a scope nested within it.
   // in this scope or a scope nested within it.
   auto& lexical_results = lexical_lookup_.Get(name_id);
   auto& lexical_results = lexical_lookup_.Get(name_id);
-  CARBON_CHECK(lexical_results.empty() ||
-               lexical_results.back().scope_index < PeekIndex())
-      << "Failed to clean up after scope nested within the current scope";
+  CARBON_CHECK(
+      lexical_results.empty() ||
+          lexical_results.back().scope_index < PeekIndex(),
+      "Failed to clean up after scope nested within the current scope");
   lexical_results.push_back({.inst_id = target_id, .scope_index = PeekIndex()});
   lexical_results.push_back({.inst_id = target_id, .scope_index = PeekIndex()});
   return SemIR::InstId::Invalid;
   return SemIR::InstId::Invalid;
 }
 }
 
 
 auto ScopeStack::SetReturnedVarOrGetExisting(SemIR::InstId inst_id)
 auto ScopeStack::SetReturnedVarOrGetExisting(SemIR::InstId inst_id)
     -> SemIR::InstId {
     -> SemIR::InstId {
-  CARBON_CHECK(!return_scope_stack_.empty()) << "`returned var` in no function";
+  CARBON_CHECK(!return_scope_stack_.empty(), "`returned var` in no function");
   auto& returned_var = return_scope_stack_.back().returned_var;
   auto& returned_var = return_scope_stack_.back().returned_var;
   if (returned_var.is_valid()) {
   if (returned_var.is_valid()) {
     return returned_var;
     return returned_var;
   }
   }
 
 
   returned_var = inst_id;
   returned_var = inst_id;
-  CARBON_CHECK(!scope_stack_.back().has_returned_var)
-      << "Scope has returned var but none is set";
+  CARBON_CHECK(!scope_stack_.back().has_returned_var,
+               "Scope has returned var but none is set");
   if (inst_id.is_valid()) {
   if (inst_id.is_valid()) {
     scope_stack_.back().has_returned_var = true;
     scope_stack_.back().has_returned_var = true;
   }
   }
@@ -169,7 +171,7 @@ auto ScopeStack::SetReturnedVarOrGetExisting(SemIR::InstId inst_id)
 }
 }
 
 
 auto ScopeStack::Suspend() -> SuspendedScope {
 auto ScopeStack::Suspend() -> SuspendedScope {
-  CARBON_CHECK(!scope_stack_.empty()) << "No scope to suspend";
+  CARBON_CHECK(!scope_stack_.empty(), "No scope to suspend");
   SuspendedScope result = {.entry = scope_stack_.pop_back_val(),
   SuspendedScope result = {.entry = scope_stack_.pop_back_val(),
                            .suspended_items = {}};
                            .suspended_items = {}};
   if (result.entry.scope_id.is_valid()) {
   if (result.entry.scope_id.is_valid()) {
@@ -198,8 +200,8 @@ auto ScopeStack::Suspend() -> SuspendedScope {
   compile_time_binding_stack_.PopArray();
   compile_time_binding_stack_.PopArray();
 
 
   // This would be easy to support if we had a need, but currently we do not.
   // This would be easy to support if we had a need, but currently we do not.
-  CARBON_CHECK(!result.entry.has_returned_var)
-      << "Should not suspend a scope with a returned var.";
+  CARBON_CHECK(!result.entry.has_returned_var,
+               "Should not suspend a scope with a returned var.");
   return result;
   return result;
 }
 }
 
 
@@ -216,11 +218,11 @@ auto ScopeStack::Restore(SuspendedScope scope) -> void {
 
 
   CARBON_CHECK(
   CARBON_CHECK(
       scope.entry.next_compile_time_bind_index.index ==
       scope.entry.next_compile_time_bind_index.index ==
-      static_cast<int32_t>(compile_time_binding_stack_.all_values_size()))
-      << "Wrong number of entries in compile-time binding stack "
-         "when restoring, have "
-      << compile_time_binding_stack_.all_values_size() << ", expected "
-      << scope.entry.next_compile_time_bind_index.index;
+          static_cast<int32_t>(compile_time_binding_stack_.all_values_size()),
+      "Wrong number of entries in compile-time binding stack when restoring, "
+      "have {0}, expected {1}",
+      compile_time_binding_stack_.all_values_size(),
+      scope.entry.next_compile_time_bind_index.index);
 
 
   if (scope.entry.scope_id.is_valid()) {
   if (scope.entry.scope_id.is_valid()) {
     non_lexical_scope_stack_.push_back(
     non_lexical_scope_stack_.push_back(

+ 6 - 6
toolchain/check/sem_ir_diagnostic_converter.cpp

@@ -18,9 +18,9 @@ auto SemIRDiagnosticConverter::ConvertLoc(SemIRLoc loc,
   auto follow_import_ref = [&](SemIR::ImportIRInstId import_ir_inst_id) {
   auto follow_import_ref = [&](SemIR::ImportIRInstId import_ir_inst_id) {
     auto import_ir_inst = cursor_ir->import_ir_insts().Get(import_ir_inst_id);
     auto import_ir_inst = cursor_ir->import_ir_insts().Get(import_ir_inst_id);
     const auto& import_ir = cursor_ir->import_irs().Get(import_ir_inst.ir_id);
     const auto& import_ir = cursor_ir->import_irs().Get(import_ir_inst.ir_id);
-    CARBON_CHECK(import_ir.decl_id.is_valid())
-        << "If we get invalid locations here, we may need to more thoroughly "
-           "track ImportDecls.";
+    CARBON_CHECK(import_ir.decl_id.is_valid(),
+                 "If we get invalid locations here, we may need to more "
+                 "thoroughly track ImportDecls.");
 
 
     DiagnosticLoc in_import_loc;
     DiagnosticLoc in_import_loc;
     auto import_loc_id = cursor_ir->insts().GetLocId(import_ir.decl_id);
     auto import_loc_id = cursor_ir->insts().GetLocId(import_ir.decl_id);
@@ -37,8 +37,8 @@ auto SemIRDiagnosticConverter::ConvertLoc(SemIRLoc loc,
           cursor_ir->import_irs().Get(implicit_import_ir_inst.ir_id);
           cursor_ir->import_irs().Get(implicit_import_ir_inst.ir_id);
       auto implicit_loc_id =
       auto implicit_loc_id =
           implicit_ir.sem_ir->insts().GetLocId(implicit_import_ir_inst.inst_id);
           implicit_ir.sem_ir->insts().GetLocId(implicit_import_ir_inst.inst_id);
-      CARBON_CHECK(implicit_loc_id.is_node_id())
-          << "Should only be one layer of implicit imports";
+      CARBON_CHECK(implicit_loc_id.is_node_id(),
+                   "Should only be one layer of implicit imports");
       in_import_loc =
       in_import_loc =
           ConvertLocInFile(implicit_ir.sem_ir, implicit_loc_id.node_id(),
           ConvertLocInFile(implicit_ir.sem_ir, implicit_loc_id.node_id(),
                            loc.token_only, context_fn);
                            loc.token_only, context_fn);
@@ -75,7 +75,7 @@ auto SemIRDiagnosticConverter::ConvertLoc(SemIRLoc loc,
     if (auto diag_loc = handle_loc(loc.loc_id)) {
     if (auto diag_loc = handle_loc(loc.loc_id)) {
       return *diag_loc;
       return *diag_loc;
     }
     }
-    CARBON_CHECK(cursor_inst_id.is_valid()) << "Should have been set";
+    CARBON_CHECK(cursor_inst_id.is_valid(), "Should have been set");
   }
   }
 
 
   while (true) {
   while (true) {

+ 6 - 6
toolchain/check/subst.cpp

@@ -45,7 +45,7 @@ class Worklist {
     worklist_.push_back({.inst_id = inst_id,
     worklist_.push_back({.inst_id = inst_id,
                          .is_expanded = false,
                          .is_expanded = false,
                          .next_index = static_cast<int>(worklist_.size() + 1)});
                          .next_index = static_cast<int>(worklist_.size() + 1)});
-    CARBON_CHECK(worklist_.back().next_index > 0) << "Constant too large.";
+    CARBON_CHECK(worklist_.back().next_index > 0, "Constant too large.");
   }
   }
   auto Pop() -> SemIR::InstId { return worklist_.pop_back_val().inst_id; }
   auto Pop() -> SemIR::InstId { return worklist_.pop_back_val().inst_id; }
 
 
@@ -240,8 +240,8 @@ auto SubstInst(Context& context, SemIR::InstId inst_id,
     }
     }
   }
   }
 
 
-  CARBON_CHECK(worklist.size() == 1)
-      << "Unexpected data left behind in work list";
+  CARBON_CHECK(worklist.size() == 1,
+               "Unexpected data left behind in work list");
   return worklist.back().inst_id;
   return worklist.back().inst_id;
 }
 }
 
 
@@ -288,8 +288,8 @@ class SubstConstantCallbacks final : public SubstInstCallbacks {
   auto Rebuild(SemIR::InstId /*old_inst_id*/, SemIR::Inst new_inst) const
   auto Rebuild(SemIR::InstId /*old_inst_id*/, SemIR::Inst new_inst) const
       -> SemIR::InstId override {
       -> SemIR::InstId override {
     auto result_id = TryEvalInst(context_, SemIR::InstId::Invalid, new_inst);
     auto result_id = TryEvalInst(context_, SemIR::InstId::Invalid, new_inst);
-    CARBON_CHECK(result_id.is_constant())
-        << "Substitution into constant produced non-constant";
+    CARBON_CHECK(result_id.is_constant(),
+                 "Substitution into constant produced non-constant");
     return context_.constant_values().GetInstId(result_id);
     return context_.constant_values().GetInstId(result_id);
   }
   }
 
 
@@ -301,7 +301,7 @@ class SubstConstantCallbacks final : public SubstInstCallbacks {
 
 
 auto SubstConstant(Context& context, SemIR::ConstantId const_id,
 auto SubstConstant(Context& context, SemIR::ConstantId const_id,
                    Substitutions substitutions) -> SemIR::ConstantId {
                    Substitutions substitutions) -> SemIR::ConstantId {
-  CARBON_CHECK(const_id.is_constant()) << "Substituting into non-constant";
+  CARBON_CHECK(const_id.is_constant(), "Substituting into non-constant");
 
 
   if (substitutions.empty()) {
   if (substitutions.empty()) {
     // Nothing to substitute.
     // Nothing to substitute.

+ 9 - 8
toolchain/diagnostics/diagnostic_emitter.h

@@ -63,8 +63,8 @@ class DiagnosticEmitter {
     auto Note(LocT loc,
     auto Note(LocT loc,
               const Internal::DiagnosticBase<Args...>& diagnostic_base,
               const Internal::DiagnosticBase<Args...>& diagnostic_base,
               Internal::NoTypeDeduction<Args>... args) -> DiagnosticBuilder& {
               Internal::NoTypeDeduction<Args>... args) -> DiagnosticBuilder& {
-      CARBON_CHECK(diagnostic_base.Level == DiagnosticLevel::Note)
-          << static_cast<int>(diagnostic_base.Level);
+      CARBON_CHECK(diagnostic_base.Level == DiagnosticLevel::Note, "{0}",
+                   static_cast<int>(diagnostic_base.Level));
       AddMessage(loc, diagnostic_base, {emitter_->MakeAny<Args>(args)...});
       AddMessage(loc, diagnostic_base, {emitter_->MakeAny<Args>(args)...});
       return *this;
       return *this;
     }
     }
@@ -137,9 +137,9 @@ class DiagnosticEmitter {
     static auto FormatFn(const DiagnosticMessage& message,
     static auto FormatFn(const DiagnosticMessage& message,
                          std::index_sequence<N...> /*indices*/) -> std::string {
                          std::index_sequence<N...> /*indices*/) -> std::string {
       static_assert(sizeof...(Args) == sizeof...(N), "Invalid template args");
       static_assert(sizeof...(Args) == sizeof...(N), "Invalid template args");
-      CARBON_CHECK(message.format_args.size() == sizeof...(Args))
-          << "Argument count mismatch on " << message.kind << ": "
-          << message.format_args.size() << " != " << sizeof...(Args);
+      CARBON_CHECK(message.format_args.size() == sizeof...(Args),
+                   "Argument count mismatch on {0}: {1} != {2}", message.kind,
+                   message.format_args.size(), sizeof...(Args));
       return llvm::formatv(
       return llvm::formatv(
           message.format.data(),
           message.format.data(),
           llvm::any_cast<
           llvm::any_cast<
@@ -189,9 +189,10 @@ class DiagnosticEmitter {
   auto MakeAny(Arg arg) -> llvm::Any {
   auto MakeAny(Arg arg) -> llvm::Any {
     llvm::Any converted = converter_->ConvertArg(arg);
     llvm::Any converted = converter_->ConvertArg(arg);
     using Storage = Internal::DiagnosticTypeForArg<Arg>::StorageType;
     using Storage = Internal::DiagnosticTypeForArg<Arg>::StorageType;
-    CARBON_CHECK(llvm::any_cast<Storage>(&converted))
-        << "Failed to convert argument of type " << typeid(Arg).name()
-        << " to its storage type " << typeid(Storage).name();
+    CARBON_CHECK(
+        llvm::any_cast<Storage>(&converted),
+        "Failed to convert argument of type {0} to its storage type {1}",
+        typeid(Arg).name(), typeid(Storage).name());
     return converted;
     return converted;
   }
   }
 
 

+ 2 - 2
toolchain/diagnostics/sorting_diagnostic_consumer.h

@@ -22,8 +22,8 @@ class SortingDiagnosticConsumer : public DiagnosticConsumer {
     // likely to refer to data that gets destroyed before the diagnostics
     // likely to refer to data that gets destroyed before the diagnostics
     // consumer is destroyed, because the diagnostics consumer is typically
     // consumer is destroyed, because the diagnostics consumer is typically
     // created before the objects that diagnostics refer into are created.
     // created before the objects that diagnostics refer into are created.
-    CARBON_CHECK(diagnostics_.empty())
-        << "Must flush diagnostics consumer before destroying it";
+    CARBON_CHECK(diagnostics_.empty(),
+                 "Must flush diagnostics consumer before destroying it");
   }
   }
 
 
   // Buffers the diagnostic.
   // Buffers the diagnostic.

+ 1 - 1
toolchain/docs/idioms.md

@@ -289,7 +289,7 @@ CARBON_DCHECK([&] {
   return complicated && multiple_parts;
   return complicated && multiple_parts;
 
 
 // finish defining the lambda, and then immediately invoke it
 // finish defining the lambda, and then immediately invoke it
-}()) << "Complicated things went wrong";
+}(), "Complicated things went wrong");
 ```
 ```
 
 
 See a description of this technique on
 See a description of this technique on

+ 1 - 1
toolchain/driver/clang_runner.cpp

@@ -118,7 +118,7 @@ auto ClangRunner::Run(llvm::ArrayRef<llvm::StringRef> args) -> bool {
   // driver.CC1Main = [](llvm::SmallVectorImpl<const char*>& argv) {};
   // driver.CC1Main = [](llvm::SmallVectorImpl<const char*>& argv) {};
   std::unique_ptr<clang::driver::Compilation> compilation(
   std::unique_ptr<clang::driver::Compilation> compilation(
       driver.BuildCompilation(cstr_args));
       driver.BuildCompilation(cstr_args));
-  CARBON_CHECK(compilation) << "Should always successfully allocate!";
+  CARBON_CHECK(compilation, "Should always successfully allocate!");
   if (compilation->containsError()) {
   if (compilation->containsError()) {
     // These should have been diagnosed by the driver.
     // These should have been diagnosed by the driver.
     return false;
     return false;

+ 1 - 1
toolchain/driver/clang_runner_test.cpp

@@ -106,7 +106,7 @@ static auto WriteTestFile(llvm::StringRef name_suffix, llvm::Twine contents)
   {
   {
     std::error_code ec;
     std::error_code ec;
     llvm::raw_fd_ostream test_file_stream(test_file.string(), ec);
     llvm::raw_fd_ostream test_file_stream(test_file.string(), ec);
-    CARBON_CHECK(!ec) << "Test file error: " << ec.message();
+    CARBON_CHECK(!ec, "Test file error: {0}", ec.message());
     test_file_stream << contents;
     test_file_stream << contents;
   }
   }
   return test_file;
   return test_file;

+ 2 - 2
toolchain/driver/driver.cpp

@@ -946,8 +946,8 @@ auto Driver::Compile(const CompileOptions& options,
   if (options.phase == CompileOptions::Phase::Lower) {
   if (options.phase == CompileOptions::Phase::Lower) {
     return make_result();
     return make_result();
   }
   }
-  CARBON_CHECK(options.phase == CompileOptions::Phase::CodeGen)
-      << "CodeGen should be the last stage";
+  CARBON_CHECK(options.phase == CompileOptions::Phase::CodeGen,
+               "CodeGen should be the last stage");
 
 
   // Codegen.
   // Codegen.
   for (auto& unit : units) {
   for (auto& unit : units) {

+ 1 - 1
toolchain/driver/driver_fuzzer.cpp

@@ -20,7 +20,7 @@ static const InstallPaths* install_paths = nullptr;
 
 
 // NOLINTNEXTLINE(readability-non-const-parameter): External API required types.
 // NOLINTNEXTLINE(readability-non-const-parameter): External API required types.
 extern "C" auto LLVMFuzzerInitialize(int* argc, char*** argv) -> int {
 extern "C" auto LLVMFuzzerInitialize(int* argc, char*** argv) -> int {
-  CARBON_CHECK(*argc >= 1) << "Need the `argv[0]` value to initialize!";
+  CARBON_CHECK(*argc >= 1, "Need the `argv[0]` value to initialize!");
   install_paths = new InstallPaths(
   install_paths = new InstallPaths(
       InstallPaths::MakeForBazelRunfiles(FindExecutablePath((*argv)[0])));
       InstallPaths::MakeForBazelRunfiles(FindExecutablePath((*argv)[0])));
   return 0;
   return 0;

+ 10 - 9
toolchain/driver/driver_test.cpp

@@ -65,7 +65,7 @@ class DriverTest : public testing::Test {
     // Save our current working directory.
     // Save our current working directory.
     std::error_code ec;
     std::error_code ec;
     auto original_dir = std::filesystem::current_path(ec);
     auto original_dir = std::filesystem::current_path(ec);
-    CARBON_CHECK(!ec) << ec.message();
+    CARBON_CHECK(!ec, "{0}", ec.message());
 
 
     const auto* unit_test = ::testing::UnitTest::GetInstance();
     const auto* unit_test = ::testing::UnitTest::GetInstance();
     const auto* test_info = unit_test->current_test_info();
     const auto* test_info = unit_test->current_test_info();
@@ -74,19 +74,20 @@ class DriverTest : public testing::Test {
                       test_info->name())
                       test_info->name())
             .str());
             .str());
     std::filesystem::create_directory(test_dir, ec);
     std::filesystem::create_directory(test_dir, ec);
-    CARBON_CHECK(!ec) << "Could not create test working dir '" << test_dir
-                      << "': " << ec.message();
+    CARBON_CHECK(!ec, "Could not create test working dir '{0}': {1}", test_dir,
+                 ec.message());
     std::filesystem::current_path(test_dir, ec);
     std::filesystem::current_path(test_dir, ec);
-    CARBON_CHECK(!ec) << "Could not change the current working dir to '"
-                      << test_dir << "': " << ec.message();
+    CARBON_CHECK(!ec, "Could not change the current working dir to '{0}': {1}",
+                 test_dir, ec.message());
     return llvm::make_scope_exit([original_dir, test_dir] {
     return llvm::make_scope_exit([original_dir, test_dir] {
       std::error_code ec;
       std::error_code ec;
       std::filesystem::current_path(original_dir, ec);
       std::filesystem::current_path(original_dir, ec);
-      CARBON_CHECK(!ec) << "Could not change the current working dir to '"
-                        << original_dir << "': " << ec.message();
+      CARBON_CHECK(!ec,
+                   "Could not change the current working dir to '{0}': {1}",
+                   original_dir, ec.message());
       std::filesystem::remove_all(test_dir, ec);
       std::filesystem::remove_all(test_dir, ec);
-      CARBON_CHECK(!ec) << "Could not remove the test working dir '" << test_dir
-                        << "': " << ec.message();
+      CARBON_CHECK(!ec, "Could not remove the test working dir '{0}': {1}",
+                   test_dir, ec.message());
     });
     });
   }
   }
 
 

+ 3 - 3
toolchain/install/install_paths.cpp

@@ -54,8 +54,8 @@ auto InstallPaths::MakeForBazelRunfiles(llvm::StringRef exe_path)
   std::string runtimes_error;
   std::string runtimes_error;
   std::unique_ptr<Runfiles> runfiles(
   std::unique_ptr<Runfiles> runfiles(
       Runfiles::Create(exe_path.str(), &runtimes_error));
       Runfiles::Create(exe_path.str(), &runtimes_error));
-  CARBON_CHECK(runfiles != nullptr)
-      << "Failed to find runtimes tree: " << runtimes_error;
+  CARBON_CHECK(runfiles != nullptr, "Failed to find runtimes tree: {0}",
+               runtimes_error);
 
 
   std::string relative_marker_path = (PrefixRoot.str() + MarkerPath).str();
   std::string relative_marker_path = (PrefixRoot.str() + MarkerPath).str();
   std::string runtimes_marker_path = runfiles->Rlocation(relative_marker_path);
   std::string runtimes_marker_path = runfiles->Rlocation(relative_marker_path);
@@ -68,7 +68,7 @@ auto InstallPaths::MakeForBazelRunfiles(llvm::StringRef exe_path)
                           "../../");
                           "../../");
 
 
   paths.CheckMarkerFile();
   paths.CheckMarkerFile();
-  CARBON_CHECK(!paths.error()) << *paths.error();
+  CARBON_CHECK(!paths.error(), "{0}", *paths.error());
   return paths;
   return paths;
 }
 }
 
 

+ 5 - 5
toolchain/install/install_paths_test.cpp

@@ -29,7 +29,7 @@ class InstallPathsTest : public ::testing::Test {
   InstallPathsTest() {
   InstallPathsTest() {
     std::string error;
     std::string error;
     test_runfiles_.reset(Runfiles::Create(Testing::GetExePath().str(), &error));
     test_runfiles_.reset(Runfiles::Create(Testing::GetExePath().str(), &error));
-    CARBON_CHECK(test_runfiles_ != nullptr) << error;
+    CARBON_CHECK(test_runfiles_ != nullptr, "{0}", error);
   }
   }
 
 
   // Test the install paths found with the given `exe_path`. Will check that
   // Test the install paths found with the given `exe_path`. Will check that
@@ -92,8 +92,8 @@ TEST_F(InstallPathsTest, PrefixRootExplicit) {
       "carbon/toolchain/install/prefix_root/lib/carbon/carbon_install.txt");
       "carbon/toolchain/install/prefix_root/lib/carbon/carbon_install.txt");
 
 
   llvm::StringRef prefix_path = marker_path;
   llvm::StringRef prefix_path = marker_path;
-  CARBON_CHECK(prefix_path.consume_back("lib/carbon/carbon_install.txt"))
-      << "Unexpected suffix of the marker path: " << marker_path;
+  CARBON_CHECK(prefix_path.consume_back("lib/carbon/carbon_install.txt"),
+               "Unexpected suffix of the marker path: {0}", marker_path);
 
 
   auto paths = InstallPaths::Make(prefix_path);
   auto paths = InstallPaths::Make(prefix_path);
   ASSERT_THAT(paths.error(), Eq(std::nullopt)) << *paths.error();
   ASSERT_THAT(paths.error(), Eq(std::nullopt)) << *paths.error();
@@ -109,8 +109,8 @@ TEST_F(InstallPathsTest, TestRunfiles) {
 TEST_F(InstallPathsTest, BinaryRunfiles) {
 TEST_F(InstallPathsTest, BinaryRunfiles) {
   std::string test_binary_path =
   std::string test_binary_path =
       test_runfiles_->Rlocation("carbon/toolchain/install/test_binary");
       test_runfiles_->Rlocation("carbon/toolchain/install/test_binary");
-  CARBON_CHECK(llvm::sys::fs::can_execute(test_binary_path))
-      << test_binary_path;
+  CARBON_CHECK(llvm::sys::fs::can_execute(test_binary_path), "{0}",
+               test_binary_path);
 
 
   auto paths = InstallPaths::MakeForBazelRunfiles(test_binary_path);
   auto paths = InstallPaths::MakeForBazelRunfiles(test_binary_path);
   ASSERT_THAT(paths.error(), Eq(std::nullopt)) << *paths.error();
   ASSERT_THAT(paths.error(), Eq(std::nullopt)) << *paths.error();

+ 3 - 3
toolchain/install/install_paths_test_helpers.cpp

@@ -15,14 +15,14 @@ auto AddPreludeFilesToVfs(InstallPaths install_paths,
   // Load the prelude into the test VFS.
   // Load the prelude into the test VFS.
   auto real_fs = llvm::vfs::getRealFileSystem();
   auto real_fs = llvm::vfs::getRealFileSystem();
   auto prelude = install_paths.ReadPreludeManifest();
   auto prelude = install_paths.ReadPreludeManifest();
-  CARBON_CHECK(prelude.ok()) << prelude.error();
+  CARBON_CHECK(prelude.ok(), "{0}", prelude.error());
 
 
   for (const auto& path : *prelude) {
   for (const auto& path : *prelude) {
     llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> file =
     llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> file =
         real_fs->getBufferForFile(path);
         real_fs->getBufferForFile(path);
-    CARBON_CHECK(file) << "Error getting file: " << file.getError().message();
+    CARBON_CHECK(file, "Error getting file: {0}", file.getError().message());
     bool added = vfs->addFile(path, /*ModificationTime=*/0, std::move(*file));
     bool added = vfs->addFile(path, /*ModificationTime=*/0, std::move(*file));
-    CARBON_CHECK(added) << "Duplicate file: " << path;
+    CARBON_CHECK(added, "Duplicate file: {0}", path);
   }
   }
 }
 }
 
 

Некоторые файлы не были показаны из-за большого количества измененных файлов