Improve mapping of Clang diagnostics into Carbon diagnostics (#5894)

Instead of taking the complete text of the Clang diagnostic and using it
as the message portion of a Carbon diagnostic, generate the individual
pieces separately and pass them into the Carbon diagnostic
infrastructure.

* Clang's context lines are generated by running a custom "diagnostic
renderer" and tracking which lines it wants to print as context for a
given source location. When mapping from a C++ source location back to a
Carbon location, the Carbon `Loc` structure is now fully populated,
including filling in the context line and the column number.
* Clang's snippet is generated by running a custom diagnostic renderer
that is a cut-down version of the full text diagnostic renderer that
only prints a snippet. This is then attached to the Carbon diagnostic
manually as an override for the snippet we'd usually create.

We no longer repeat the file location twice on each diagnostic, and no
longer produce a bogus "in import" line for all locations coming from
clang that point arbitrarily to the first C++ import in the Carbon file.
The `[diagnostic kind]` marker is now displayed at the end of the
diagnostic message, not on a line of its own after the snippet.
This commit is contained in:
Richard Smith
2025-08-01 01:24:31 +00:00
committed by GitHub
parent b320ea77ec
commit 25681901bd
24 changed files with 581 additions and 322 deletions
+10 -6
View File
@@ -50,11 +50,13 @@ library "[[@TEST_NAME]]";
import Cpp library "non_function_member_protected.h";
fn F(c: Cpp.C) {
// CHECK:STDERR: fail_import_non_function_member_protected.carbon:[[@LINE+6]]:16: error: cannot access protected member `x` of type `Cpp.C` [ClassInvalidMemberAccess]
// CHECK:STDERR: fail_import_non_function_member_protected.carbon:[[@LINE+8]]:16: error: cannot access protected member `x` of type `Cpp.C` [ClassInvalidMemberAccess]
// CHECK:STDERR: let x: i32 = c.x;
// CHECK:STDERR: ^~~
// CHECK:STDERR: fail_import_non_function_member_protected.carbon:[[@LINE-6]]:1: in import [InImport]
// CHECK:STDERR: ./non_function_member_protected.h:2: note: declared here [ClassMemberDeclaration]
// CHECK:STDERR: fail_import_non_function_member_protected.carbon:[[@LINE-6]]:10: in file included here [InCppInclude]
// CHECK:STDERR: ./non_function_member_protected.h:2:7: note: declared here [ClassMemberDeclaration]
// CHECK:STDERR: class C {
// CHECK:STDERR: ^
// CHECK:STDERR:
let x: i32 = c.x;
}
@@ -76,11 +78,13 @@ library "[[@TEST_NAME]]";
import Cpp library "non_function_member_private.h";
fn F(c: Cpp.C) {
// CHECK:STDERR: fail_import_non_function_member_private.carbon:[[@LINE+6]]:16: error: cannot access private member `x` of type `Cpp.C` [ClassInvalidMemberAccess]
// CHECK:STDERR: fail_import_non_function_member_private.carbon:[[@LINE+8]]:16: error: cannot access private member `x` of type `Cpp.C` [ClassInvalidMemberAccess]
// CHECK:STDERR: let x: i32 = c.x;
// CHECK:STDERR: ^~~
// CHECK:STDERR: fail_import_non_function_member_private.carbon:[[@LINE-6]]:1: in import [InImport]
// CHECK:STDERR: ./non_function_member_private.h:2: note: declared here [ClassMemberDeclaration]
// CHECK:STDERR: fail_import_non_function_member_private.carbon:[[@LINE-6]]:10: in file included here [InCppInclude]
// CHECK:STDERR: ./non_function_member_private.h:2:7: note: declared here [ClassMemberDeclaration]
// CHECK:STDERR: class C {
// CHECK:STDERR: ^
// CHECK:STDERR:
let x: i32 = c.x;
}
+5 -3
View File
@@ -35,11 +35,13 @@ library "[[@TEST_NAME]]";
import Cpp library "declaration.h";
fn MyF() {
// CHECK:STDERR: fail_use_declaration_as_definition.carbon:[[@LINE+6]]:12: error: binding pattern has incomplete type `Bar` in name binding declaration [IncompleteTypeInBindingDecl]
// CHECK:STDERR: fail_use_declaration_as_definition.carbon:[[@LINE+8]]:12: error: binding pattern has incomplete type `Bar` in name binding declaration [IncompleteTypeInBindingDecl]
// CHECK:STDERR: var bar: Cpp.Bar;
// CHECK:STDERR: ^~~~~~~
// CHECK:STDERR: fail_use_declaration_as_definition.carbon:[[@LINE-6]]:1: in import [InImport]
// CHECK:STDERR: ./declaration.h:2: note: class was forward declared here [ClassForwardDeclaredHere]
// CHECK:STDERR: fail_use_declaration_as_definition.carbon:[[@LINE-6]]:10: in file included here [InCppInclude]
// CHECK:STDERR: ./declaration.h:2:7: note: class was forward declared here [ClassForwardDeclaredHere]
// CHECK:STDERR: class Bar;
// CHECK:STDERR: ^
// CHECK:STDERR:
var bar: Cpp.Bar;
}
+5 -3
View File
@@ -35,11 +35,13 @@ library "[[@TEST_NAME]]";
import Cpp library "declaration.h";
fn MyF() {
// CHECK:STDERR: fail_use_declaration_as_definition.carbon:[[@LINE+6]]:12: error: binding pattern has incomplete type `Bar` in name binding declaration [IncompleteTypeInBindingDecl]
// CHECK:STDERR: fail_use_declaration_as_definition.carbon:[[@LINE+8]]:12: error: binding pattern has incomplete type `Bar` in name binding declaration [IncompleteTypeInBindingDecl]
// CHECK:STDERR: var bar: Cpp.Bar;
// CHECK:STDERR: ^~~~~~~
// CHECK:STDERR: fail_use_declaration_as_definition.carbon:[[@LINE-6]]:1: in import [InImport]
// CHECK:STDERR: ./declaration.h:2: note: class was forward declared here [ClassForwardDeclaredHere]
// CHECK:STDERR: fail_use_declaration_as_definition.carbon:[[@LINE-6]]:10: in file included here [InCppInclude]
// CHECK:STDERR: ./declaration.h:2:8: note: class was forward declared here [ClassForwardDeclaredHere]
// CHECK:STDERR: struct Bar;
// CHECK:STDERR: ^
// CHECK:STDERR:
var bar: Cpp.Bar;
}
+26 -29
View File
@@ -60,17 +60,14 @@ using Xint = X<int>;
library "[[@TEST_NAME]]";
// CHECK:STDERR: fail_use_instantiation_error.carbon:[[@LINE+11]]:1: in import [InImport]
// CHECK:STDERR: ./instantiation_error.h:3: error: In file included from fail_use_instantiation_error.carbon:[[@LINE+10]]:
// CHECK:STDERR: ./instantiation_error.h:3:25: error: type 'int' cannot be used prior to '::' because it has no members
// CHECK:STDERR: fail_use_instantiation_error.carbon:[[@LINE+8]]:10: in file included here [InCppInclude]
// CHECK:STDERR: ./instantiation_error.h:3:25: error: type 'int' cannot be used prior to '::' because it has no members [CppInteropParseError]
// CHECK:STDERR: 3 | using type = typename T::member;
// CHECK:STDERR: | ^
// CHECK:STDERR: [CppInteropParseError]
// CHECK:STDERR: fail_use_instantiation_error.carbon:[[@LINE+5]]:1: in import [InImport]
// CHECK:STDERR: ./instantiation_error.h:2: note: ./instantiation_error.h:2:29: note: in instantiation of template class 'X<int>' requested here
// CHECK:STDERR: fail_use_instantiation_error.carbon:[[@LINE+4]]:10: in file included here [InCppInclude]
// CHECK:STDERR: ./instantiation_error.h:2:29: note: in instantiation of template class 'X<int>' requested here [CppInteropParseNote]
// CHECK:STDERR: 2 | template<typename T> struct X {
// CHECK:STDERR: | ^
// CHECK:STDERR: [CppInteropParseNote]
import Cpp library "instantiation_error.h";
//@dump-sem-ir-begin
@@ -173,11 +170,11 @@ var y: Cpp.Xint.r#type = 0;
// CHECK:STDOUT: %x.var_patt: %pattern_type.7ce = var_pattern %x.patt [concrete]
// CHECK:STDOUT: }
// CHECK:STDOUT: %x.var: ref %i32 = var %x.var_patt [concrete]
// CHECK:STDOUT: %.loc18: type = splice_block %type.ref.loc18 [concrete = constants.%i32] {
// CHECK:STDOUT: %Cpp.ref.loc18: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
// CHECK:STDOUT: %.loc15: type = splice_block %type.ref.loc15 [concrete = constants.%i32] {
// CHECK:STDOUT: %Cpp.ref.loc15: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
// CHECK:STDOUT: %XY.ref: type = name_ref XY, imports.%X.decl.dec4cb.1 [concrete = constants.%X.32d59e.1]
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: %type.ref.loc18: type = name_ref r#type, %i32.2 [concrete = constants.%i32]
// CHECK:STDOUT: %type.ref.loc15: type = name_ref r#type, %i32.2 [concrete = constants.%i32]
// CHECK:STDOUT: }
// CHECK:STDOUT: %x: ref %i32 = bind_name x, %x.var [concrete = %x.var]
// CHECK:STDOUT: name_binding_decl {
@@ -185,33 +182,33 @@ var y: Cpp.Xint.r#type = 0;
// CHECK:STDOUT: %y.var_patt: %pattern_type.7ce = var_pattern %y.patt [concrete]
// CHECK:STDOUT: }
// CHECK:STDOUT: %y.var: ref %i32 = var %y.var_patt [concrete]
// CHECK:STDOUT: %.loc24: type = splice_block %type.ref.loc24 [concrete = constants.%i32] {
// CHECK:STDOUT: %Cpp.ref.loc24: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
// CHECK:STDOUT: %.loc21: type = splice_block %type.ref.loc21 [concrete = constants.%i32] {
// CHECK:STDOUT: %Cpp.ref.loc21: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
// CHECK:STDOUT: %Xint.ref: type = name_ref Xint, imports.%X.decl.dec4cb.2 [concrete = constants.%X.32d59e.2]
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: %type.ref.loc24: type = name_ref r#type, %i32.1 [concrete = constants.%i32]
// CHECK:STDOUT: %type.ref.loc21: type = name_ref r#type, %i32.1 [concrete = constants.%i32]
// CHECK:STDOUT: }
// CHECK:STDOUT: %y: ref %i32 = bind_name y, %y.var [concrete = %y.var]
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: fn @__global_init() {
// CHECK:STDOUT: !entry:
// CHECK:STDOUT: %int_0.loc18: Core.IntLiteral = int_value 0 [concrete = constants.%int_0.5c6]
// CHECK:STDOUT: %impl.elem0.loc18: %.9c3 = impl_witness_access constants.%ImplicitAs.impl_witness.c75, element0 [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.956]
// CHECK:STDOUT: %bound_method.loc18_1.1: <bound method> = bound_method %int_0.loc18, %impl.elem0.loc18 [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.bound]
// CHECK:STDOUT: %specific_fn.loc18: <specific function> = specific_function %impl.elem0.loc18, @Core.IntLiteral.as.ImplicitAs.impl.Convert(constants.%int_32) [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn]
// CHECK:STDOUT: %bound_method.loc18_1.2: <bound method> = bound_method %int_0.loc18, %specific_fn.loc18 [concrete = constants.%bound_method]
// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.call.loc18: init %i32 = call %bound_method.loc18_1.2(%int_0.loc18) [concrete = constants.%int_0.6a9]
// CHECK:STDOUT: %.loc18: init %i32 = converted %int_0.loc18, %Core.IntLiteral.as.ImplicitAs.impl.Convert.call.loc18 [concrete = constants.%int_0.6a9]
// CHECK:STDOUT: assign file.%x.var, %.loc18
// CHECK:STDOUT: %int_0.loc24: Core.IntLiteral = int_value 0 [concrete = constants.%int_0.5c6]
// CHECK:STDOUT: %impl.elem0.loc24: %.9c3 = impl_witness_access constants.%ImplicitAs.impl_witness.c75, element0 [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.956]
// CHECK:STDOUT: %bound_method.loc24_1.1: <bound method> = bound_method %int_0.loc24, %impl.elem0.loc24 [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.bound]
// CHECK:STDOUT: %specific_fn.loc24: <specific function> = specific_function %impl.elem0.loc24, @Core.IntLiteral.as.ImplicitAs.impl.Convert(constants.%int_32) [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn]
// CHECK:STDOUT: %bound_method.loc24_1.2: <bound method> = bound_method %int_0.loc24, %specific_fn.loc24 [concrete = constants.%bound_method]
// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.call.loc24: init %i32 = call %bound_method.loc24_1.2(%int_0.loc24) [concrete = constants.%int_0.6a9]
// CHECK:STDOUT: %.loc24: init %i32 = converted %int_0.loc24, %Core.IntLiteral.as.ImplicitAs.impl.Convert.call.loc24 [concrete = constants.%int_0.6a9]
// CHECK:STDOUT: assign file.%y.var, %.loc24
// CHECK:STDOUT: %int_0.loc15: Core.IntLiteral = int_value 0 [concrete = constants.%int_0.5c6]
// CHECK:STDOUT: %impl.elem0.loc15: %.9c3 = impl_witness_access constants.%ImplicitAs.impl_witness.c75, element0 [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.956]
// CHECK:STDOUT: %bound_method.loc15_1.1: <bound method> = bound_method %int_0.loc15, %impl.elem0.loc15 [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.bound]
// CHECK:STDOUT: %specific_fn.loc15: <specific function> = specific_function %impl.elem0.loc15, @Core.IntLiteral.as.ImplicitAs.impl.Convert(constants.%int_32) [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn]
// CHECK:STDOUT: %bound_method.loc15_1.2: <bound method> = bound_method %int_0.loc15, %specific_fn.loc15 [concrete = constants.%bound_method]
// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.call.loc15: init %i32 = call %bound_method.loc15_1.2(%int_0.loc15) [concrete = constants.%int_0.6a9]
// CHECK:STDOUT: %.loc15: init %i32 = converted %int_0.loc15, %Core.IntLiteral.as.ImplicitAs.impl.Convert.call.loc15 [concrete = constants.%int_0.6a9]
// CHECK:STDOUT: assign file.%x.var, %.loc15
// CHECK:STDOUT: %int_0.loc21: Core.IntLiteral = int_value 0 [concrete = constants.%int_0.5c6]
// CHECK:STDOUT: %impl.elem0.loc21: %.9c3 = impl_witness_access constants.%ImplicitAs.impl_witness.c75, element0 [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.956]
// CHECK:STDOUT: %bound_method.loc21_1.1: <bound method> = bound_method %int_0.loc21, %impl.elem0.loc21 [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.bound]
// CHECK:STDOUT: %specific_fn.loc21: <specific function> = specific_function %impl.elem0.loc21, @Core.IntLiteral.as.ImplicitAs.impl.Convert(constants.%int_32) [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn]
// CHECK:STDOUT: %bound_method.loc21_1.2: <bound method> = bound_method %int_0.loc21, %specific_fn.loc21 [concrete = constants.%bound_method]
// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.call.loc21: init %i32 = call %bound_method.loc21_1.2(%int_0.loc21) [concrete = constants.%int_0.6a9]
// CHECK:STDOUT: %.loc21: init %i32 = converted %int_0.loc21, %Core.IntLiteral.as.ImplicitAs.impl.Convert.call.loc21 [concrete = constants.%int_0.6a9]
// CHECK:STDOUT: assign file.%y.var, %.loc21
// CHECK:STDOUT: <elided>
// CHECK:STDOUT: }
// CHECK:STDOUT:
+5 -3
View File
@@ -35,11 +35,13 @@ library "[[@TEST_NAME]]";
import Cpp library "declaration.h";
fn MyF() {
// CHECK:STDERR: fail_use_declaration_as_definition.carbon:[[@LINE+6]]:12: error: binding pattern has incomplete type `Bar` in name binding declaration [IncompleteTypeInBindingDecl]
// CHECK:STDERR: fail_use_declaration_as_definition.carbon:[[@LINE+8]]:12: error: binding pattern has incomplete type `Bar` in name binding declaration [IncompleteTypeInBindingDecl]
// CHECK:STDERR: var bar: Cpp.Bar;
// CHECK:STDERR: ^~~~~~~
// CHECK:STDERR: fail_use_declaration_as_definition.carbon:[[@LINE-6]]:1: in import [InImport]
// CHECK:STDERR: ./declaration.h:2: note: class was forward declared here [ClassForwardDeclaredHere]
// CHECK:STDERR: fail_use_declaration_as_definition.carbon:[[@LINE-6]]:10: in file included here [InCppInclude]
// CHECK:STDERR: ./declaration.h:2:7: note: class was forward declared here [ClassForwardDeclaredHere]
// CHECK:STDERR: union Bar;
// CHECK:STDERR: ^
// CHECK:STDERR:
var bar: Cpp.Bar;
}