diff --git a/toolchain/codegen/BUILD b/toolchain/codegen/BUILD index 815916ca6c07..b0fc98782408 100644 --- a/toolchain/codegen/BUILD +++ b/toolchain/codegen/BUILD @@ -17,6 +17,8 @@ cc_library( hdrs = ["codegen.h"], deps = [ "//common:check", + "//toolchain/diagnostics:diagnostic_emitter", + "//toolchain/diagnostics:file_diagnostics", "@llvm-project//llvm:Core", "@llvm-project//llvm:MC", "@llvm-project//llvm:Support", diff --git a/toolchain/codegen/codegen.cpp b/toolchain/codegen/codegen.cpp index a5f1f36f6faf..31357272c35b 100644 --- a/toolchain/codegen/codegen.cpp +++ b/toolchain/codegen/codegen.cpp @@ -13,15 +13,16 @@ #include "llvm/MC/TargetRegistry.h" #include "llvm/Target/TargetOptions.h" #include "llvm/TargetParser/Host.h" +#include "toolchain/diagnostics/diagnostic_consumer.h" namespace Carbon { auto CodeGen::Make(llvm::Module* module, llvm::StringRef target_triple_str, - llvm::raw_pwrite_stream* errors) -> std::optional { + Diagnostics::Consumer* consumer) -> std::optional { std::string error; const llvm::Target* target = llvm::TargetRegistry::lookupTarget(target_triple_str, error); - CARBON_CHECK(target, "Target should be validated before codegen"); + CARBON_CHECK(target, "Target should be validated before codegen: {0}", error); llvm::Triple target_triple(target_triple_str); module->setTargetTriple(target_triple); @@ -30,7 +31,8 @@ auto CodeGen::Make(llvm::Module* module, llvm::StringRef target_triple_str, constexpr llvm::StringLiteral Features = ""; llvm::TargetOptions target_opts; - CodeGen codegen(module, errors); + CodeGen codegen(module, + consumer ? consumer : &Diagnostics::ConsoleConsumer()); codegen.target_machine_.reset(target->createTargetMachine( target_triple, CPU, Features, target_opts, llvm::Reloc::PIC_)); return codegen; @@ -54,7 +56,9 @@ auto CodeGen::EmitCode(llvm::raw_pwrite_stream& out, llvm::legacy::PassManager pass; // Note that this returns true on an error. if (target_machine_->addPassesToEmitFile(pass, out, nullptr, file_type)) { - *errors_ << "error: unable to emit to this file\n"; + CARBON_DIAGNOSTIC(CodeGenUnableToEmit, Error, + "unable to emit to this file"); + emitter_.Emit(module_->getName(), CodeGenUnableToEmit); return false; } diff --git a/toolchain/codegen/codegen.h b/toolchain/codegen/codegen.h index 8388cb926eaa..c67c2b145f51 100644 --- a/toolchain/codegen/codegen.h +++ b/toolchain/codegen/codegen.h @@ -7,35 +7,37 @@ #include "llvm/IR/Module.h" #include "llvm/Target/TargetMachine.h" +#include "toolchain/diagnostics/diagnostic_consumer.h" +#include "toolchain/diagnostics/file_diagnostics.h" namespace Carbon { class CodeGen { public: - // `module` and `errors` must not be null. + // `module` and `errors` must not be null. `consumer` may be null, in which + // case diagnostics go to stderr. static auto Make(llvm::Module* module, llvm::StringRef target_triple_str, - llvm::raw_pwrite_stream* errors) -> std::optional; + Diagnostics::Consumer* consumer = nullptr) + -> std::optional; // Generates the object code file. // Returns false in case of failure, and any information about the failure is // printed to the error stream. // - // Note that unlike the error stream, this requires a `pwrite` stream to allow - // patching the output. + // Note this requires a `pwrite` stream to allow patching the output. auto EmitObject(llvm::raw_pwrite_stream& out) -> bool; // Prints the assembly to stdout. // Returns false in case of failure, and any information about the failure is // printed to the error stream. // - // Note that unlike the error stream, this requires a `pwrite` stream to allow - // patching the output. + // Note this requires a `pwrite` stream to allow patching the output. auto EmitAssembly(llvm::raw_pwrite_stream& out) -> bool; private: - // `module` and `errors` must not be null. - explicit CodeGen(llvm::Module* module, llvm::raw_pwrite_stream* errors) - : module_(module), errors_(errors) {} + // `module` and `consumer` must not be null. + explicit CodeGen(llvm::Module* module, Diagnostics::Consumer* consumer) + : module_(module), emitter_(consumer) {} // Using the llvm pass emits either assembly or object code to dest. // Returns false in case of failure, and any information about the failure is @@ -44,7 +46,10 @@ class CodeGen { -> bool; llvm::Module* module_; - llvm::raw_pwrite_stream* errors_; + + // The emitter for diagnostics. + Diagnostics::FileEmitter emitter_; + std::unique_ptr target_machine_; }; diff --git a/toolchain/diagnostics/coverage_test.cpp b/toolchain/diagnostics/coverage_test.cpp index d807c1eb4ea5..ba518929b856 100644 --- a/toolchain/diagnostics/coverage_test.cpp +++ b/toolchain/diagnostics/coverage_test.cpp @@ -43,6 +43,9 @@ constexpr Kind UntestedKinds[] = { // This is a little long but is tested in lex/numeric_literal_test.cpp. Kind::TooManyDigits, + // Producing an emit failure may be infeasible. + Kind::CodeGenUnableToEmit, + // 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_kind.def b/toolchain/diagnostics/diagnostic_kind.def index d518cc5c1d51..d41ec131a4a9 100644 --- a/toolchain/diagnostics/diagnostic_kind.def +++ b/toolchain/diagnostics/diagnostic_kind.def @@ -499,6 +499,12 @@ CARBON_DIAGNOSTIC_KIND(GenericMissingExplicitParameters) // Pattern matching diagnostics. CARBON_DIAGNOSTIC_KIND(TuplePatternSizeDoesntMatchLiteral) +// ============================================================================ +// CodeGen diagnostics +// ============================================================================ + +CARBON_DIAGNOSTIC_KIND(CodeGenUnableToEmit) + // ============================================================================ // Language server diagnostics // ============================================================================ diff --git a/toolchain/driver/compile_subcommand.cpp b/toolchain/driver/compile_subcommand.cpp index ee28f7810963..8fb3e0144a69 100644 --- a/toolchain/driver/compile_subcommand.cpp +++ b/toolchain/driver/compile_subcommand.cpp @@ -741,8 +741,7 @@ auto CompilationUnit::PostCompile() -> void { auto CompilationUnit::RunCodeGenHelper() -> bool { std::optional codegen = - CodeGen::Make(module_.get(), options_->codegen_options.target, - driver_env_->error_stream); + CodeGen::Make(module_.get(), options_->codegen_options.target, consumer_); if (!codegen) { return false; }