Jelajahi Sumber

Error when passing multiple input files with --output (#6896)

Fixes #6895

Note this is just a short-term fix to avoid confusion, as the compile
structure needs to change on the whole.

Assisted-by: Google Antigravity with Gemini
Jon Ross-Perkins 1 bulan lalu
induk
melakukan
6706162582

+ 1 - 1
bazel/carbon_rules/defs.bzl

@@ -89,7 +89,7 @@ def _carbon_binary_impl(ctx):
                 inputs = depset(direct = srcs_reordered, transitive = dep_hdrs),
                 executable = toolchain_driver,
                 tools = depset(toolchain_data),
-                arguments = ["compile", "--output=" + out.path] +
+                arguments = ["compile", "--output=" + out.path, "--output-last-input-only"] +
                             [s.path for s in srcs_reordered] + extra_flags + ctx.attr.flags,
                 mnemonic = "CarbonCompile",
                 progress_message = "Compiling " + src.short_path,

+ 1 - 1
toolchain/codegen/testdata/objcode/basic.carbon

@@ -3,7 +3,7 @@
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 //
 // INCLUDE-FILE: toolchain/testing/testdata/min_prelude/none.carbon
-// EXTRA-ARGS: --target=x86_64-unknown-linux-gnu --output=%t
+// EXTRA-ARGS: --output-last-input-only --target=x86_64-unknown-linux-gnu --output=%t
 //
 // TODO: Add a way to write some basic tests for object file outputs.
 // AUTOUPDATE

+ 1 - 0
toolchain/diagnostics/kind.def

@@ -28,6 +28,7 @@ CARBON_DIAGNOSTIC_KIND(DriverCommandLineParseFailed)
 CARBON_DIAGNOSTIC_KIND(CompilePhaseFlagConflict)
 CARBON_DIAGNOSTIC_KIND(CompilePreludeManifestError)
 CARBON_DIAGNOSTIC_KIND(CompileInputNotRegularFile)
+CARBON_DIAGNOSTIC_KIND(CompileMultipleInputsWithOutput)
 CARBON_DIAGNOSTIC_KIND(CompileOutputFileOpenError)
 CARBON_DIAGNOSTIC_KIND(CompileTargetInvalid)
 CARBON_DIAGNOSTIC_KIND(ConfigFailedToReadDigest)

+ 1 - 0
toolchain/driver/BUILD

@@ -215,6 +215,7 @@ cc_library(
         "//toolchain/check",
         "//toolchain/codegen",
         "//toolchain/diagnostics:emitter",
+        "//toolchain/diagnostics:format_providers",
         "//toolchain/diagnostics:sorting_consumer",
         "//toolchain/format",
         "//toolchain/language_server",

+ 33 - 8
toolchain/driver/compile_subcommand.cpp

@@ -24,6 +24,7 @@
 #include "toolchain/check/check.h"
 #include "toolchain/codegen/codegen.h"
 #include "toolchain/diagnostics/emitter.h"
+#include "toolchain/diagnostics/format_providers.h"
 #include "toolchain/diagnostics/sorting_consumer.h"
 #include "toolchain/lex/lex.h"
 #include "toolchain/lower/lower.h"
@@ -358,6 +359,17 @@ Whether to emit DWARF debug information.
         arg_b.Default(true);
         arg_b.Set(&include_debug_info);
       });
