diff --git a/toolchain/check/diagnostic_emitter.cpp b/toolchain/check/diagnostic_emitter.cpp index 7c93d5bd5786..4b968434676d 100644 --- a/toolchain/check/diagnostic_emitter.cpp +++ b/toolchain/check/diagnostic_emitter.cpp @@ -11,6 +11,7 @@ #include "common/raw_string_ostream.h" #include "toolchain/check/diagnostic_helpers.h" #include "toolchain/sem_ir/absolute_node_id.h" +#include "toolchain/sem_ir/diagnostic_loc_converter.h" #include "toolchain/sem_ir/ids.h" #include "toolchain/sem_ir/stringify.h" @@ -23,7 +24,28 @@ auto DiagnosticEmitter::ConvertLoc(LocIdForDiagnostics loc_id, loc_id.loc_id(), loc_id.is_token_only()); for (const auto& import : imports) { CARBON_DIAGNOSTIC(InImport, LocationInfo, "in import"); - context_fn(import.loc, InImport); + CARBON_DIAGNOSTIC(InCppInclude, LocationInfo, "in file included here"); + CARBON_DIAGNOSTIC(InCppModule, LocationInfo, "in module imported here"); + CARBON_DIAGNOSTIC(InCppMacroExpansion, LocationInfo, + "in expansion of macro defined here"); + switch (import.kind) { + case Carbon::SemIR::DiagnosticLocConverter::ImportLoc::Import: + // TODO: Include the library name in the note. + context_fn(import.loc, InImport); + break; + case Carbon::SemIR::DiagnosticLocConverter::ImportLoc::CppInclude: + // TODO: Include the file name in the note. + context_fn(import.loc, InCppInclude); + break; + case Carbon::SemIR::DiagnosticLocConverter::ImportLoc::CppModuleImport: + // TODO: Include the module name in the note. + context_fn(import.loc, InCppModule); + break; + case Carbon::SemIR::DiagnosticLocConverter::ImportLoc::CppMacroExpansion: + // TODO: Include the macro name in the note. + context_fn(import.loc, InCppMacroExpansion); + break; + } } // Use the token when possible, but -1 is the default value. diff --git a/toolchain/check/import_cpp.cpp b/toolchain/check/import_cpp.cpp index b3d9070d72c0..d155fb71780f 100644 --- a/toolchain/check/import_cpp.cpp +++ b/toolchain/check/import_cpp.cpp @@ -141,32 +141,26 @@ class CarbonClangDiagnosticConsumer : public clang::DiagnosticConsumer { llvm::SmallString<256> message; info.FormatDiagnostic(message); + // Render a code snippet including any highlighted ranges and fixit hints. + // TODO: Also include the #include stack and macro expansion stack in the + // diagnostic output in some way. + RawStringOstream snippet_stream; if (!info.hasSourceManager()) { - // If we don't have a source manager, we haven't actually started - // compiling yet, and this is an error from the driver or early in the - // frontend. Pass it on directly. + // If we don't have a source manager, this is an error from early in the + // frontend. Don't produce a snippet. CARBON_CHECK(info.getLocation().isInvalid()); - diagnostic_infos_.push_back({.level = diag_level, - .import_ir_inst_id = clang_import_ir_inst_id, - .message = message.str().str()}); - return; + } else { + CodeContextRenderer(snippet_stream, invocation_->getLangOpts(), + invocation_->getDiagnosticOpts()) + .emitDiagnostic( + clang::FullSourceLoc(info.getLocation(), info.getSourceManager()), + diag_level, message, info.getRanges(), info.getFixItHints()); } - // TODO: This includes the full clang diagnostic, including the source - // location, resulting in the location appearing twice in the output. - RawStringOstream diagnostics_stream; - clang::TextDiagnostic text_diagnostic(diagnostics_stream, - invocation_->getLangOpts(), - invocation_->getDiagnosticOpts()); - text_diagnostic.emitDiagnostic( - clang::FullSourceLoc(info.getLocation(), info.getSourceManager()), - diag_level, message, info.getRanges(), info.getFixItHints()); - - std::string diagnostics_str = diagnostics_stream.TakeStr(); - diagnostic_infos_.push_back({.level = diag_level, .import_ir_inst_id = clang_import_ir_inst_id, - .message = diagnostics_str}); + .message = message.str().str(), + .snippet = snippet_stream.TakeStr()}); } // Outputs Carbon diagnostics based on the collected Clang diagnostics. Must @@ -200,15 +194,22 @@ class CarbonClangDiagnosticConsumer : public clang::DiagnosticConsumer { ? CppInteropParseWarning : CppInteropParseError, info.message); + builder.OverrideSnippet(info.snippet); for (; i + 1 < diagnostic_infos_.size() && diagnostic_infos_[i + 1].level == clang::DiagnosticsEngine::Note; ++i) { const ClangDiagnosticInfo& note_info = diagnostic_infos_[i + 1]; CARBON_DIAGNOSTIC(CppInteropParseNote, Note, "{0}", std::string); - builder.Note(SemIR::LocId(note_info.import_ir_inst_id), - CppInteropParseNote, note_info.message); + builder + .Note(SemIR::LocId(note_info.import_ir_inst_id), + CppInteropParseNote, note_info.message) + .OverrideSnippet(note_info.snippet); } + // TODO: This will apply all current Carbon annotation functions. We + // should instead track how Clang's context notes and Carbon's + // annotation functions are interleaved, and interleave the notes in + // the same order. builder.Emit(); break; } @@ -218,11 +219,36 @@ class CarbonClangDiagnosticConsumer : public clang::DiagnosticConsumer { } private: - // The type-checking context in which we're running Clang. - Context* context_; + // A diagnostics renderer based on clang's TextDiagnostic that captures just + // the code context (the snippet). + class CodeContextRenderer : public clang::TextDiagnostic { + public: + using TextDiagnostic::TextDiagnostic; - // The compiler invocation that is producing the diagnostics. - std::shared_ptr invocation_; + void emitDiagnosticMessage( + clang::FullSourceLoc /*loc*/, clang::PresumedLoc /*ploc*/, + clang::DiagnosticsEngine::Level /*level*/, llvm::StringRef /*message*/, + llvm::ArrayRef /*ranges*/, + clang::DiagOrStoredDiag /*info*/) override {} + void emitDiagnosticLoc( + clang::FullSourceLoc /*loc*/, clang::PresumedLoc /*ploc*/, + clang::DiagnosticsEngine::Level /*level*/, + llvm::ArrayRef /*ranges*/) override {} + + // emitCodeContext is inherited from clang::TextDiagnostic. + + void emitIncludeLocation(clang::FullSourceLoc /*loc*/, + clang::PresumedLoc /*ploc*/) override {} + void emitImportLocation(clang::FullSourceLoc /*loc*/, + clang::PresumedLoc /*ploc*/, + llvm::StringRef /*module_name*/) override {} + void emitBuildingModuleLocation(clang::FullSourceLoc /*loc*/, + clang::PresumedLoc /*ploc*/, + llvm::StringRef /*module_name*/) override {} + + // beginDiagnostic and endDiagnostic are inherited from + // clang::TextDiagnostic in case it wants to do any setup / teardown work. + }; // Information on a Clang diagnostic that can be converted to a Carbon // diagnostic. @@ -236,25 +262,56 @@ class CarbonClangDiagnosticConsumer : public clang::DiagnosticConsumer { // The Clang diagnostic textual message. std::string message; + + // The code snippet produced by clang. + std::string snippet; }; + // The type-checking context in which we're running Clang. + Context* context_; + + // The compiler invocation that is producing the diagnostics. + std::shared_ptr invocation_; + // Collects the information for all Clang diagnostics to be converted to // Carbon diagnostics after the context has been initialized with the Clang // AST. llvm::SmallVector diagnostic_infos_; }; +// A wrapper around a clang::CompilerInvocation that allows us to make a shallow +// copy of most of the invocation and only make a deep copy of the parts that we +// want to change. +// +// clang::CowCompilerInvocation almost allows this, but doesn't derive from +// CompilerInvocation or support shallow copies from a CompilerInvocation, so is +// not useful to us as we can't build an ASTUnit from it. +class ShallowCopyCompilerInvocation : public clang::CompilerInvocation { + public: + explicit ShallowCopyCompilerInvocation( + const clang::CompilerInvocation& invocation) { + shallow_copy_assign(invocation); + + // The preprocessor options are modified to hold a replacement includes + // buffer, so make our own version of those options. + PPOpts = std::make_shared(*PPOpts); + } +}; + } // namespace // Returns an AST for the C++ imports and a bool that represents whether // compilation errors where encountered or the generated AST is null due to an // error. Sets the AST in the context's `sem_ir`. // TODO: Consider to always have a (non-null) AST. -static auto GenerateAst(Context& context, - llvm::ArrayRef imports, - llvm::IntrusiveRefCntPtr fs, - std::shared_ptr invocation) +static auto GenerateAst( + Context& context, llvm::ArrayRef imports, + llvm::IntrusiveRefCntPtr fs, + std::shared_ptr base_invocation) -> std::pair, bool> { + auto invocation = + std::make_shared(*base_invocation); + // Build a diagnostics engine. llvm::IntrusiveRefCntPtr diags( clang::CompilerInstance::createDiagnostics( @@ -274,9 +331,10 @@ static auto GenerateAst(Context& context, // TODO: Modify the frontend options to specify this memory buffer as input // instead of remapping the file. std::string includes = GenerateCppIncludesHeaderCode(context, imports); - auto includes_buffer = llvm::MemoryBuffer::getMemBuffer(includes, file_name); + auto includes_buffer = + llvm::MemoryBuffer::getMemBufferCopy(includes, file_name); invocation->getPreprocessorOpts().addRemappedFile(file_name, - includes_buffer.get()); + includes_buffer.release()); clang::DiagnosticErrorTrap trap(*diags); @@ -285,9 +343,6 @@ static auto GenerateAst(Context& context, invocation, std::make_shared(), nullptr, diags, new clang::FileManager(invocation->getFileSystemOpts(), fs)); - // Remove remapped file before its underlying storage is destroyed. - invocation->getPreprocessorOpts().clearRemappedFiles(); - // Attach the AST to SemIR. This needs to be done before we can emit any // diagnostics, so their locations can be properly interpreted by our // diagnostics machinery. @@ -377,6 +432,9 @@ static auto ClangLookup(Context& context, SemIR::NameScopeId scope_id, CARBON_CHECK(ast); clang::Sema& sema = ast->getSema(); + // TODO: Map the LocId of the lookup to a clang SourceLocation and provide it + // here so that clang's diagnostics can point into the carbon code that uses + // the name. clang::LookupResult lookup( sema, clang::DeclarationNameInfo( diff --git a/toolchain/check/testdata/interop/cpp/bad_import.carbon b/toolchain/check/testdata/interop/cpp/bad_import.carbon index 54df4d287b37..cc1df7c6811a 100644 --- a/toolchain/check/testdata/interop/cpp/bad_import.carbon +++ b/toolchain/check/testdata/interop/cpp/bad_import.carbon @@ -34,10 +34,8 @@ import Cpp library ""; library "[[@TEST_NAME]]"; -// CHECK:STDERR: fail_import_cpp_library_file_with_quotes.carbon:[[@LINE+6]]:1: in import [InImport] -// CHECK:STDERR: fail_import_cpp_library_file_with_quotes.carbon:[[@LINE+5]]: error: fail_import_cpp_library_file_with_quotes.carbon:[[@LINE+5]]:10: fatal error: '\"foo.h\"' file not found -// CHECK:STDERR: 10 | #include "\"foo.h\"" +// CHECK:STDERR: fail_import_cpp_library_file_with_quotes.carbon:[[@LINE+4]]:10: error: '\"foo.h\"' file not found [CppInteropParseError] +// CHECK:STDERR: 8 | #include "\"foo.h\"" // CHECK:STDERR: | ^~~~~~~~~~~ -// CHECK:STDERR: [CppInteropParseError] // CHECK:STDERR: import Cpp library "\"foo.h\""; diff --git a/toolchain/check/testdata/interop/cpp/class/access.carbon b/toolchain/check/testdata/interop/cpp/class/access.carbon index 186d58c46f99..ccfecbd5bef0 100644 --- a/toolchain/check/testdata/interop/cpp/class/access.carbon +++ b/toolchain/check/testdata/interop/cpp/class/access.carbon @@ -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; } diff --git a/toolchain/check/testdata/interop/cpp/class/class.carbon b/toolchain/check/testdata/interop/cpp/class/class.carbon index 208202f781bd..31a7a132985d 100644 --- a/toolchain/check/testdata/interop/cpp/class/class.carbon +++ b/toolchain/check/testdata/interop/cpp/class/class.carbon @@ -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; } diff --git a/toolchain/check/testdata/interop/cpp/class/struct.carbon b/toolchain/check/testdata/interop/cpp/class/struct.carbon index 4e36b3fda27c..71674258255c 100644 --- a/toolchain/check/testdata/interop/cpp/class/struct.carbon +++ b/toolchain/check/testdata/interop/cpp/class/struct.carbon @@ -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; } diff --git a/toolchain/check/testdata/interop/cpp/class/template.carbon b/toolchain/check/testdata/interop/cpp/class/template.carbon index 567a6b47d436..69d5725ac59a 100644 --- a/toolchain/check/testdata/interop/cpp/class/template.carbon +++ b/toolchain/check/testdata/interop/cpp/class/template.carbon @@ -60,17 +60,14 @@ using Xint = X; 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' 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' requested here [CppInteropParseNote] // CHECK:STDERR: 2 | template 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: = 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: = 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: -// 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: = 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: = 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: -// 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 %int_0.loc18, %impl.elem0.loc18 [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.bound] -// CHECK:STDOUT: %specific_fn.loc18: = 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 %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 %int_0.loc24, %impl.elem0.loc24 [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.bound] -// CHECK:STDOUT: %specific_fn.loc24: = 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 %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 %int_0.loc15, %impl.elem0.loc15 [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.bound] +// CHECK:STDOUT: %specific_fn.loc15: = 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 %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 %int_0.loc21, %impl.elem0.loc21 [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.bound] +// CHECK:STDOUT: %specific_fn.loc21: = 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 %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: // CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/check/testdata/interop/cpp/class/union.carbon b/toolchain/check/testdata/interop/cpp/class/union.carbon index 89f811d60f30..95c0affd6698 100644 --- a/toolchain/check/testdata/interop/cpp/class/union.carbon +++ b/toolchain/check/testdata/interop/cpp/class/union.carbon @@ -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; } diff --git a/toolchain/check/testdata/interop/cpp/cpp_diagnostics.carbon b/toolchain/check/testdata/interop/cpp/cpp_diagnostics.carbon index ad36155d9597..da199c832707 100644 --- a/toolchain/check/testdata/interop/cpp/cpp_diagnostics.carbon +++ b/toolchain/check/testdata/interop/cpp/cpp_diagnostics.carbon @@ -22,12 +22,10 @@ library "[[@TEST_NAME]]"; -// CHECK:STDERR: fail_import_cpp_file_with_one_error.carbon:[[@LINE+7]]:1: in import [InImport] -// CHECK:STDERR: ./one_error.h:2: error: In file included from fail_import_cpp_file_with_one_error.carbon:[[@LINE+6]]: -// CHECK:STDERR: ./one_error.h:2:2: error: "error1" +// CHECK:STDERR: fail_import_cpp_file_with_one_error.carbon:[[@LINE+5]]:10: in file included here [InCppInclude] +// CHECK:STDERR: ./one_error.h:2:2: error: "error1" [CppInteropParseError] // CHECK:STDERR: 2 | #error "error1" // CHECK:STDERR: | ^ -// CHECK:STDERR: [CppInteropParseError] // CHECK:STDERR: import Cpp library "one_error.h"; @@ -44,19 +42,15 @@ import Cpp library "one_error.h"; library "[[@TEST_NAME]]"; -// CHECK:STDERR: fail_import_cpp_file_with_multiple_errors.carbon:[[@LINE+14]]:1: in import [InImport] -// CHECK:STDERR: ./multiple_errors.h:2: error: In file included from fail_import_cpp_file_with_multiple_errors.carbon:[[@LINE+13]]: -// CHECK:STDERR: ./multiple_errors.h:2:2: error: "error1" +// CHECK:STDERR: fail_import_cpp_file_with_multiple_errors.carbon:[[@LINE+10]]:10: in file included here [InCppInclude] +// CHECK:STDERR: ./multiple_errors.h:2:2: error: "error1" [CppInteropParseError] // CHECK:STDERR: 2 | #error "error1" // CHECK:STDERR: | ^ -// CHECK:STDERR: [CppInteropParseError] // CHECK:STDERR: -// CHECK:STDERR: fail_import_cpp_file_with_multiple_errors.carbon:[[@LINE+7]]:1: in import [InImport] -// CHECK:STDERR: ./multiple_errors.h:3: error: In file included from fail_import_cpp_file_with_multiple_errors.carbon:[[@LINE+6]]: -// CHECK:STDERR: ./multiple_errors.h:3:2: error: "error2" +// CHECK:STDERR: fail_import_cpp_file_with_multiple_errors.carbon:[[@LINE+5]]:10: in file included here [InCppInclude] +// CHECK:STDERR: ./multiple_errors.h:3:2: error: "error2" [CppInteropParseError] // CHECK:STDERR: 3 | #error "error2" // CHECK:STDERR: | ^ -// CHECK:STDERR: [CppInteropParseError] // CHECK:STDERR: import Cpp library "multiple_errors.h"; @@ -73,12 +67,10 @@ import Cpp library "multiple_errors.h"; library "[[@TEST_NAME]]"; //@dump-sem-ir-begin -// CHECK:STDERR: import_cpp_file_with_one_warning.carbon:[[@LINE+7]]:1: in import [InImport] -// CHECK:STDERR: ./one_warning.h:2: warning: In file included from import_cpp_file_with_one_warning.carbon:[[@LINE+6]]: -// CHECK:STDERR: ./one_warning.h:2:2: warning: "warning1" +// CHECK:STDERR: import_cpp_file_with_one_warning.carbon:[[@LINE+5]]:10: in file included here [InCppInclude] +// CHECK:STDERR: ./one_warning.h:2:2: warning: "warning1" [CppInteropParseWarning] // CHECK:STDERR: 2 | #warning "warning1" // CHECK:STDERR: | ^ -// CHECK:STDERR: [CppInteropParseWarning] // CHECK:STDERR: import Cpp library "one_warning.h"; //@dump-sem-ir-end @@ -98,26 +90,20 @@ import Cpp library "one_warning.h"; library "[[@TEST_NAME]]"; //@dump-sem-ir-begin -// CHECK:STDERR: import_cpp_file_with_multiple_warnings.carbon:[[@LINE+21]]:1: in import [InImport] -// CHECK:STDERR: ./multiple_warnings.h:2: warning: In file included from import_cpp_file_with_multiple_warnings.carbon:[[@LINE+20]]: -// CHECK:STDERR: ./multiple_warnings.h:2:2: warning: "warning1" +// CHECK:STDERR: import_cpp_file_with_multiple_warnings.carbon:[[@LINE+15]]:10: in file included here [InCppInclude] +// CHECK:STDERR: ./multiple_warnings.h:2:2: warning: "warning1" [CppInteropParseWarning] // CHECK:STDERR: 2 | #warning "warning1" // CHECK:STDERR: | ^ -// CHECK:STDERR: [CppInteropParseWarning] // CHECK:STDERR: -// CHECK:STDERR: import_cpp_file_with_multiple_warnings.carbon:[[@LINE+14]]:1: in import [InImport] -// CHECK:STDERR: ./multiple_warnings.h:3: warning: In file included from import_cpp_file_with_multiple_warnings.carbon:[[@LINE+13]]: -// CHECK:STDERR: ./multiple_warnings.h:3:2: warning: "warning2" +// CHECK:STDERR: import_cpp_file_with_multiple_warnings.carbon:[[@LINE+10]]:10: in file included here [InCppInclude] +// CHECK:STDERR: ./multiple_warnings.h:3:2: warning: "warning2" [CppInteropParseWarning] // CHECK:STDERR: 3 | #warning "warning2" // CHECK:STDERR: | ^ -// CHECK:STDERR: [CppInteropParseWarning] // CHECK:STDERR: -// CHECK:STDERR: import_cpp_file_with_multiple_warnings.carbon:[[@LINE+7]]:1: in import [InImport] -// CHECK:STDERR: ./multiple_warnings.h:4: warning: In file included from import_cpp_file_with_multiple_warnings.carbon:[[@LINE+6]]: -// CHECK:STDERR: ./multiple_warnings.h:4:2: warning: "warning3" +// CHECK:STDERR: import_cpp_file_with_multiple_warnings.carbon:[[@LINE+5]]:10: in file included here [InCppInclude] +// CHECK:STDERR: ./multiple_warnings.h:4:2: warning: "warning3" [CppInteropParseWarning] // CHECK:STDERR: 4 | #warning "warning3" // CHECK:STDERR: | ^ -// CHECK:STDERR: [CppInteropParseWarning] // CHECK:STDERR: import Cpp library "multiple_warnings.h"; //@dump-sem-ir-end @@ -135,19 +121,15 @@ import Cpp library "multiple_warnings.h"; library "[[@TEST_NAME]]"; -// CHECK:STDERR: fail_import_cpp_file_with_one_error_and_one_warning.carbon:[[@LINE+14]]:1: in import [InImport] -// CHECK:STDERR: ./one_error_and_one_warning.h:2: error: In file included from fail_import_cpp_file_with_one_error_and_one_warning.carbon:[[@LINE+13]]: -// CHECK:STDERR: ./one_error_and_one_warning.h:2:2: error: "error1" +// CHECK:STDERR: fail_import_cpp_file_with_one_error_and_one_warning.carbon:[[@LINE+10]]:10: in file included here [InCppInclude] +// CHECK:STDERR: ./one_error_and_one_warning.h:2:2: error: "error1" [CppInteropParseError] // CHECK:STDERR: 2 | #error "error1" // CHECK:STDERR: | ^ -// CHECK:STDERR: [CppInteropParseError] // CHECK:STDERR: -// CHECK:STDERR: fail_import_cpp_file_with_one_error_and_one_warning.carbon:[[@LINE+7]]:1: in import [InImport] -// CHECK:STDERR: ./one_error_and_one_warning.h:3: warning: In file included from fail_import_cpp_file_with_one_error_and_one_warning.carbon:[[@LINE+6]]: -// CHECK:STDERR: ./one_error_and_one_warning.h:3:2: warning: "warning1" +// CHECK:STDERR: fail_import_cpp_file_with_one_error_and_one_warning.carbon:[[@LINE+5]]:10: in file included here [InCppInclude] +// CHECK:STDERR: ./one_error_and_one_warning.h:3:2: warning: "warning1" [CppInteropParseWarning] // CHECK:STDERR: 3 | #warning "warning1" // CHECK:STDERR: | ^ -// CHECK:STDERR: [CppInteropParseWarning] // CHECK:STDERR: import Cpp library "one_error_and_one_warning.h"; @@ -167,40 +149,30 @@ import Cpp library "one_error_and_one_warning.h"; library "[[@TEST_NAME]]"; -// CHECK:STDERR: fail_import_cpp_file_with_multiple_errors_and_multiple_warnings.carbon:[[@LINE+35]]:1: in import [InImport] -// CHECK:STDERR: ./multiple_errors_and_multiple_warnings.h:2: error: In file included from fail_import_cpp_file_with_multiple_errors_and_multiple_warnings.carbon:[[@LINE+34]]: -// CHECK:STDERR: ./multiple_errors_and_multiple_warnings.h:2:2: error: "error1" +// CHECK:STDERR: fail_import_cpp_file_with_multiple_errors_and_multiple_warnings.carbon:[[@LINE+25]]:10: in file included here [InCppInclude] +// CHECK:STDERR: ./multiple_errors_and_multiple_warnings.h:2:2: error: "error1" [CppInteropParseError] // CHECK:STDERR: 2 | #error "error1" // CHECK:STDERR: | ^ -// CHECK:STDERR: [CppInteropParseError] // CHECK:STDERR: -// CHECK:STDERR: fail_import_cpp_file_with_multiple_errors_and_multiple_warnings.carbon:[[@LINE+28]]:1: in import [InImport] -// CHECK:STDERR: ./multiple_errors_and_multiple_warnings.h:3: error: In file included from fail_import_cpp_file_with_multiple_errors_and_multiple_warnings.carbon:[[@LINE+27]]: -// CHECK:STDERR: ./multiple_errors_and_multiple_warnings.h:3:2: error: "error2" +// CHECK:STDERR: fail_import_cpp_file_with_multiple_errors_and_multiple_warnings.carbon:[[@LINE+20]]:10: in file included here [InCppInclude] +// CHECK:STDERR: ./multiple_errors_and_multiple_warnings.h:3:2: error: "error2" [CppInteropParseError] // CHECK:STDERR: 3 | #error "error2" // CHECK:STDERR: | ^ -// CHECK:STDERR: [CppInteropParseError] // CHECK:STDERR: -// CHECK:STDERR: fail_import_cpp_file_with_multiple_errors_and_multiple_warnings.carbon:[[@LINE+21]]:1: in import [InImport] -// CHECK:STDERR: ./multiple_errors_and_multiple_warnings.h:4: warning: In file included from fail_import_cpp_file_with_multiple_errors_and_multiple_warnings.carbon:[[@LINE+20]]: -// CHECK:STDERR: ./multiple_errors_and_multiple_warnings.h:4:2: warning: "warning1" +// CHECK:STDERR: fail_import_cpp_file_with_multiple_errors_and_multiple_warnings.carbon:[[@LINE+15]]:10: in file included here [InCppInclude] +// CHECK:STDERR: ./multiple_errors_and_multiple_warnings.h:4:2: warning: "warning1" [CppInteropParseWarning] // CHECK:STDERR: 4 | #warning "warning1" // CHECK:STDERR: | ^ -// CHECK:STDERR: [CppInteropParseWarning] // CHECK:STDERR: -// CHECK:STDERR: fail_import_cpp_file_with_multiple_errors_and_multiple_warnings.carbon:[[@LINE+14]]:1: in import [InImport] -// CHECK:STDERR: ./multiple_errors_and_multiple_warnings.h:5: warning: In file included from fail_import_cpp_file_with_multiple_errors_and_multiple_warnings.carbon:[[@LINE+13]]: -// CHECK:STDERR: ./multiple_errors_and_multiple_warnings.h:5:2: warning: "warning2" +// CHECK:STDERR: fail_import_cpp_file_with_multiple_errors_and_multiple_warnings.carbon:[[@LINE+10]]:10: in file included here [InCppInclude] +// CHECK:STDERR: ./multiple_errors_and_multiple_warnings.h:5:2: warning: "warning2" [CppInteropParseWarning] // CHECK:STDERR: 5 | #warning "warning2" // CHECK:STDERR: | ^ -// CHECK:STDERR: [CppInteropParseWarning] // CHECK:STDERR: -// CHECK:STDERR: fail_import_cpp_file_with_multiple_errors_and_multiple_warnings.carbon:[[@LINE+7]]:1: in import [InImport] -// CHECK:STDERR: ./multiple_errors_and_multiple_warnings.h:6: warning: In file included from fail_import_cpp_file_with_multiple_errors_and_multiple_warnings.carbon:[[@LINE+6]]: -// CHECK:STDERR: ./multiple_errors_and_multiple_warnings.h:6:2: warning: "warning3" +// CHECK:STDERR: fail_import_cpp_file_with_multiple_errors_and_multiple_warnings.carbon:[[@LINE+5]]:10: in file included here [InCppInclude] +// CHECK:STDERR: ./multiple_errors_and_multiple_warnings.h:6:2: warning: "warning3" [CppInteropParseWarning] // CHECK:STDERR: 6 | #warning "warning3" // CHECK:STDERR: | ^ -// CHECK:STDERR: [CppInteropParseWarning] // CHECK:STDERR: import Cpp library "multiple_errors_and_multiple_warnings.h"; @@ -213,35 +185,27 @@ import Cpp library "multiple_errors_and_multiple_warnings.h"; library "[[@TEST_NAME]]"; //@dump-sem-ir-begin -// CHECK:STDERR: import_multiple_cpp_files_with_warnings.carbon:[[@LINE+28]]:1: in import [InImport] -// CHECK:STDERR: ./one_warning.h:2: warning: In file included from import_multiple_cpp_files_with_warnings.carbon:[[@LINE+27]]: -// CHECK:STDERR: ./one_warning.h:2:2: warning: "warning1" +// CHECK:STDERR: import_multiple_cpp_files_with_warnings.carbon:[[@LINE+5]]:10: in file included here [InCppInclude] +// CHECK:STDERR: ./one_warning.h:2:2: warning: "warning1" [CppInteropParseWarning] // CHECK:STDERR: 2 | #warning "warning1" // CHECK:STDERR: | ^ -// CHECK:STDERR: [CppInteropParseWarning] -// CHECK:STDERR: -// CHECK:STDERR: import_multiple_cpp_files_with_warnings.carbon:[[@LINE+21]]:1: in import [InImport] -// CHECK:STDERR: ./multiple_warnings.h:2: warning: In file included from import_multiple_cpp_files_with_warnings.carbon:[[@LINE+21]]: -// CHECK:STDERR: ./multiple_warnings.h:2:2: warning: "warning1" -// CHECK:STDERR: 2 | #warning "warning1" -// CHECK:STDERR: | ^ -// CHECK:STDERR: [CppInteropParseWarning] -// CHECK:STDERR: -// CHECK:STDERR: import_multiple_cpp_files_with_warnings.carbon:[[@LINE+14]]:1: in import [InImport] -// CHECK:STDERR: ./multiple_warnings.h:3: warning: In file included from import_multiple_cpp_files_with_warnings.carbon:[[@LINE+14]]: -// CHECK:STDERR: ./multiple_warnings.h:3:2: warning: "warning2" -// CHECK:STDERR: 3 | #warning "warning2" -// CHECK:STDERR: | ^ -// CHECK:STDERR: [CppInteropParseWarning] -// CHECK:STDERR: -// CHECK:STDERR: import_multiple_cpp_files_with_warnings.carbon:[[@LINE+7]]:1: in import [InImport] -// CHECK:STDERR: ./multiple_warnings.h:4: warning: In file included from import_multiple_cpp_files_with_warnings.carbon:[[@LINE+7]]: -// CHECK:STDERR: ./multiple_warnings.h:4:2: warning: "warning3" -// CHECK:STDERR: 4 | #warning "warning3" -// CHECK:STDERR: | ^ -// CHECK:STDERR: [CppInteropParseWarning] // CHECK:STDERR: import Cpp library "one_warning.h"; +// CHECK:STDERR: import_multiple_cpp_files_with_warnings.carbon:[[@LINE+15]]:10: in file included here [InCppInclude] +// CHECK:STDERR: ./multiple_warnings.h:2:2: warning: "warning1" [CppInteropParseWarning] +// CHECK:STDERR: 2 | #warning "warning1" +// CHECK:STDERR: | ^ +// CHECK:STDERR: +// CHECK:STDERR: import_multiple_cpp_files_with_warnings.carbon:[[@LINE+10]]:10: in file included here [InCppInclude] +// CHECK:STDERR: ./multiple_warnings.h:3:2: warning: "warning2" [CppInteropParseWarning] +// CHECK:STDERR: 3 | #warning "warning2" +// CHECK:STDERR: | ^ +// CHECK:STDERR: +// CHECK:STDERR: import_multiple_cpp_files_with_warnings.carbon:[[@LINE+5]]:10: in file included here [InCppInclude] +// CHECK:STDERR: ./multiple_warnings.h:4:2: warning: "warning3" [CppInteropParseWarning] +// CHECK:STDERR: 4 | #warning "warning3" +// CHECK:STDERR: | ^ +// CHECK:STDERR: import Cpp library "multiple_warnings.h"; //@dump-sem-ir-end @@ -253,56 +217,42 @@ import Cpp library "multiple_warnings.h"; library "[[@TEST_NAME]]"; -// CHECK:STDERR: fail_import_multiple_cpp_files_with_errors_and_warnings.carbon:[[@LINE+49]]:1: in import [InImport] -// CHECK:STDERR: ./one_error_and_one_warning.h:2: error: In file included from fail_import_multiple_cpp_files_with_errors_and_warnings.carbon:[[@LINE+48]]: -// CHECK:STDERR: ./one_error_and_one_warning.h:2:2: error: "error1" +// CHECK:STDERR: fail_import_multiple_cpp_files_with_errors_and_warnings.carbon:[[@LINE+10]]:10: in file included here [InCppInclude] +// CHECK:STDERR: ./one_error_and_one_warning.h:2:2: error: "error1" [CppInteropParseError] // CHECK:STDERR: 2 | #error "error1" // CHECK:STDERR: | ^ -// CHECK:STDERR: [CppInteropParseError] // CHECK:STDERR: -// CHECK:STDERR: fail_import_multiple_cpp_files_with_errors_and_warnings.carbon:[[@LINE+42]]:1: in import [InImport] -// CHECK:STDERR: ./one_error_and_one_warning.h:3: warning: In file included from fail_import_multiple_cpp_files_with_errors_and_warnings.carbon:[[@LINE+41]]: -// CHECK:STDERR: ./one_error_and_one_warning.h:3:2: warning: "warning1" +// CHECK:STDERR: fail_import_multiple_cpp_files_with_errors_and_warnings.carbon:[[@LINE+5]]:10: in file included here [InCppInclude] +// CHECK:STDERR: ./one_error_and_one_warning.h:3:2: warning: "warning1" [CppInteropParseWarning] // CHECK:STDERR: 3 | #warning "warning1" // CHECK:STDERR: | ^ -// CHECK:STDERR: [CppInteropParseWarning] -// CHECK:STDERR: -// CHECK:STDERR: fail_import_multiple_cpp_files_with_errors_and_warnings.carbon:[[@LINE+35]]:1: in import [InImport] -// CHECK:STDERR: ./multiple_errors_and_multiple_warnings.h:2: error: In file included from fail_import_multiple_cpp_files_with_errors_and_warnings.carbon:[[@LINE+35]]: -// CHECK:STDERR: ./multiple_errors_and_multiple_warnings.h:2:2: error: "error1" -// CHECK:STDERR: 2 | #error "error1" -// CHECK:STDERR: | ^ -// CHECK:STDERR: [CppInteropParseError] -// CHECK:STDERR: -// CHECK:STDERR: fail_import_multiple_cpp_files_with_errors_and_warnings.carbon:[[@LINE+28]]:1: in import [InImport] -// CHECK:STDERR: ./multiple_errors_and_multiple_warnings.h:3: error: In file included from fail_import_multiple_cpp_files_with_errors_and_warnings.carbon:[[@LINE+28]]: -// CHECK:STDERR: ./multiple_errors_and_multiple_warnings.h:3:2: error: "error2" -// CHECK:STDERR: 3 | #error "error2" -// CHECK:STDERR: | ^ -// CHECK:STDERR: [CppInteropParseError] -// CHECK:STDERR: -// CHECK:STDERR: fail_import_multiple_cpp_files_with_errors_and_warnings.carbon:[[@LINE+21]]:1: in import [InImport] -// CHECK:STDERR: ./multiple_errors_and_multiple_warnings.h:4: warning: In file included from fail_import_multiple_cpp_files_with_errors_and_warnings.carbon:[[@LINE+21]]: -// CHECK:STDERR: ./multiple_errors_and_multiple_warnings.h:4:2: warning: "warning1" -// CHECK:STDERR: 4 | #warning "warning1" -// CHECK:STDERR: | ^ -// CHECK:STDERR: [CppInteropParseWarning] -// CHECK:STDERR: -// CHECK:STDERR: fail_import_multiple_cpp_files_with_errors_and_warnings.carbon:[[@LINE+14]]:1: in import [InImport] -// CHECK:STDERR: ./multiple_errors_and_multiple_warnings.h:5: warning: In file included from fail_import_multiple_cpp_files_with_errors_and_warnings.carbon:[[@LINE+14]]: -// CHECK:STDERR: ./multiple_errors_and_multiple_warnings.h:5:2: warning: "warning2" -// CHECK:STDERR: 5 | #warning "warning2" -// CHECK:STDERR: | ^ -// CHECK:STDERR: [CppInteropParseWarning] -// CHECK:STDERR: -// CHECK:STDERR: fail_import_multiple_cpp_files_with_errors_and_warnings.carbon:[[@LINE+7]]:1: in import [InImport] -// CHECK:STDERR: ./multiple_errors_and_multiple_warnings.h:6: warning: In file included from fail_import_multiple_cpp_files_with_errors_and_warnings.carbon:[[@LINE+7]]: -// CHECK:STDERR: ./multiple_errors_and_multiple_warnings.h:6:2: warning: "warning3" -// CHECK:STDERR: 6 | #warning "warning3" -// CHECK:STDERR: | ^ -// CHECK:STDERR: [CppInteropParseWarning] // CHECK:STDERR: import Cpp library "one_error_and_one_warning.h"; +// CHECK:STDERR: fail_import_multiple_cpp_files_with_errors_and_warnings.carbon:[[@LINE+25]]:10: in file included here [InCppInclude] +// CHECK:STDERR: ./multiple_errors_and_multiple_warnings.h:2:2: error: "error1" [CppInteropParseError] +// CHECK:STDERR: 2 | #error "error1" +// CHECK:STDERR: | ^ +// CHECK:STDERR: +// CHECK:STDERR: fail_import_multiple_cpp_files_with_errors_and_warnings.carbon:[[@LINE+20]]:10: in file included here [InCppInclude] +// CHECK:STDERR: ./multiple_errors_and_multiple_warnings.h:3:2: error: "error2" [CppInteropParseError] +// CHECK:STDERR: 3 | #error "error2" +// CHECK:STDERR: | ^ +// CHECK:STDERR: +// CHECK:STDERR: fail_import_multiple_cpp_files_with_errors_and_warnings.carbon:[[@LINE+15]]:10: in file included here [InCppInclude] +// CHECK:STDERR: ./multiple_errors_and_multiple_warnings.h:4:2: warning: "warning1" [CppInteropParseWarning] +// CHECK:STDERR: 4 | #warning "warning1" +// CHECK:STDERR: | ^ +// CHECK:STDERR: +// CHECK:STDERR: fail_import_multiple_cpp_files_with_errors_and_warnings.carbon:[[@LINE+10]]:10: in file included here [InCppInclude] +// CHECK:STDERR: ./multiple_errors_and_multiple_warnings.h:5:2: warning: "warning2" [CppInteropParseWarning] +// CHECK:STDERR: 5 | #warning "warning2" +// CHECK:STDERR: | ^ +// CHECK:STDERR: +// CHECK:STDERR: fail_import_multiple_cpp_files_with_errors_and_warnings.carbon:[[@LINE+5]]:10: in file included here [InCppInclude] +// CHECK:STDERR: ./multiple_errors_and_multiple_warnings.h:6:2: warning: "warning3" [CppInteropParseWarning] +// CHECK:STDERR: 6 | #warning "warning3" +// CHECK:STDERR: | ^ +// CHECK:STDERR: import Cpp library "multiple_errors_and_multiple_warnings.h"; // ============================================================================ @@ -313,19 +263,15 @@ import Cpp library "multiple_errors_and_multiple_warnings.h"; #include "one_error.h" -// --- fail_todo_import_indirect_error.carbon +// --- fail_import_indirect_error.carbon library "[[@TEST_NAME]]"; -// TODO: The `In file included from` line should not be prefixed. See -// https://github.com/carbon-language/carbon-lang/pull/5614#pullrequestreview-2900939411 -// CHECK:STDERR: fail_todo_import_indirect_error.carbon:[[@LINE+8]]:1: in import [InImport] -// CHECK:STDERR: ./one_error.h:2: error: In file included from fail_todo_import_indirect_error.carbon:[[@LINE+7]]: -// CHECK:STDERR: In file included from ./indirect_error.h:2: -// CHECK:STDERR: ./one_error.h:2:2: error: "error1" +// CHECK:STDERR: fail_import_indirect_error.carbon:[[@LINE+6]]:10: in file included here [InCppInclude] +// CHECK:STDERR: ./indirect_error.h:2:10: in file included here [InCppInclude] +// CHECK:STDERR: ./one_error.h:2:2: error: "error1" [CppInteropParseError] // CHECK:STDERR: 2 | #error "error1" // CHECK:STDERR: | ^ -// CHECK:STDERR: [CppInteropParseError] // CHECK:STDERR: import Cpp library "indirect_error.h"; @@ -337,20 +283,16 @@ import Cpp library "indirect_error.h"; #include "one_warning.h" -// --- todo_import_indirect_warning.carbon +// --- import_indirect_warning.carbon library "[[@TEST_NAME]]"; -// TODO: The `In file included from` line should not be prefixed. See -// https://github.com/carbon-language/carbon-lang/pull/5614#pullrequestreview-2900939411 //@dump-sem-ir-begin -// CHECK:STDERR: todo_import_indirect_warning.carbon:[[@LINE+8]]:1: in import [InImport] -// CHECK:STDERR: ./one_warning.h:2: warning: In file included from todo_import_indirect_warning.carbon:[[@LINE+7]]: -// CHECK:STDERR: In file included from ./indirect_warning.h:2: -// CHECK:STDERR: ./one_warning.h:2:2: warning: "warning1" +// CHECK:STDERR: import_indirect_warning.carbon:[[@LINE+6]]:10: in file included here [InCppInclude] +// CHECK:STDERR: ./indirect_warning.h:2:10: in file included here [InCppInclude] +// CHECK:STDERR: ./one_warning.h:2:2: warning: "warning1" [CppInteropParseWarning] // CHECK:STDERR: 2 | #warning "warning1" // CHECK:STDERR: | ^ -// CHECK:STDERR: [CppInteropParseWarning] // CHECK:STDERR: import Cpp library "indirect_warning.h"; //@dump-sem-ir-end @@ -364,14 +306,12 @@ import Cpp library "indirect_warning.h"; library "[[@TEST_NAME]]"; // Trailing comment // TODO: Move this warning to be after the lexer trailing comment error. -// CHECK:STDERR: fail_import_cpp_library_lexer_error.carbon:[[@LINE+11]]:1: in import [InImport] -// CHECK:STDERR: ./one_warning.h:2: warning: In file included from fail_import_cpp_library_lexer_error.carbon:[[@LINE+10]]: -// CHECK:STDERR: ./one_warning.h:2:2: warning: "warning1" +// CHECK:STDERR: fail_import_cpp_library_lexer_error.carbon:[[@LINE+9]]:10: in file included here [InCppInclude] +// CHECK:STDERR: ./one_warning.h:2:2: warning: "warning1" [CppInteropParseWarning] // CHECK:STDERR: 2 | #warning "warning1" // CHECK:STDERR: | ^ -// CHECK:STDERR: [CppInteropParseWarning] // CHECK:STDERR: -// CHECK:STDERR: fail_import_cpp_library_lexer_error.carbon:[[@LINE-10]]:44: error: trailing comments are not permitted [TrailingComment] +// CHECK:STDERR: fail_import_cpp_library_lexer_error.carbon:[[@LINE-8]]:44: error: trailing comments are not permitted [TrailingComment] // CHECK:STDERR: library "import_cpp_library_lexer_error"; // Trailing comment // CHECK:STDERR: ^ // CHECK:STDERR: @@ -389,13 +329,11 @@ double score = 0.1 library "[[@TEST_NAME]]"; -// CHECK:STDERR: fail_import_fix_it_hints.carbon:[[@LINE+8]]:1: in import [InImport] -// CHECK:STDERR: ./fix_it_hints.h:2: error: In file included from fail_import_fix_it_hints.carbon:[[@LINE+7]]: -// CHECK:STDERR: ./fix_it_hints.h:2:19: error: expected ';' after top level declarator +// CHECK:STDERR: fail_import_fix_it_hints.carbon:[[@LINE+6]]:10: in file included here [InCppInclude] +// CHECK:STDERR: ./fix_it_hints.h:2:19: error: expected ';' after top level declarator [CppInteropParseError] // CHECK:STDERR: 2 | double score = 0.1 // CHECK:STDERR: | ^ // CHECK:STDERR: | ; -// CHECK:STDERR: [CppInteropParseError] // CHECK:STDERR: import Cpp library "fix_it_hints.h"; @@ -419,17 +357,14 @@ inline void call_foobar() { library "[[@TEST_NAME]]"; -// CHECK:STDERR: fail_with_notes.carbon:[[@LINE+12]]:1: in import [InImport] -// CHECK:STDERR: ./with_notes.h:5: error: In file included from fail_with_notes.carbon:[[@LINE+11]]: -// CHECK:STDERR: ./with_notes.h:5:3: error: no matching function for call to 'foobar' +// CHECK:STDERR: fail_with_notes.carbon:[[@LINE+9]]:10: in file included here [InCppInclude] +// CHECK:STDERR: ./with_notes.h:5:3: error: no matching function for call to 'foobar' [CppInteropParseError] // CHECK:STDERR: 5 | foobar(1, 2); // CHECK:STDERR: | ^~~~~~ -// CHECK:STDERR: [CppInteropParseError] -// CHECK:STDERR: fail_with_notes.carbon:[[@LINE+6]]:1: in import [InImport] -// CHECK:STDERR: ./with_notes.h:2: note: ./with_notes.h:2:6: note: candidate function not viable: requires 1 argument, but 2 were provided +// CHECK:STDERR: fail_with_notes.carbon:[[@LINE+5]]:10: in file included here [InCppInclude] +// CHECK:STDERR: ./with_notes.h:2:6: note: candidate function not viable: requires 1 argument, but 2 were provided [CppInteropParseNote] // CHECK:STDERR: 2 | void foobar(int); // CHECK:STDERR: | ^ ~~~ -// CHECK:STDERR: [CppInteropParseNote] // CHECK:STDERR: import Cpp library "with_notes.h"; @@ -437,6 +372,44 @@ fn F() { Cpp.call_foobar(); } +// ============================================================================ +// Context stacks +// ============================================================================ + +// --- indirect_include.h + +#define FOO BAR +#define BAZ void f(error); + +FOO + +// --- direct_include.h + +#define BAR BAZ + +#include "indirect_include.h" + +// --- fail_use_context_stack.carbon + +library "[[@TEST_NAME]]"; + +// CHECK:STDERR: fail_use_context_stack.carbon:[[@LINE+15]]:10: in file included here [InCppInclude] +// CHECK:STDERR: ./direct_include.h:4:10: in file included here [InCppInclude] +// CHECK:STDERR: ./indirect_include.h:2:13: in expansion of macro defined here [InCppMacroExpansion] +// CHECK:STDERR: ./direct_include.h:2:13: in expansion of macro defined here [InCppMacroExpansion] +// CHECK:STDERR: ./indirect_include.h:3:20: in expansion of macro defined here [InCppMacroExpansion] +// CHECK:STDERR: ./indirect_include.h:5:1: error: unknown type name 'error' [CppInteropParseError] +// CHECK:STDERR: 5 | FOO +// CHECK:STDERR: | ^ +// CHECK:STDERR: 2 | #define FOO BAR +// CHECK:STDERR: | ^ +// CHECK:STDERR: 2 | #define BAR BAZ +// CHECK:STDERR: | ^ +// CHECK:STDERR: 3 | #define BAZ void f(error); +// CHECK:STDERR: | ^ +// CHECK:STDERR: +import Cpp library "direct_include.h"; + // CHECK:STDOUT: --- import_cpp_file_with_one_warning.carbon // CHECK:STDOUT: // CHECK:STDOUT: imports { @@ -471,7 +444,7 @@ fn F() { // CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: --- todo_import_indirect_warning.carbon +// CHECK:STDOUT: --- import_indirect_warning.carbon // CHECK:STDOUT: // CHECK:STDOUT: imports { // CHECK:STDOUT: } diff --git a/toolchain/check/testdata/interop/cpp/file_not_found.carbon b/toolchain/check/testdata/interop/cpp/file_not_found.carbon index f4a301b323e3..fdc1b5b5f14d 100644 --- a/toolchain/check/testdata/interop/cpp/file_not_found.carbon +++ b/toolchain/check/testdata/interop/cpp/file_not_found.carbon @@ -14,10 +14,8 @@ library "[[@TEST_NAME]]"; -// CHECK:STDERR: fail_cpp_file_not_found.carbon:[[@LINE+6]]:1: in import [InImport] -// CHECK:STDERR: fail_cpp_file_not_found.carbon:[[@LINE+5]]: error: fail_cpp_file_not_found.carbon:[[@LINE+5]]:10: fatal error: 'not_found.h' file not found -// CHECK:STDERR: 10 | #include "not_found.h" +// CHECK:STDERR: fail_cpp_file_not_found.carbon:[[@LINE+4]]:10: error: 'not_found.h' file not found [CppInteropParseError] +// CHECK:STDERR: 8 | #include "not_found.h" // CHECK:STDERR: | ^~~~~~~~~~~~~ -// CHECK:STDERR: [CppInteropParseError] // CHECK:STDERR: import Cpp library "not_found.h"; diff --git a/toolchain/check/testdata/interop/cpp/function/class.carbon b/toolchain/check/testdata/interop/cpp/function/class.carbon index 77277c97a702..ae83d9bb48c6 100644 --- a/toolchain/check/testdata/interop/cpp/function/class.carbon +++ b/toolchain/check/testdata/interop/cpp/function/class.carbon @@ -27,11 +27,13 @@ library "[[@TEST_NAME]]"; import Cpp library "decl_value_param_type.h"; fn F() { - // CHECK:STDERR: fail_todo_import_decl_value_param_type.carbon:[[@LINE+7]]:11: error: forming value of incomplete type `Cpp.C` [IncompleteTypeInValueConversion] + // CHECK:STDERR: fail_todo_import_decl_value_param_type.carbon:[[@LINE+9]]:11: error: forming value of incomplete type `Cpp.C` [IncompleteTypeInValueConversion] // CHECK:STDERR: Cpp.foo({}); // CHECK:STDERR: ^~ - // CHECK:STDERR: fail_todo_import_decl_value_param_type.carbon:[[@LINE-6]]:1: in import [InImport] - // CHECK:STDERR: ./decl_value_param_type.h:2: note: class was forward declared here [ClassForwardDeclaredHere] + // CHECK:STDERR: fail_todo_import_decl_value_param_type.carbon:[[@LINE-6]]:10: in file included here [InCppInclude] + // CHECK:STDERR: ./decl_value_param_type.h:2:7: note: class was forward declared here [ClassForwardDeclaredHere] + // CHECK:STDERR: class C; + // CHECK:STDERR: ^ // CHECK:STDERR: fail_todo_import_decl_value_param_type.carbon: note: initializing function parameter [InCallToFunctionParam] // CHECK:STDERR: Cpp.foo({}); @@ -44,11 +46,13 @@ library "[[@TEST_NAME]]"; import Cpp library "decl_value_param_type.h"; fn F() { - // CHECK:STDERR: fail_todo_import_decl_value_param_type_previously_imported.carbon:[[@LINE+10]]:10: error: binding pattern has incomplete type `C` in name binding declaration [IncompleteTypeInBindingDecl] + // CHECK:STDERR: fail_todo_import_decl_value_param_type_previously_imported.carbon:[[@LINE+12]]:10: error: binding pattern has incomplete type `C` in name binding declaration [IncompleteTypeInBindingDecl] // CHECK:STDERR: let c: Cpp.C; // CHECK:STDERR: ^~~~~ - // CHECK:STDERR: fail_todo_import_decl_value_param_type_previously_imported.carbon:[[@LINE-6]]:1: in import [InImport] - // CHECK:STDERR: ./decl_value_param_type.h:2: note: class was forward declared here [ClassForwardDeclaredHere] + // CHECK:STDERR: fail_todo_import_decl_value_param_type_previously_imported.carbon:[[@LINE-6]]:10: in file included here [InCppInclude] + // CHECK:STDERR: ./decl_value_param_type.h:2:7: note: class was forward declared here [ClassForwardDeclaredHere] + // CHECK:STDERR: class C; + // CHECK:STDERR: ^ // CHECK:STDERR: // CHECK:STDERR: fail_todo_import_decl_value_param_type_previously_imported.carbon:[[@LINE+4]]:15: error: expected `=`; `let` declaration must have an initializer [ExpectedInitializerAfterLet] // CHECK:STDERR: let c: Cpp.C; @@ -76,19 +80,23 @@ library "[[@TEST_NAME]]"; import Cpp library "double_decl_value_param_type.h"; fn F() { - // CHECK:STDERR: fail_todo_import_double_decl_value_param_type.carbon:[[@LINE+7]]:12: error: forming value of incomplete type `Cpp.C` [IncompleteTypeInValueConversion] + // CHECK:STDERR: fail_todo_import_double_decl_value_param_type.carbon:[[@LINE+9]]:12: error: forming value of incomplete type `Cpp.C` [IncompleteTypeInValueConversion] // CHECK:STDERR: Cpp.foo1({}); // CHECK:STDERR: ^~ - // CHECK:STDERR: fail_todo_import_double_decl_value_param_type.carbon:[[@LINE-6]]:1: in import [InImport] - // CHECK:STDERR: ./double_decl_value_param_type.h:2: note: class was forward declared here [ClassForwardDeclaredHere] + // CHECK:STDERR: fail_todo_import_double_decl_value_param_type.carbon:[[@LINE-6]]:10: in file included here [InCppInclude] + // CHECK:STDERR: ./double_decl_value_param_type.h:2:7: note: class was forward declared here [ClassForwardDeclaredHere] + // CHECK:STDERR: class C; + // CHECK:STDERR: ^ // CHECK:STDERR: fail_todo_import_double_decl_value_param_type.carbon: note: initializing function parameter [InCallToFunctionParam] // CHECK:STDERR: Cpp.foo1({}); - // CHECK:STDERR: fail_todo_import_double_decl_value_param_type.carbon:[[@LINE+7]]:12: error: forming value of incomplete type `Cpp.C` [IncompleteTypeInValueConversion] + // CHECK:STDERR: fail_todo_import_double_decl_value_param_type.carbon:[[@LINE+9]]:12: error: forming value of incomplete type `Cpp.C` [IncompleteTypeInValueConversion] // CHECK:STDERR: Cpp.foo2({}); // CHECK:STDERR: ^~ - // CHECK:STDERR: fail_todo_import_double_decl_value_param_type.carbon:[[@LINE-14]]:1: in import [InImport] - // CHECK:STDERR: ./double_decl_value_param_type.h:2: note: class was forward declared here [ClassForwardDeclaredHere] + // CHECK:STDERR: fail_todo_import_double_decl_value_param_type.carbon:[[@LINE-16]]:10: in file included here [InCppInclude] + // CHECK:STDERR: ./double_decl_value_param_type.h:2:7: note: class was forward declared here [ClassForwardDeclaredHere] + // CHECK:STDERR: class C; + // CHECK:STDERR: ^ // CHECK:STDERR: fail_todo_import_double_decl_value_param_type.carbon: note: initializing function parameter [InCallToFunctionParam] // CHECK:STDERR: Cpp.foo2({}); @@ -359,11 +367,13 @@ library "[[@TEST_NAME]]"; import Cpp library "decl_value_return_type.h"; fn F() { - // CHECK:STDERR: fail_todo_import_decl_value_return_type.carbon:[[@LINE+7]]:3: error: function returns incomplete type `Cpp.C` [IncompleteTypeInFunctionReturnType] + // CHECK:STDERR: fail_todo_import_decl_value_return_type.carbon:[[@LINE+9]]:3: error: function returns incomplete type `Cpp.C` [IncompleteTypeInFunctionReturnType] // CHECK:STDERR: Cpp.foo(); // CHECK:STDERR: ^~~~~~~~~ - // CHECK:STDERR: fail_todo_import_decl_value_return_type.carbon:[[@LINE-6]]:1: in import [InImport] - // CHECK:STDERR: ./decl_value_return_type.h:2: note: class was forward declared here [ClassForwardDeclaredHere] + // CHECK:STDERR: fail_todo_import_decl_value_return_type.carbon:[[@LINE-6]]:10: in file included here [InCppInclude] + // CHECK:STDERR: ./decl_value_return_type.h:2:7: note: class was forward declared here [ClassForwardDeclaredHere] + // CHECK:STDERR: class C; + // CHECK:STDERR: ^ // CHECK:STDERR: fail_todo_import_decl_value_return_type.carbon: note: return type declared here [IncompleteReturnTypeHere] // CHECK:STDERR: Cpp.foo(); diff --git a/toolchain/check/testdata/interop/cpp/function/struct.carbon b/toolchain/check/testdata/interop/cpp/function/struct.carbon index 96caaa19f769..e7892e12cf76 100644 --- a/toolchain/check/testdata/interop/cpp/function/struct.carbon +++ b/toolchain/check/testdata/interop/cpp/function/struct.carbon @@ -27,11 +27,13 @@ library "[[@TEST_NAME]]"; import Cpp library "decl_value_param_type.h"; fn F() { - // CHECK:STDERR: fail_todo_import_decl_value_param_type.carbon:[[@LINE+7]]:11: error: forming value of incomplete type `Cpp.S` [IncompleteTypeInValueConversion] + // CHECK:STDERR: fail_todo_import_decl_value_param_type.carbon:[[@LINE+9]]:11: error: forming value of incomplete type `Cpp.S` [IncompleteTypeInValueConversion] // CHECK:STDERR: Cpp.foo({}); // CHECK:STDERR: ^~ - // CHECK:STDERR: fail_todo_import_decl_value_param_type.carbon:[[@LINE-6]]:1: in import [InImport] - // CHECK:STDERR: ./decl_value_param_type.h:2: note: class was forward declared here [ClassForwardDeclaredHere] + // CHECK:STDERR: fail_todo_import_decl_value_param_type.carbon:[[@LINE-6]]:10: in file included here [InCppInclude] + // CHECK:STDERR: ./decl_value_param_type.h:2:8: note: class was forward declared here [ClassForwardDeclaredHere] + // CHECK:STDERR: struct S; + // CHECK:STDERR: ^ // CHECK:STDERR: fail_todo_import_decl_value_param_type.carbon: note: initializing function parameter [InCallToFunctionParam] // CHECK:STDERR: Cpp.foo({}); @@ -44,11 +46,13 @@ library "[[@TEST_NAME]]"; import Cpp library "decl_value_param_type.h"; fn F() { - // CHECK:STDERR: fail_todo_import_decl_value_param_type_previously_imported.carbon:[[@LINE+10]]:10: error: binding pattern has incomplete type `S` in name binding declaration [IncompleteTypeInBindingDecl] + // CHECK:STDERR: fail_todo_import_decl_value_param_type_previously_imported.carbon:[[@LINE+12]]:10: error: binding pattern has incomplete type `S` in name binding declaration [IncompleteTypeInBindingDecl] // CHECK:STDERR: let s: Cpp.S; // CHECK:STDERR: ^~~~~ - // CHECK:STDERR: fail_todo_import_decl_value_param_type_previously_imported.carbon:[[@LINE-6]]:1: in import [InImport] - // CHECK:STDERR: ./decl_value_param_type.h:2: note: class was forward declared here [ClassForwardDeclaredHere] + // CHECK:STDERR: fail_todo_import_decl_value_param_type_previously_imported.carbon:[[@LINE-6]]:10: in file included here [InCppInclude] + // CHECK:STDERR: ./decl_value_param_type.h:2:8: note: class was forward declared here [ClassForwardDeclaredHere] + // CHECK:STDERR: struct S; + // CHECK:STDERR: ^ // CHECK:STDERR: // CHECK:STDERR: fail_todo_import_decl_value_param_type_previously_imported.carbon:[[@LINE+4]]:15: error: expected `=`; `let` declaration must have an initializer [ExpectedInitializerAfterLet] // CHECK:STDERR: let s: Cpp.S; @@ -76,19 +80,23 @@ library "[[@TEST_NAME]]"; import Cpp library "double_decl_value_param_type.h"; fn F() { - // CHECK:STDERR: fail_todo_import_double_decl_value_param_type.carbon:[[@LINE+7]]:12: error: forming value of incomplete type `Cpp.S` [IncompleteTypeInValueConversion] + // CHECK:STDERR: fail_todo_import_double_decl_value_param_type.carbon:[[@LINE+9]]:12: error: forming value of incomplete type `Cpp.S` [IncompleteTypeInValueConversion] // CHECK:STDERR: Cpp.foo1({}); // CHECK:STDERR: ^~ - // CHECK:STDERR: fail_todo_import_double_decl_value_param_type.carbon:[[@LINE-6]]:1: in import [InImport] - // CHECK:STDERR: ./double_decl_value_param_type.h:2: note: class was forward declared here [ClassForwardDeclaredHere] + // CHECK:STDERR: fail_todo_import_double_decl_value_param_type.carbon:[[@LINE-6]]:10: in file included here [InCppInclude] + // CHECK:STDERR: ./double_decl_value_param_type.h:2:8: note: class was forward declared here [ClassForwardDeclaredHere] + // CHECK:STDERR: struct S; + // CHECK:STDERR: ^ // CHECK:STDERR: fail_todo_import_double_decl_value_param_type.carbon: note: initializing function parameter [InCallToFunctionParam] // CHECK:STDERR: Cpp.foo1({}); - // CHECK:STDERR: fail_todo_import_double_decl_value_param_type.carbon:[[@LINE+7]]:12: error: forming value of incomplete type `Cpp.S` [IncompleteTypeInValueConversion] + // CHECK:STDERR: fail_todo_import_double_decl_value_param_type.carbon:[[@LINE+9]]:12: error: forming value of incomplete type `Cpp.S` [IncompleteTypeInValueConversion] // CHECK:STDERR: Cpp.foo2({}); // CHECK:STDERR: ^~ - // CHECK:STDERR: fail_todo_import_double_decl_value_param_type.carbon:[[@LINE-14]]:1: in import [InImport] - // CHECK:STDERR: ./double_decl_value_param_type.h:2: note: class was forward declared here [ClassForwardDeclaredHere] + // CHECK:STDERR: fail_todo_import_double_decl_value_param_type.carbon:[[@LINE-16]]:10: in file included here [InCppInclude] + // CHECK:STDERR: ./double_decl_value_param_type.h:2:8: note: class was forward declared here [ClassForwardDeclaredHere] + // CHECK:STDERR: struct S; + // CHECK:STDERR: ^ // CHECK:STDERR: fail_todo_import_double_decl_value_param_type.carbon: note: initializing function parameter [InCallToFunctionParam] // CHECK:STDERR: Cpp.foo2({}); @@ -351,11 +359,13 @@ library "[[@TEST_NAME]]"; import Cpp library "decl_value_return_type.h"; fn F() { - // CHECK:STDERR: fail_todo_import_decl_value_return_type.carbon:[[@LINE+7]]:3: error: function returns incomplete type `Cpp.S` [IncompleteTypeInFunctionReturnType] + // CHECK:STDERR: fail_todo_import_decl_value_return_type.carbon:[[@LINE+9]]:3: error: function returns incomplete type `Cpp.S` [IncompleteTypeInFunctionReturnType] // CHECK:STDERR: Cpp.foo(); // CHECK:STDERR: ^~~~~~~~~ - // CHECK:STDERR: fail_todo_import_decl_value_return_type.carbon:[[@LINE-6]]:1: in import [InImport] - // CHECK:STDERR: ./decl_value_return_type.h:2: note: class was forward declared here [ClassForwardDeclaredHere] + // CHECK:STDERR: fail_todo_import_decl_value_return_type.carbon:[[@LINE-6]]:10: in file included here [InCppInclude] + // CHECK:STDERR: ./decl_value_return_type.h:2:8: note: class was forward declared here [ClassForwardDeclaredHere] + // CHECK:STDERR: struct S; + // CHECK:STDERR: ^ // CHECK:STDERR: fail_todo_import_decl_value_return_type.carbon: note: return type declared here [IncompleteReturnTypeHere] // CHECK:STDERR: Cpp.foo(); diff --git a/toolchain/check/testdata/interop/cpp/function/union.carbon b/toolchain/check/testdata/interop/cpp/function/union.carbon index d08a10e98bb0..2a7fac76c980 100644 --- a/toolchain/check/testdata/interop/cpp/function/union.carbon +++ b/toolchain/check/testdata/interop/cpp/function/union.carbon @@ -28,11 +28,13 @@ import Cpp library "decl_value_param_type.h"; fn F() { //@dump-sem-ir-begin - // CHECK:STDERR: fail_todo_import_decl_value_param_type.carbon:[[@LINE+7]]:11: error: forming value of incomplete type `Cpp.U` [IncompleteTypeInValueConversion] + // CHECK:STDERR: fail_todo_import_decl_value_param_type.carbon:[[@LINE+9]]:11: error: forming value of incomplete type `Cpp.U` [IncompleteTypeInValueConversion] // CHECK:STDERR: Cpp.foo({}); // CHECK:STDERR: ^~ - // CHECK:STDERR: fail_todo_import_decl_value_param_type.carbon:[[@LINE-7]]:1: in import [InImport] - // CHECK:STDERR: ./decl_value_param_type.h:2: note: class was forward declared here [ClassForwardDeclaredHere] + // CHECK:STDERR: fail_todo_import_decl_value_param_type.carbon:[[@LINE-7]]:10: in file included here [InCppInclude] + // CHECK:STDERR: ./decl_value_param_type.h:2:7: note: class was forward declared here [ClassForwardDeclaredHere] + // CHECK:STDERR: union U; + // CHECK:STDERR: ^ // CHECK:STDERR: fail_todo_import_decl_value_param_type.carbon: note: initializing function parameter [InCallToFunctionParam] // CHECK:STDERR: Cpp.foo({}); @@ -46,11 +48,13 @@ library "[[@TEST_NAME]]"; import Cpp library "decl_value_param_type.h"; fn F() { - // CHECK:STDERR: fail_todo_import_decl_value_param_type_previously_imported.carbon:[[@LINE+10]]:10: error: binding pattern has incomplete type `U` in name binding declaration [IncompleteTypeInBindingDecl] + // CHECK:STDERR: fail_todo_import_decl_value_param_type_previously_imported.carbon:[[@LINE+12]]:10: error: binding pattern has incomplete type `U` in name binding declaration [IncompleteTypeInBindingDecl] // CHECK:STDERR: let u: Cpp.U; // CHECK:STDERR: ^~~~~ - // CHECK:STDERR: fail_todo_import_decl_value_param_type_previously_imported.carbon:[[@LINE-6]]:1: in import [InImport] - // CHECK:STDERR: ./decl_value_param_type.h:2: note: class was forward declared here [ClassForwardDeclaredHere] + // CHECK:STDERR: fail_todo_import_decl_value_param_type_previously_imported.carbon:[[@LINE-6]]:10: in file included here [InCppInclude] + // CHECK:STDERR: ./decl_value_param_type.h:2:7: note: class was forward declared here [ClassForwardDeclaredHere] + // CHECK:STDERR: union U; + // CHECK:STDERR: ^ // CHECK:STDERR: // CHECK:STDERR: fail_todo_import_decl_value_param_type_previously_imported.carbon:[[@LINE+4]]:15: error: expected `=`; `let` declaration must have an initializer [ExpectedInitializerAfterLet] // CHECK:STDERR: let u: Cpp.U; @@ -78,19 +82,23 @@ library "[[@TEST_NAME]]"; import Cpp library "double_decl_value_param_type.h"; fn F() { - // CHECK:STDERR: fail_todo_import_double_decl_value_param_type.carbon:[[@LINE+7]]:12: error: forming value of incomplete type `Cpp.U` [IncompleteTypeInValueConversion] + // CHECK:STDERR: fail_todo_import_double_decl_value_param_type.carbon:[[@LINE+9]]:12: error: forming value of incomplete type `Cpp.U` [IncompleteTypeInValueConversion] // CHECK:STDERR: Cpp.foo1({}); // CHECK:STDERR: ^~ - // CHECK:STDERR: fail_todo_import_double_decl_value_param_type.carbon:[[@LINE-6]]:1: in import [InImport] - // CHECK:STDERR: ./double_decl_value_param_type.h:2: note: class was forward declared here [ClassForwardDeclaredHere] + // CHECK:STDERR: fail_todo_import_double_decl_value_param_type.carbon:[[@LINE-6]]:10: in file included here [InCppInclude] + // CHECK:STDERR: ./double_decl_value_param_type.h:2:7: note: class was forward declared here [ClassForwardDeclaredHere] + // CHECK:STDERR: union U; + // CHECK:STDERR: ^ // CHECK:STDERR: fail_todo_import_double_decl_value_param_type.carbon: note: initializing function parameter [InCallToFunctionParam] // CHECK:STDERR: Cpp.foo1({}); - // CHECK:STDERR: fail_todo_import_double_decl_value_param_type.carbon:[[@LINE+7]]:12: error: forming value of incomplete type `Cpp.U` [IncompleteTypeInValueConversion] + // CHECK:STDERR: fail_todo_import_double_decl_value_param_type.carbon:[[@LINE+9]]:12: error: forming value of incomplete type `Cpp.U` [IncompleteTypeInValueConversion] // CHECK:STDERR: Cpp.foo2({}); // CHECK:STDERR: ^~ - // CHECK:STDERR: fail_todo_import_double_decl_value_param_type.carbon:[[@LINE-14]]:1: in import [InImport] - // CHECK:STDERR: ./double_decl_value_param_type.h:2: note: class was forward declared here [ClassForwardDeclaredHere] + // CHECK:STDERR: fail_todo_import_double_decl_value_param_type.carbon:[[@LINE-16]]:10: in file included here [InCppInclude] + // CHECK:STDERR: ./double_decl_value_param_type.h:2:7: note: class was forward declared here [ClassForwardDeclaredHere] + // CHECK:STDERR: union U; + // CHECK:STDERR: ^ // CHECK:STDERR: fail_todo_import_double_decl_value_param_type.carbon: note: initializing function parameter [InCallToFunctionParam] // CHECK:STDERR: Cpp.foo2({}); @@ -354,11 +362,13 @@ library "[[@TEST_NAME]]"; import Cpp library "decl_value_return_type.h"; fn F() { - // CHECK:STDERR: fail_todo_import_decl_value_return_type.carbon:[[@LINE+7]]:3: error: function returns incomplete type `Cpp.U` [IncompleteTypeInFunctionReturnType] + // CHECK:STDERR: fail_todo_import_decl_value_return_type.carbon:[[@LINE+9]]:3: error: function returns incomplete type `Cpp.U` [IncompleteTypeInFunctionReturnType] // CHECK:STDERR: Cpp.foo(); // CHECK:STDERR: ^~~~~~~~~ - // CHECK:STDERR: fail_todo_import_decl_value_return_type.carbon:[[@LINE-6]]:1: in import [InImport] - // CHECK:STDERR: ./decl_value_return_type.h:2: note: class was forward declared here [ClassForwardDeclaredHere] + // CHECK:STDERR: fail_todo_import_decl_value_return_type.carbon:[[@LINE-6]]:10: in file included here [InCppInclude] + // CHECK:STDERR: ./decl_value_return_type.h:2:7: note: class was forward declared here [ClassForwardDeclaredHere] + // CHECK:STDERR: union U; + // CHECK:STDERR: ^ // CHECK:STDERR: fail_todo_import_decl_value_return_type.carbon: note: return type declared here [IncompleteReturnTypeHere] // CHECK:STDERR: Cpp.foo(); @@ -455,7 +465,7 @@ fn F() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] // CHECK:STDOUT: %foo.ref: %foo.type = name_ref foo, imports.%foo.decl [concrete = constants.%foo] -// CHECK:STDOUT: %.loc15: %empty_struct_type = struct_literal () +// CHECK:STDOUT: %.loc17: %empty_struct_type = struct_literal () // CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref() // CHECK:STDOUT: // CHECK:STDOUT: } diff --git a/toolchain/check/testdata/interop/cpp/namespace.carbon b/toolchain/check/testdata/interop/cpp/namespace.carbon index 5b9194cefaaa..2a5ff8030c9e 100644 --- a/toolchain/check/testdata/interop/cpp/namespace.carbon +++ b/toolchain/check/testdata/interop/cpp/namespace.carbon @@ -121,22 +121,29 @@ inline namespace { namespace N {} } library "[[@TEST_NAME]]"; -// CHECK:STDERR: fail_import_inline_ambiguity.carbon:[[@LINE+13]]:1: in import [InImport] -// CHECK:STDERR: error: error: reference to 'N' is ambiguous -// CHECK:STDERR: [CppInteropParseError] -// CHECK:STDERR: fail_import_inline_ambiguity.carbon:[[@LINE+10]]:1: in import [InImport] -// CHECK:STDERR: ./inline_ambiguity.h:2: note: ./inline_ambiguity.h:2:11: note: candidate found by name lookup is 'N' -// CHECK:STDERR: 2 | namespace N { void foo(); } -// CHECK:STDERR: | ^ -// CHECK:STDERR: [CppInteropParseNote] -// CHECK:STDERR: fail_import_inline_ambiguity.carbon:[[@LINE+5]]:1: in import [InImport] -// CHECK:STDERR: ./inline_ambiguity.h:3: note: ./inline_ambiguity.h:3:30: note: candidate found by name lookup is '(anonymous namespace)::N' -// CHECK:STDERR: 3 | inline namespace { namespace N {} } -// CHECK:STDERR: | ^ -// CHECK:STDERR: [CppInteropParseNote] import Cpp library "inline_ambiguity.h"; fn MyF() { + // Artificially create an error message here so that the first error line for + // this file (which otherwise has no source location) is associated with this + // file split. + // TODO: Pass a location into Clang when performing C++ name lookup so that + // its error has a location attached. + // CHECK:STDERR: fail_import_inline_ambiguity.carbon:[[@LINE+13]]:3: error: name `error` not found [NameNotFound] + // CHECK:STDERR: error; + // CHECK:STDERR: ^~~~~ + // CHECK:STDERR: + // CHECK:STDERR: error: reference to 'N' is ambiguous [CppInteropParseError] + // CHECK:STDERR: fail_import_inline_ambiguity.carbon:[[@LINE-13]]:10: in file included here [InCppInclude] + // CHECK:STDERR: ./inline_ambiguity.h:2:11: note: candidate found by name lookup is 'N' [CppInteropParseNote] + // CHECK:STDERR: 2 | namespace N { void foo(); } + // CHECK:STDERR: | ^ + // CHECK:STDERR: fail_import_inline_ambiguity.carbon:[[@LINE-17]]:10: in file included here [InCppInclude] + // CHECK:STDERR: ./inline_ambiguity.h:3:30: note: candidate found by name lookup is '(anonymous namespace)::N' [CppInteropParseNote] + // CHECK:STDERR: 3 | inline namespace { namespace N {} } + // CHECK:STDERR: | ^ + error; + // CHECK:STDERR: fail_import_inline_ambiguity.carbon:[[@LINE+4]]:3: note: in `Cpp` name lookup for `N` [InCppNameLookup] // CHECK:STDERR: Cpp.N.foo(); // CHECK:STDERR: ^~~~~ diff --git a/toolchain/diagnostics/coverage_test.cpp b/toolchain/diagnostics/coverage_test.cpp index ba518929b856..65eb674e9852 100644 --- a/toolchain/diagnostics/coverage_test.cpp +++ b/toolchain/diagnostics/coverage_test.cpp @@ -46,6 +46,11 @@ constexpr Kind UntestedKinds[] = { // Producing an emit failure may be infeasible. Kind::CodeGenUnableToEmit, + // TODO: This is currently hard to test because it requires building and + // importing a module, which attempts to create additional files with + // unpredictable names in the module cache, which bazel doesn't permit. + Kind::InCppModule, + // TODO: This can only fire if the first message in a diagnostic is rooted // in a file other than the file being compiled. The language server // currently only supports compiling one file at a time. Do one of: diff --git a/toolchain/diagnostics/diagnostic.cpp b/toolchain/diagnostics/diagnostic.cpp index 0ed9ae4dba70..b4369225f4ea 100644 --- a/toolchain/diagnostics/diagnostic.cpp +++ b/toolchain/diagnostics/diagnostic.cpp @@ -24,6 +24,17 @@ auto Loc::FormatLocation(llvm::raw_ostream& out) const -> void { } auto Loc::FormatSnippet(llvm::raw_ostream& out, int indent) const -> void { + if (!snippet.empty()) { + llvm::StringRef snippet_ref = snippet; + do { + auto [snippet_line, rest] = snippet_ref.split('\n'); + out.indent(indent); + out << snippet_line << "\n"; + snippet_ref = rest; + } while (!snippet_ref.empty()); + return; + } + if (column_number == -1) { return; } @@ -33,6 +44,7 @@ auto Loc::FormatSnippet(llvm::raw_ostream& out, int indent) const -> void { out.indent(indent); out << line << "\n"; + out.indent(indent + column); out << "^"; // We want to ensure that we don't underline past the end of the line in diff --git a/toolchain/diagnostics/diagnostic.h b/toolchain/diagnostics/diagnostic.h index 022f2c15cacb..9085424fb6c3 100644 --- a/toolchain/diagnostics/diagnostic.h +++ b/toolchain/diagnostics/diagnostic.h @@ -65,6 +65,10 @@ struct Loc { // A reference to the line of the error. llvm::StringRef line; + // A full snippet to print. If non-empty, this is used instead of `line` when + // printing a snippet. Should contain both the quoted text and the caret line. + std::string snippet; + // 1-based line number. -1 indicates unknown; other values are unused. int32_t line_number = -1; diff --git a/toolchain/diagnostics/diagnostic_emitter.h b/toolchain/diagnostics/diagnostic_emitter.h index 34745328dbea..9bab3ba2fda3 100644 --- a/toolchain/diagnostics/diagnostic_emitter.h +++ b/toolchain/diagnostics/diagnostic_emitter.h @@ -75,6 +75,12 @@ class Emitter { Builder(Builder&&) noexcept = default; auto operator=(Builder&&) noexcept -> Builder& = default; + // Overrides the snippet for the most recently added diagnostic or note with + // the given text. The provided override should include the caret text as + // well as the source snippet. An empty snippet restores the default + // behavior of printing the original source line. + auto OverrideSnippet(llvm::StringRef snippet) -> Builder&; + // Adds a note diagnostic attached to the main diagnostic being built. // The API mirrors the main emission API: `Emitter::Emit`. // For the expected usage see the builder API: `Emitter::Build`. @@ -302,6 +308,16 @@ struct DiagnosticTypeForArg : public Arg::DiagnosticType {}; } // namespace Internal +template +auto Emitter::Builder::OverrideSnippet(llvm::StringRef snippet) + -> Builder& { + if (!emitter_) { + return *this; + } + diagnostic_.messages.back().loc.snippet = snippet; + return *this; +} + template template auto Emitter::Builder::Note( diff --git a/toolchain/diagnostics/diagnostic_kind.def b/toolchain/diagnostics/diagnostic_kind.def index 9ce7628c914d..22a486ddce68 100644 --- a/toolchain/diagnostics/diagnostic_kind.def +++ b/toolchain/diagnostics/diagnostic_kind.def @@ -162,6 +162,9 @@ CARBON_DIAGNOSTIC_KIND(SemanticsTodo) // Location context. CARBON_DIAGNOSTIC_KIND(InImport) +CARBON_DIAGNOSTIC_KIND(InCppInclude) +CARBON_DIAGNOSTIC_KIND(InCppModule) +CARBON_DIAGNOSTIC_KIND(InCppMacroExpansion) CARBON_DIAGNOSTIC_KIND(ResolvingSpecificHere) CARBON_DIAGNOSTIC_KIND(InCppTypeCompletion) diff --git a/toolchain/language_server/testdata/text_document/open_with_cpp_nonexistent.carbon b/toolchain/language_server/testdata/text_document/open_with_cpp_nonexistent.carbon index 8497420213c2..1c166bde0ac2 100644 --- a/toolchain/language_server/testdata/text_document/open_with_cpp_nonexistent.carbon +++ b/toolchain/language_server/testdata/text_document/open_with_cpp_nonexistent.carbon @@ -33,7 +33,7 @@ // CHECK:STDOUT: "textDocumentSync": 2 // CHECK:STDOUT: } // CHECK:STDOUT: } -// CHECK:STDOUT: }Content-Length: 443{{\r}} +// CHECK:STDOUT: }Content-Length: 464{{\r}} // CHECK:STDOUT: {{\r}} // CHECK:STDOUT: { // CHECK:STDOUT: "jsonrpc": "2.0", @@ -41,14 +41,14 @@ // CHECK:STDOUT: "params": { // CHECK:STDOUT: "diagnostics": [ // CHECK:STDOUT: { -// CHECK:STDOUT: "message": "in import", +// CHECK:STDOUT: "message": "'nonexistent.h' file not found", // CHECK:STDOUT: "range": { // CHECK:STDOUT: "end": { -// CHECK:STDOUT: "character": 36, +// CHECK:STDOUT: "character": 11, // CHECK:STDOUT: "line": 1 // CHECK:STDOUT: }, // CHECK:STDOUT: "start": { -// CHECK:STDOUT: "character": 0, +// CHECK:STDOUT: "character": 9, // CHECK:STDOUT: "line": 0 // CHECK:STDOUT: } // CHECK:STDOUT: }, diff --git a/toolchain/sem_ir/BUILD b/toolchain/sem_ir/BUILD index 584bf238b0f0..962ebe8ed572 100644 --- a/toolchain/sem_ir/BUILD +++ b/toolchain/sem_ir/BUILD @@ -245,6 +245,7 @@ cc_library( ":typed_insts", "//toolchain/diagnostics:diagnostic_emitter", "//toolchain/parse:tree", + "@llvm-project//clang:frontend", "@llvm-project//llvm:Support", ], ) diff --git a/toolchain/sem_ir/absolute_node_id.cpp b/toolchain/sem_ir/absolute_node_id.cpp index 40c34c0e56bb..04c274cf3790 100644 --- a/toolchain/sem_ir/absolute_node_id.cpp +++ b/toolchain/sem_ir/absolute_node_id.cpp @@ -17,12 +17,6 @@ static auto FollowImportRef( auto import_ir_inst = cursor_ir->import_ir_insts().Get(import_ir_inst_id); if (import_ir_inst.ir_id() == ImportIRId::Cpp) { CARBON_CHECK(cursor_ir->import_cpps().size() > 0); - // TODO: Decompose the Clang source location to determine which C++ import - // made this location available, and use the location of that import instead - // of arbitrarily using the first C++ import. - absolute_node_ids.push_back( - AbsoluteNodeId(cursor_ir->check_ir_id(), - cursor_ir->import_cpps().values().begin()->node_id)); absolute_node_ids.push_back( AbsoluteNodeId(import_ir_inst.clang_source_loc_id())); return true; diff --git a/toolchain/sem_ir/diagnostic_loc_converter.cpp b/toolchain/sem_ir/diagnostic_loc_converter.cpp index 0982af003ab8..2a1b404d1cbb 100644 --- a/toolchain/sem_ir/diagnostic_loc_converter.cpp +++ b/toolchain/sem_ir/diagnostic_loc_converter.cpp @@ -4,8 +4,106 @@ #include "toolchain/sem_ir/diagnostic_loc_converter.h" +#include "clang/Frontend/DiagnosticRenderer.h" + namespace Carbon::SemIR { +static auto ConvertPresumedLocToDiagnosticsLoc(clang::FullSourceLoc loc, + clang::PresumedLoc presumed_loc) + -> Diagnostics::Loc { + llvm::StringRef line; + + // Ask the Clang SourceManager for the contents of the line containing this + // location. + // TODO: If this location is in our generated header, use the source text from + // the presumed location (the Carbon source file) as the snippet instead. + bool loc_invalid = false; + const auto& src_mgr = loc.getManager(); + auto [file_id, offset] = src_mgr.getDecomposedSpellingLoc(loc); + auto loc_line = src_mgr.getLineNumber(file_id, offset, &loc_invalid); + if (!loc_invalid) { + auto start_of_line = src_mgr.translateLineCol(file_id, loc_line, 1); + line = src_mgr.getCharacterData(start_of_line, &loc_invalid); + line = line.take_until([](char c) { return c == '\n'; }); + } + + return {.filename = presumed_loc.getFilename(), + .line = loc_invalid ? "" : line, + .line_number = static_cast(presumed_loc.getLine()), + .column_number = static_cast(presumed_loc.getColumn()), + .length = loc_invalid ? -1 : 1}; +} + +namespace { +// A diagnostics "renderer" that renders the diagnostic into an array of +// importing contexts based on the C++ include stack. +class ClangImportCollector : public clang::DiagnosticRenderer { + public: + explicit ClangImportCollector( + const clang::LangOptions& lang_opts, clang::DiagnosticOptions& diag_opts, + llvm::SmallVectorImpl* imports) + : DiagnosticRenderer(lang_opts, diag_opts), imports_(imports) {} + + void emitDiagnosticMessage(clang::FullSourceLoc loc, clang::PresumedLoc ploc, + clang::DiagnosticsEngine::Level /*level*/, + llvm::StringRef message, + llvm::ArrayRef /*ranges*/, + clang::DiagOrStoredDiag /*info*/) override { + if (!emitted_message_) { + emitted_message_ = true; + return; + } + // This is an "in macro expanded here" diagnostic that Clang emits after the + // emitted diagnostic. We treat that as another form of context location. + imports_->push_back( + {.loc = ConvertPresumedLocToDiagnosticsLoc(loc, ploc), + .kind = DiagnosticLocConverter::ImportLoc::CppMacroExpansion, + .imported_name = message}); + } + + void emitDiagnosticLoc( + clang::FullSourceLoc /*loc*/, clang::PresumedLoc /*ploc*/, + clang::DiagnosticsEngine::Level /*level*/, + llvm::ArrayRef /*ranges*/) override {} + void emitCodeContext( + clang::FullSourceLoc /*loc*/, clang::DiagnosticsEngine::Level /*level*/, + llvm::SmallVectorImpl& /*ranges*/, + llvm::ArrayRef /*hints*/) override {} + + void emitIncludeLocation(clang::FullSourceLoc loc, + clang::PresumedLoc ploc) override { + // TODO: If this location is for a `#include` in the generated C++ includes + // buffer that corresponds to a carbon import, report it as being an Import + // instead of a CppInclude. + imports_->push_back( + {.loc = ConvertPresumedLocToDiagnosticsLoc(loc, ploc), + .kind = DiagnosticLocConverter::ImportLoc::CppInclude}); + } + void emitImportLocation(clang::FullSourceLoc loc, clang::PresumedLoc ploc, + llvm::StringRef module_name) override { + imports_->push_back( + {.loc = ConvertPresumedLocToDiagnosticsLoc(loc, ploc), + .kind = DiagnosticLocConverter::ImportLoc::CppModuleImport, + .imported_name = module_name}); + } + void emitBuildingModuleLocation(clang::FullSourceLoc loc, + clang::PresumedLoc ploc, + llvm::StringRef module_name) override { + imports_->push_back( + {.loc = ConvertPresumedLocToDiagnosticsLoc(loc, ploc), + .kind = DiagnosticLocConverter::ImportLoc::CppModuleImport, + .imported_name = module_name}); + } + + private: + llvm::SmallVectorImpl* imports_; + // Whether we've emitted the primary diagnostic message or not. Any diagnostic + // emitted after this is an "in macro expansion" note that we want to capture + // as context. + bool emitted_message_ = false; +}; +} // namespace + auto DiagnosticLocConverter::ConvertWithImports(LocId loc_id, bool token_only) const -> LocAndImports { @@ -26,6 +124,20 @@ auto DiagnosticLocConverter::ConvertWithImports(LocId loc_id, result.imports.push_back({.loc = ConvertImpl(absolute_node_id, false).loc}); } + // Convert the C++ import locations. + if (final_node_id.check_ir_id() == SemIR::CheckIRId::Cpp) { + const clang::ASTUnit* ast = sem_ir_->cpp_ast(); + // Collect the location backtrace that Clang would use for an error here. + ClangImportCollector(ast->getLangOpts(), + ast->getDiagnostics().getDiagnosticOptions(), + &result.imports) + .emitDiagnostic( + clang::FullSourceLoc(sem_ir_->clang_source_locs().Get( + final_node_id.clang_source_loc_id()), + ast->getSourceManager()), + clang::DiagnosticsEngine::Error, "", {}, {}); + } + return result; } @@ -63,17 +175,16 @@ auto DiagnosticLocConverter::ConvertImpl( sem_ir_->clang_source_locs().Get(clang_source_loc_id); CARBON_CHECK(sem_ir_->cpp_ast()); - clang::PresumedLoc presumed_loc = - sem_ir_->cpp_ast()->getSourceManager().getPresumedLoc(clang_loc); + const auto& src_mgr = sem_ir_->cpp_ast()->getSourceManager(); + clang::PresumedLoc presumed_loc = src_mgr.getPresumedLoc(clang_loc); if (presumed_loc.isInvalid()) { return Diagnostics::ConvertedLoc(); } - unsigned offset = - sem_ir_->cpp_ast()->getSourceManager().getDecomposedLoc(clang_loc).second; + unsigned offset = src_mgr.getDecomposedLoc(clang_loc).second; return Diagnostics::ConvertedLoc{ - .loc = {.filename = presumed_loc.getFilename(), - .line_number = static_cast(presumed_loc.getLine())}, + .loc = ConvertPresumedLocToDiagnosticsLoc( + clang::FullSourceLoc(clang_loc, src_mgr), presumed_loc), .last_byte_offset = static_cast(offset)}; } diff --git a/toolchain/sem_ir/diagnostic_loc_converter.h b/toolchain/sem_ir/diagnostic_loc_converter.h index 56f392826ac9..8bf9ac3c83a8 100644 --- a/toolchain/sem_ir/diagnostic_loc_converter.h +++ b/toolchain/sem_ir/diagnostic_loc_converter.h @@ -23,9 +23,29 @@ class DiagnosticLocConverter { public: // Information about an import within which the location was found. struct ImportLoc { + enum Kind { + // A regular Carbon `import`. + Import, + // A C++ `#include`. + CppInclude, + // A C++ module import. + CppModuleImport, + // A C++ macro expansion. + CppMacroExpansion, + }; + + // The location of the import. Diagnostics::Loc loc; - // TODO: Include the name of the imported library in this information so it - // can be included in the diagnostic. + + // The kind of import. + Kind kind; + + // The name of the imported module for CppInclude, or the complete macro + // expansion diagnostic message for CppMacroExpansion. + // TODO: In the latter case, provide just the macro name. + // TODO: Include the name of the imported library in this information for + // Import so it can be mentioned in the diagnostic. + llvm::StringRef imported_name; }; // Information about a location that has been converted from a LocId to a