Render diagnostics through the terminal library (#7683)

Diagnostic rendering was part of the data model: `Loc::FormatLocation`
and
`Loc::FormatSnippet` wrote plain text to a stream, so no capability,
color, or
terminal width could reach them.

A diagnostic is now one message with labels, contexts, and location
information
attached, and `Diagnostics::Renderer` draws it into a
`Terminal::Buffer`. The
design is in `toolchain/docs/diagnostics_rendering.md` (#7668),
authoring in
`toolchain/docs/diagnostics.md`.

Before:

```
example.carbon:6:3: error: 1 argument passed to function expecting 0 arguments
  Run0(1);
  ^~~~~~~
example.carbon:3:1: note: calling function declared here
fn Run0() {}
^~~~~~~~~~~
```

After:

```
error: 1 argument passed to function expecting 0 arguments
       ╭─┤ example.carbon:6:3
       ┆
     3 │ fn Run0() {}
       · ─────┬─────
       ·      ╰──┤ calling function declared here
       ┆
->   6 │   Run0(1);
       ·   ───────
       ╰────────────
```

`--no-diagnostic-snippets` gives a compact form, `example.carbon:6:3-9`.
File
tests use it; the rendering tests under `toolchain/diagnostics/testdata`
ask for
snippets.

C++ interop diagnostics are data now rather than text Clang drew:
`SemIR::ClangSourceLocId` names a `clang::SourceRange`, and a Clang
location is
marked as the point it names.

`StreamConsumer` moves to a `:renderer` target that `:emitter` does not
depend
on, keeping `common/terminal` out of `consumer.h`. Capabilities come
from the
file behind the error stream, so tests get plain ASCII.

`renderer_fuzzer` draws diagnostics built from fuzzer bytes with every
capability combination, since a shape the renderer doesn't expect must
never be
why the compiler dies while reporting a problem.

TODOs mark the follow-ups: line weights and crossing lines, wrapping
that keeps
a quoted type whole, and ordering diagnostics that share a byte offset.

Also: `IncorrectExtension`'s hint moves into its message, since its note
had no
location of its own, and `strip_noise` in `check_diagnostics.py` blanks
multi-line `#define`s instead of deleting them.

Assisted-by: Claude Code
This commit is contained in:
Chandler Carruth authored and GitHub committed 2026-10-15 06:08:57 +00:00
1 parent e1c8c1f855
commit 2c9739799b
1205 files changed
+20291 -24988

No files matched your search

@@ -25,57 +25,29 @@ auto foo2(ForwardDeclaredStruct) -> void;
library "[[@TEST_NAME]]";
// CHECK:STDERR: fail_import_decl_value_param_type.carbon:[[@LINE+8]]:10: in file included here [InCppInclude]
// CHECK:STDERR: ./decl_value_param_type.h:4:6: error: argument type 'ForwardDeclaredStruct' is incomplete [CppInteropParseError]
// CHECK:STDERR: 4 | auto foo1(ForwardDeclaredStruct) -> void;
// CHECK:STDERR: | ^~~~
// CHECK:STDERR: fail_import_decl_value_param_type.carbon:[[@LINE+4]]:10: in file included here [InCppInclude]
// CHECK:STDERR: included from: fail_import_decl_value_param_type.carbon:[[@LINE+3]]:10 [InCppInclude]
// CHECK:STDERR: ./decl_value_param_type.h:4:6-9: error: argument type 'ForwardDeclaredStruct' is incomplete [CppInteropParseError]
// CHECK:STDERR: ./decl_value_param_type.h:2:8: note: forward declaration of 'ForwardDeclaredStruct' [CppInteropParseNote]
// CHECK:STDERR: 2 | struct ForwardDeclaredStruct;
// CHECK:STDERR: | ^
import Cpp library "decl_value_param_type.h";
fn F(p: Cpp.ForwardDeclaredStruct*) {
// CHECK:STDERR: fail_import_decl_value_param_type.carbon:[[@LINE+12]]:3: note: in thunk for C++ function used here [InCppThunk]
// CHECK:STDERR: Cpp.foo1(*p);
// CHECK:STDERR: ^~~~~~~~~~~~
// CHECK:STDERR: fail_import_decl_value_param_type.carbon:[[@LINE+5]]:3-14: note: in thunk for C++ function used here [InCppThunk]
// CHECK:STDERR:
// CHECK:STDERR: fail_import_decl_value_param_type.carbon:[[@LINE-7]]:10: in file included here [InCppInclude]
// CHECK:STDERR: ./decl_value_param_type.h:5:6: error: argument type 'ForwardDeclaredStruct' is incomplete [CppInteropParseError]
// CHECK:STDERR: 5 | auto foo2(ForwardDeclaredStruct) -> void;
// CHECK:STDERR: | ^~~~
// CHECK:STDERR: fail_import_decl_value_param_type.carbon:[[@LINE-11]]:10: in file included here [InCppInclude]
// CHECK:STDERR: included from: fail_import_decl_value_param_type.carbon:[[@LINE-5]]:10 [InCppInclude]
// CHECK:STDERR: ./decl_value_param_type.h:5:6-9: error: argument type 'ForwardDeclaredStruct' is incomplete [CppInteropParseError]
// CHECK:STDERR: ./decl_value_param_type.h:2:8: note: forward declaration of 'ForwardDeclaredStruct' [CppInteropParseNote]
// CHECK:STDERR: 2 | struct ForwardDeclaredStruct;
// CHECK:STDERR: | ^
Cpp.foo1(*p);
// CHECK:STDERR: fail_import_decl_value_param_type.carbon:[[@LINE+28]]:3: note: in thunk for C++ function used here [InCppThunk]
// CHECK:STDERR: Cpp.foo2(*p);
// CHECK:STDERR: ^~~~~~~~~~~~
// CHECK:STDERR: fail_import_decl_value_param_type.carbon:[[@LINE+12]]:3-14: note: in thunk for C++ function used here [InCppThunk]
// CHECK:STDERR:
// CHECK:STDERR: fail_import_decl_value_param_type.carbon:[[@LINE-5]]:12: error: forming value of incomplete type `Cpp.ForwardDeclaredStruct` [IncompleteTypeInValueConversion]
// CHECK:STDERR: Cpp.foo1(*p);
// CHECK:STDERR: ^~
// CHECK:STDERR: fail_import_decl_value_param_type.carbon:[[@LINE-23]]:10: in file included here [InCppInclude]
// CHECK:STDERR: fail_import_decl_value_param_type.carbon:[[@LINE-3]]:12-13: error: forming value of incomplete type `Cpp.ForwardDeclaredStruct` [IncompleteTypeInValueConversion]
// CHECK:STDERR: included from: fail_import_decl_value_param_type.carbon:[[@LINE-12]]:10 [InCppInclude]
// CHECK:STDERR: ./decl_value_param_type.h:2:8: note: class was forward declared here [ClassForwardDeclaredHere]
// CHECK:STDERR: struct ForwardDeclaredStruct;
// CHECK:STDERR: ^
// CHECK:STDERR: fail_import_decl_value_param_type.carbon:[[@LINE-27]]:10: in file included here [InCppInclude]
// CHECK:STDERR: ./decl_value_param_type.h:4:32: note: initializing function parameter [InCallToFunctionParam]
// CHECK:STDERR: auto foo1(ForwardDeclaredStruct) -> void;
// CHECK:STDERR: ^
// CHECK:STDERR:
// CHECK:STDERR: fail_import_decl_value_param_type.carbon:[[@LINE+12]]:12: error: forming value of incomplete type `Cpp.ForwardDeclaredStruct` [IncompleteTypeInValueConversion]
// CHECK:STDERR: Cpp.foo2(*p);
// CHECK:STDERR: ^~
// CHECK:STDERR: fail_import_decl_value_param_type.carbon:[[@LINE-35]]:10: in file included here [InCppInclude]
// CHECK:STDERR: fail_import_decl_value_param_type.carbon:[[@LINE+5]]:12-13: error: forming value of incomplete type `Cpp.ForwardDeclaredStruct` [IncompleteTypeInValueConversion]
// CHECK:STDERR: included from: fail_import_decl_value_param_type.carbon:[[@LINE-17]]:10 [InCppInclude]
// CHECK:STDERR: ./decl_value_param_type.h:2:8: note: class was forward declared here [ClassForwardDeclaredHere]
// CHECK:STDERR: struct ForwardDeclaredStruct;
// CHECK:STDERR: ^
// CHECK:STDERR: fail_import_decl_value_param_type.carbon:[[@LINE-39]]:10: in file included here [InCppInclude]
// CHECK:STDERR: ./decl_value_param_type.h:5:32: note: initializing function parameter [InCallToFunctionParam]
// CHECK:STDERR: auto foo2(ForwardDeclaredStruct) -> void;
// CHECK:STDERR: ^
// CHECK:STDERR:
Cpp.foo2(*p);
}
@@ -118,25 +90,15 @@ auto foo_non_copyable(NonCopyableStruct) -> void;
library "[[@TEST_NAME]]";
// CHECK:STDERR: fail_import_non_copyable_param_type.carbon:[[@LINE+12]]:10: in file included here [InCppInclude]
// CHECK:STDERR: ./non_copyable_param_type.h:6:6: error: call to deleted constructor of 'NonCopyableStruct' [CppInteropParseError]
// CHECK:STDERR: 6 | auto foo_non_copyable(NonCopyableStruct) -> void;
// CHECK:STDERR: | ^~~~~~~~~~~~~~~~
// CHECK:STDERR: fail_import_non_copyable_param_type.carbon:[[@LINE+8]]:10: in file included here [InCppInclude]
// CHECK:STDERR: included from: fail_import_non_copyable_param_type.carbon:[[@LINE+4]]:10 [InCppInclude]
// CHECK:STDERR: ./non_copyable_param_type.h:6:6-21: error: call to deleted constructor of 'NonCopyableStruct' [CppInteropParseError]
// CHECK:STDERR: ./non_copyable_param_type.h:3:3: note: 'NonCopyableStruct' has been explicitly marked deleted here [CppInteropParseNote]
// CHECK:STDERR: 3 | NonCopyableStruct(const NonCopyableStruct&) = delete;
// CHECK:STDERR: | ^
// CHECK:STDERR: fail_import_non_copyable_param_type.carbon:[[@LINE+4]]:10: in file included here [InCppInclude]
// CHECK:STDERR: ./non_copyable_param_type.h:6:40: note: passing argument to parameter here [CppInteropParseNote]
// CHECK:STDERR: 6 | auto foo_non_copyable(NonCopyableStruct) -> void;
// CHECK:STDERR: | ^
import Cpp library "non_copyable_param_type.h";
fn F(s: Cpp.NonCopyableStruct) {
//@dump-sem-ir-begin
// CHECK:STDERR: fail_import_non_copyable_param_type.carbon:[[@LINE+4]]:3: note: in thunk for C++ function used here [InCppThunk]
// CHECK:STDERR: Cpp.foo_non_copyable(s);
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR: fail_import_non_copyable_param_type.carbon:[[@LINE+2]]:3-25: note: in thunk for C++ function used here [InCppThunk]
// CHECK:STDERR:
Cpp.foo_non_copyable(s);
//@dump-sem-ir-end
@@ -321,13 +283,9 @@ library "[[@TEST_NAME]]";
import Cpp library "incomplete.h";
fn F() {
// CHECK:STDERR: fail_import_incomplete.carbon:[[@LINE+8]]:3: error: member access into incomplete class `Cpp.IncompleteStruct` [QualifiedExprInIncompleteClassScope]
// CHECK:STDERR: Cpp.IncompleteStruct.foo();
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR: fail_import_incomplete.carbon:[[@LINE-6]]:10: in file included here [InCppInclude]
// CHECK:STDERR: fail_import_incomplete.carbon:[[@LINE+4]]:3-26: error: member access into incomplete class `Cpp.IncompleteStruct` [QualifiedExprInIncompleteClassScope]
// CHECK:STDERR: included from: fail_import_incomplete.carbon:[[@LINE-4]]:10 [InCppInclude]
// CHECK:STDERR: ./incomplete.h:2:8: note: class was forward declared here [ClassForwardDeclaredHere]
// CHECK:STDERR: struct IncompleteStruct;
// CHECK:STDERR: ^
// CHECK:STDERR:
Cpp.IncompleteStruct.foo();
}
@@ -391,36 +349,19 @@ auto foo_decl_value_return() -> DeclValueReturnStruct;
library "[[@TEST_NAME]]";
// TODO: We should only produce one error here.
// CHECK:STDERR: fail_import_decl_value_return_type.carbon:[[@LINE+12]]:10: in file included here [InCppInclude]
// CHECK:STDERR: ./decl_value_return_type.h:4:6: error: calling 'foo_decl_value_return' with incomplete return type 'DeclValueReturnStruct' [CppInteropParseError]
// CHECK:STDERR: 4 | auto foo_decl_value_return() -> DeclValueReturnStruct;
// CHECK:STDERR: | ^~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR: fail_import_decl_value_return_type.carbon:[[@LINE+8]]:10: in file included here [InCppInclude]
// CHECK:STDERR: included from: fail_import_decl_value_return_type.carbon:[[@LINE+4]]:10 [InCppInclude]
// CHECK:STDERR: ./decl_value_return_type.h:4:6-26: error: calling 'foo_decl_value_return' with incomplete return type 'DeclValueReturnStruct' [CppInteropParseError]
// CHECK:STDERR: ./decl_value_return_type.h:4:6: note: 'foo_decl_value_return' declared here [CppInteropParseNote]
// CHECK:STDERR: 4 | auto foo_decl_value_return() -> DeclValueReturnStruct;
// CHECK:STDERR: | ^
// CHECK:STDERR: fail_import_decl_value_return_type.carbon:[[@LINE+4]]:10: in file included here [InCppInclude]
// CHECK:STDERR: ./decl_value_return_type.h:2:8: note: forward declaration of 'DeclValueReturnStruct' [CppInteropParseNote]
// CHECK:STDERR: 2 | struct DeclValueReturnStruct;
// CHECK:STDERR: | ^
import Cpp library "decl_value_return_type.h";
fn F() {
// CHECK:STDERR: fail_import_decl_value_return_type.carbon:[[@LINE+16]]:3: note: in thunk for C++ function used here [InCppThunk]
// CHECK:STDERR: Cpp.foo_decl_value_return();
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR: fail_import_decl_value_return_type.carbon:[[@LINE+7]]:3-29: note: in thunk for C++ function used here [InCppThunk]
// CHECK:STDERR:
// CHECK:STDERR: fail_import_decl_value_return_type.carbon:[[@LINE+12]]:3: error: function returns incomplete type `Cpp.DeclValueReturnStruct` [IncompleteTypeInFunctionReturnType]
// CHECK:STDERR: Cpp.foo_decl_value_return();
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR: fail_import_decl_value_return_type.carbon:[[@LINE-10]]:10: in file included here [InCppInclude]
// CHECK:STDERR: fail_import_decl_value_return_type.carbon:[[@LINE+5]]:3-29: error: function returns incomplete type `Cpp.DeclValueReturnStruct` [IncompleteTypeInFunctionReturnType]
// CHECK:STDERR: included from: fail_import_decl_value_return_type.carbon:[[@LINE-6]]:10 [InCppInclude]
// CHECK:STDERR: ./decl_value_return_type.h:2:8: note: class was forward declared here [ClassForwardDeclaredHere]
// CHECK:STDERR: struct DeclValueReturnStruct;
// CHECK:STDERR: ^
// CHECK:STDERR: fail_import_decl_value_return_type.carbon:[[@LINE-14]]:10: in file included here [InCppInclude]
// CHECK:STDERR: ./decl_value_return_type.h:4:33: note: return type declared here [IncompleteReturnTypeHere]
// CHECK:STDERR: auto foo_decl_value_return() -> DeclValueReturnStruct;
// CHECK:STDERR: ^
// CHECK:STDERR:
Cpp.foo_decl_value_return();
}
@@ -559,7 +500,7 @@ fn F() {
// CHECK:STDOUT:
// CHECK:STDOUT: fn @F(%s.param: %NonCopyableStruct) {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %Cpp.ref.loc24: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
// CHECK:STDOUT: %Cpp.ref.loc14: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
// CHECK:STDOUT: %foo_non_copyable.ref: %foo_non_copyable.cpp_overload_set.type = name_ref foo_non_copyable, imports.%foo_non_copyable.cpp_overload_set.value [concrete = constants.%foo_non_copyable.cpp_overload_set.value]
// CHECK:STDOUT: %s.ref: %NonCopyableStruct = name_ref s, %s
// CHECK:STDOUT: %foo_non_copyable.call: init %empty_tuple.type = call imports.%foo_non_copyable.decl(%s.ref)