+  b.AddFlag(
+      {
+          .name = "output-last-input-only",
+          .help = R"""(
+Only write output for the last input file, ignoring all others.
+
+TODO: This is a temporary workaround and should be removed once separate
+compilation is better implemented.
+)""",
+      },
+      [&](auto& arg_b) { arg_b.Set(&output_last_input_only); });
   b.AddFlag(
       {
           .name = "verify-llvm-ir",
@@ -1028,11 +1040,8 @@ auto CompilationUnit::RunCodeGenHelper() -> bool {
       llvm::sys::path::replace_extension(output_filename,
                                          options_->asm_output ? ".s" : ".o");
     } else {
-      // TODO: Handle the case where multiple input files were specified
-      // along with an output file name. That should either be an error or
-      // should produce a single LLVM IR module containing all inputs.
-      // Currently each unit overwrites the output from the previous one in
-      // this case.
+      CARBON_CHECK(total_ir_count_ == 1 || options_->output_last_input_only,
+                   "Handled by CompileMultipleInputsWithOutput diagnostic");
     }
     CARBON_VLOG("Writing output to: {0}\n", output_filename);
 
@@ -1156,9 +1165,21 @@ auto CompileSubcommand::Run(DriverEnv& driver_env) -> DriverResult {
     }
   }
 
+  int total_unit_count = prelude.size() + options_.input_filenames.size();
+  if (!options_.output_last_input_only && total_unit_count > 1 &&
+      !options_.output_filename.empty() && options_.output_filename != "-") {
+    CARBON_DIAGNOSTIC(
+        CompileMultipleInputsWithOutput, Error,
+        "writing {0} input file{0:s} to the same `--output` file would "
+        "overwrite the output file; for now, pass `--output-last-input-only` "
+        "if intended",
+        Diagnostics::IntAsSelect);
+    driver_env.emitter.Emit(CompileMultipleInputsWithOutput, total_unit_count);
+    return {.success = false};
+  }
+
   // Prepare CompilationUnits before building scope exit handlers.
   llvm::SmallVector<std::unique_ptr<CompilationUnit>> units;
-  int total_unit_count = prelude.size() + options_.input_filenames.size();
   int unit_index = -1;
   auto unit_builder = [&](llvm::StringRef filename) {
     ++unit_index;
@@ -1310,8 +1331,12 @@ auto CompileSubcommand::Run(DriverEnv& driver_env) -> DriverResult {
                "CodeGen should be the last stage");
 
   // Codegen.
-  for (auto& unit : units) {
-    unit->RunCodeGen();
+  if (options_.output_last_input_only) {
+    units.back()->RunCodeGen();
+  } else {
+    for (const auto& unit : units) {
+      unit->RunCodeGen();
+    }
   }
   return make_result();
 }

+ 1 - 0
toolchain/driver/compile_subcommand.h

@@ -65,6 +65,7 @@ struct CompileOptions {
   bool builtin_sem_ir = false;
   bool prelude_import = false;
   bool include_debug_info = true;
+  bool output_last_input_only = false;
   bool run_llvm_verifier = true;
 
   llvm::SmallVector<llvm::StringRef> exclude_dump_file_prefixes;

+ 16 - 0
toolchain/driver/testdata/fail_multi_input_with_output.carbon

@@ -0,0 +1,16 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+// Exclude the prelude import so that the number of prelude files isn't tested.
+// ARGS: --include-diagnostic-kind compile --output=foo.o --no-prelude-import foo.carbon bar.carbon
+//
+// SET-CAPTURE-CONSOLE-OUTPUT
+// clang-format off
+// AUTOUPDATE
+// TIP: To test this file alone, run:
+// TIP:   bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/driver/testdata/fail_multi_input_with_output.carbon
+// TIP: To dump output, run:
+// TIP:   bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/driver/testdata/fail_multi_input_with_output.carbon
+// CHECK:STDERR: error: writing 2 input files to the same `--output` file would overwrite the output file; for now, pass `--output-last-input-only` if intended [CompileMultipleInputsWithOutput]
+// CHECK:STDERR:

+ 1 - 1
toolchain/driver/testdata/verbose.carbon

@@ -3,7 +3,7 @@
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 //
 // INCLUDE-FILE: toolchain/testing/testdata/min_prelude/none.carbon
-// ARGS: -v compile --phase=codegen --target=x86_64-unknown-linux-gnu --output=%t %s
+// ARGS: -v compile --phase=codegen --target=x86_64-unknown-linux-gnu --output=%t --output-last-input-only %s
 //
 // Verifies that various phases are included in vlog output.
 //