Pārlūkot izejas kodu

Change CodeGen to use a diagnostic consumer (#5847)

We've been trying to have errors/warnings all go through the diagnostics
consumers instead of straight to stderr.
Jon Ross-Perkins 9 mēneši atpakaļ
vecāks
revīzija
d599023c19

+ 2 - 0
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",

+ 8 - 4
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<CodeGen> {
+                   Diagnostics::Consumer* consumer) -> std::optional<CodeGen> {
   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;
   }
 

+ 15 - 10
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<CodeGen>;
+                   Diagnostics::Consumer* consumer = nullptr)
+      -> std::optional<CodeGen>;
 
   // 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<llvm::TargetMachine> target_machine_;
 };
 

+ 3 - 0
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:

+ 6 - 0
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
 // ============================================================================

+ 1 - 2
toolchain/driver/compile_subcommand.cpp

@@ -741,8 +741,7 @@ auto CompilationUnit::PostCompile() -> void {
 
 auto CompilationUnit::RunCodeGenHelper() -> bool {
   std::optional<CodeGen> 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;
   }